255 lines
8.2 KiB
Rust
255 lines
8.2 KiB
Rust
use gloo::{console::log, utils::format::JsValueSerdeExt};
|
|
use std::{
|
|
error::Error,
|
|
fmt::{self, Debug, Display, Formatter},
|
|
};
|
|
use wasm_bindgen::{JsCast, JsValue};
|
|
|
|
use common::{CommonAdmin, CommonDriver};
|
|
use wasm_bindgen_futures::JsFuture;
|
|
use web_sys::{Request, RequestInit, RequestMode, Response};
|
|
use yew::{html, Component, Context, Html};
|
|
//Trait to handle Future yew HTMLS
|
|
pub trait UseAble {
|
|
//Return HTML if didn't fail return error if not
|
|
fn use_it(self) -> Result<Html, String>;
|
|
}
|
|
impl UseAble for CommonDriver {
|
|
fn use_it(self) -> Result<Html, String> {
|
|
let name = self.name;
|
|
let email = self.address;
|
|
let id = self.id;
|
|
let html = html! {
|
|
<div>
|
|
<h2> { "Driver:" } </h2>
|
|
<p> { format!("Name: {}", name) } </p>
|
|
<p> { format!("Email: {}", email) } </p>
|
|
<p> { format!("ID: {}", id) } </p>
|
|
</div>
|
|
};
|
|
Ok(html)
|
|
}
|
|
}
|
|
impl UseAble for CommonAdmin {
|
|
fn use_it(self) -> Result<Html, String> {
|
|
let name = self.name;
|
|
let email = self.address;
|
|
let id = self.id;
|
|
let html = html! {
|
|
<div>
|
|
<h2> { "Admin:" } </h2>
|
|
<p> { format!("Name: {}", name) } </p>
|
|
<p> { format!("Email: {}", email) } </p>
|
|
<p> { format!("ID: {}", id) } </p>
|
|
</div>
|
|
};
|
|
Ok(html)
|
|
}
|
|
}
|
|
|
|
//Wwasm bingdengen code
|
|
const DRIVER_URL: &str = "http://db.sewelam.tech/api/driver/1234";
|
|
const FUNNY_TXT_URL: &str = "https://whatthecommit.com/index.txt";
|
|
const INCORRECT_URL: &str = "http://libkyy.cf";
|
|
//Generic Msg for our states
|
|
enum Msg<T> {
|
|
SetDataFetchState(FetchState<T>),
|
|
GetData,
|
|
GetError,
|
|
}
|
|
struct RandomCommit {
|
|
commit: FetchState<String>,
|
|
}
|
|
//This trait is for all yew components
|
|
impl Component for RandomCommit {
|
|
type Message = Msg<String>;
|
|
type Properties = ();
|
|
fn create(_ctx: &Context<Self>) -> Self {
|
|
Self {
|
|
commit: FetchState::NotFetching, //Default state is not fetching anything
|
|
}
|
|
}
|
|
|
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
|
match msg {
|
|
Msg::SetDataFetchState(fetch_state) => {
|
|
self.commit = fetch_state;
|
|
true
|
|
}
|
|
Msg::GetData => {
|
|
ctx.link().send_future(async {
|
|
match fetch_commit(FUNNY_TXT_URL).await {
|
|
Ok(commit) => Msg::SetDataFetchState(FetchState::Success(commit)),
|
|
Err(err) => Msg::SetDataFetchState(FetchState::Failed(err)),
|
|
}
|
|
});
|
|
ctx.link()
|
|
.send_message(Msg::SetDataFetchState(FetchState::Fetching));
|
|
false
|
|
}
|
|
Msg::GetError => {
|
|
ctx.link().send_future(async {
|
|
match fetch_commit(INCORRECT_URL).await {
|
|
Ok(commit) => Msg::SetDataFetchState(FetchState::Success(commit)),
|
|
Err(err) => Msg::SetDataFetchState(FetchState::Failed(err)),
|
|
}
|
|
});
|
|
ctx.link()
|
|
.send_message(Msg::SetDataFetchState(FetchState::Fetching));
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
match &self.commit {
|
|
FetchState::NotFetching => html! {
|
|
<>
|
|
<button onclick={ctx.link().callback(|_| Msg::GetData)}>
|
|
{ "Get commit msg" }
|
|
</button>
|
|
<button onclick={ctx.link().callback(|_| Msg::GetError)}>
|
|
{ "Get using incorrect URL" }
|
|
</button>
|
|
</>
|
|
},
|
|
FetchState::Fetching => html! { "Fetching" },
|
|
FetchState::Success(data) => {
|
|
html! { <> <h2> {"Commit Header:"} </h2> {data}</> }
|
|
}
|
|
FetchState::Failed(err) => html! { err },
|
|
}
|
|
}
|
|
}
|
|
//Generate Struct and implement component for driver using CommonDriver
|
|
struct Driver {
|
|
driver: FetchState<String>,
|
|
}
|
|
//implement the component for Driver using a string
|
|
impl Component for Driver {
|
|
type Message = Msg<String>;
|
|
type Properties = ();
|
|
fn create(_ctx: &Context<Self>) -> Self {
|
|
Self {
|
|
driver: FetchState::NotFetching,
|
|
}
|
|
}
|
|
|
|
fn update(&mut self, ctx: &Context<Self>, msg: Self::Message) -> bool {
|
|
match msg {
|
|
Msg::SetDataFetchState(fetch_state) => {
|
|
self.driver = fetch_state;
|
|
true
|
|
}
|
|
Msg::GetData => {
|
|
ctx.link().send_future(async {
|
|
match fetch_driver(DRIVER_URL).await {
|
|
Ok(driver) => Msg::SetDataFetchState(FetchState::Success(driver)),
|
|
Err(err) => Msg::SetDataFetchState(FetchState::Failed(err)),
|
|
}
|
|
});
|
|
ctx.link()
|
|
.send_message(Msg::SetDataFetchState(FetchState::Fetching));
|
|
false
|
|
}
|
|
Msg::GetError => {
|
|
ctx.link().send_future(async {
|
|
match fetch_driver(INCORRECT_URL).await {
|
|
Ok(driver) => Msg::SetDataFetchState(FetchState::Success(driver)),
|
|
Err(err) => Msg::SetDataFetchState(FetchState::Failed(err)),
|
|
}
|
|
});
|
|
ctx.link()
|
|
.send_message(Msg::SetDataFetchState(FetchState::Fetching));
|
|
false
|
|
}
|
|
}
|
|
}
|
|
|
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
|
match &self.driver {
|
|
FetchState::NotFetching => html! {
|
|
<>
|
|
<button onclick={ctx.link().callback(|_| Msg::GetData)}>
|
|
{ "Get driver" }
|
|
</button>
|
|
<button onclick={ctx.link().callback(|_| Msg::GetError)}>
|
|
{ "Get using incorrect URL" }
|
|
</button>
|
|
</>
|
|
},
|
|
FetchState::Fetching => html! { "Fetching" },
|
|
FetchState::Success(data) => html! { <> <h2> {"Driver"} </h2> {data} </> },
|
|
FetchState::Failed(err) => html! { err },
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq)]
|
|
pub struct FetchError {
|
|
err: JsValue,
|
|
}
|
|
|
|
impl Display for FetchError {
|
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
|
Debug::fmt(&self.err, f)
|
|
}
|
|
}
|
|
|
|
impl Error for FetchError {}
|
|
|
|
impl From<JsValue> for FetchError {
|
|
fn from(value: JsValue) -> Self {
|
|
Self { err: value }
|
|
}
|
|
}
|
|
//Enum for Fetchstates that takes a generic type --> String/Driver etc.
|
|
pub enum FetchState<T> {
|
|
NotFetching,
|
|
Fetching,
|
|
Success(T),
|
|
Failed(FetchError),
|
|
}
|
|
|
|
//Working example function
|
|
async fn fetch_commit(url: &'static str) -> Result<String, FetchError> {
|
|
//initialise request
|
|
let mut opts = RequestInit::new();
|
|
opts.method("GET");
|
|
opts.mode(RequestMode::Cors); //Cors is required for fetch to work
|
|
|
|
let request = Request::new_with_str_and_init(url, &opts)?;
|
|
|
|
let window = gloo::utils::window();
|
|
//get response value
|
|
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
|
let resp: Response = resp_value.dyn_into().unwrap();
|
|
|
|
//parse response value as text
|
|
let text = JsFuture::from(resp.text()?).await?;
|
|
Ok(text.as_string().unwrap())
|
|
}
|
|
|
|
async fn fetch_driver(url: &'static str) -> Result<String, FetchError> {
|
|
let mut opts = RequestInit::new();
|
|
opts.method("GET");
|
|
opts.mode(RequestMode::Cors); //Cors is required for fetch to work
|
|
|
|
//initialise request
|
|
let request = Request::new_with_str_and_init(url, &opts)?;
|
|
let window = gloo::utils::window();
|
|
let resp_value = JsFuture::from(window.fetch_with_request(&request)).await?;
|
|
let resp: Response = resp_value.dyn_into().unwrap();
|
|
let text = JsFuture::from(resp.text()?).await?;
|
|
Ok(text.as_string().unwrap())
|
|
}
|
|
|
|
//renders components above
|
|
pub fn render_commit() {
|
|
yew::Renderer::<RandomCommit>::new().render();
|
|
}
|
|
|
|
pub fn render_driver() {
|
|
yew::Renderer::<Driver>::new().render();
|
|
}
|