re-write create_milestone as functional component
This commit is contained in:
parent
d39596da77
commit
7793f6a5dc
@ -1,127 +1,113 @@
|
|||||||
use super::error::error_provider::get_error_context;
|
use crate::components::error::error_provider::ErrorContext;
|
||||||
use crate::services::rest::RestService;
|
use crate::services::rest::RestService;
|
||||||
use crate::services::rest::RestServiceError;
|
|
||||||
use common::CreateMilestone;
|
use common::CreateMilestone;
|
||||||
|
use std::rc::Rc;
|
||||||
use wasm_bindgen::JsCast;
|
use wasm_bindgen::JsCast;
|
||||||
use wasm_bindgen_futures::spawn_local;
|
use wasm_bindgen_futures::spawn_local;
|
||||||
use web_sys::HtmlInputElement;
|
use web_sys::HtmlInputElement;
|
||||||
use yew::html;
|
use yew::html;
|
||||||
|
use yew::prelude::*;
|
||||||
use yew::Callback;
|
use yew::Callback;
|
||||||
use yew::Component;
|
|
||||||
use yew::Html;
|
use yew::Html;
|
||||||
use yew::NodeRef;
|
use yew_router::prelude::use_navigator;
|
||||||
use yew_router::scope_ext::RouterScopeExt;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Properties, PartialEq)]
|
||||||
pub enum Msg {
|
pub struct Props;
|
||||||
Submit,
|
|
||||||
SubmitResult(Result<(), RestServiceError>),
|
|
||||||
UpdateInput(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default)]
|
#[function_component]
|
||||||
pub struct CreateMilestoneComponent {
|
pub fn CreateMilestoneComponent(_: &Props) -> Html {
|
||||||
input_value: String,
|
let nav = use_navigator().expect("cannot get navigator");
|
||||||
input_ref: NodeRef,
|
let err_ctx = Rc::new(use_context::<ErrorContext>());
|
||||||
|
|
||||||
/// Submitted and awaiting response
|
let input_ref = use_node_ref();
|
||||||
awaiting_response: bool,
|
// Focus input after it is rendered
|
||||||
}
|
{
|
||||||
impl Component for CreateMilestoneComponent {
|
let input_ref = input_ref.clone();
|
||||||
type Message = Msg;
|
use_effect(move || {
|
||||||
type Properties = ();
|
if let Some(input_element) = input_ref.get() {
|
||||||
|
|
||||||
fn create(_ctx: &yew::Context<Self>) -> Self {
|
|
||||||
Self::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rendered(&mut self, _ctx: &yew::Context<Self>, first_render: bool) {
|
|
||||||
if first_render {
|
|
||||||
if let Some(input_element) = self.input_ref.get() {
|
|
||||||
let input_element = input_element
|
let input_element = input_element
|
||||||
.dyn_into::<HtmlInputElement>()
|
.dyn_into::<HtmlInputElement>()
|
||||||
.expect("Failed to cast input element");
|
.expect("Failed to cast input element");
|
||||||
input_element.focus().expect("Failed to focus input");
|
input_element.focus().expect("Failed to focus input");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// effect destructor
|
||||||
|
|| {}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(&mut self, ctx: &yew::Context<Self>, msg: Self::Message) -> bool {
|
let input_value = use_state(String::default);
|
||||||
match msg {
|
let awaiting_response = use_state(|| false);
|
||||||
Msg::Submit => {
|
|
||||||
log::info!("Creating milestone");
|
|
||||||
let Ok(goal) = self.input_value.parse::<f64>() else { return false; };
|
|
||||||
|
|
||||||
let goal = goal as usize;
|
let onclick_go_back = {
|
||||||
let payload = CreateMilestone { goal };
|
let nav = nav.clone();
|
||||||
let link = ctx.link().clone();
|
Callback::from(move |_: web_sys::MouseEvent| {
|
||||||
spawn_local(async move {
|
|
||||||
let res = RestService::create_milestone(payload).await;
|
|
||||||
link.send_message(Msg::SubmitResult(res));
|
|
||||||
});
|
|
||||||
self.awaiting_response = true;
|
|
||||||
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Msg::SubmitResult(result) => {
|
|
||||||
match result {
|
|
||||||
Ok(_response) => {
|
|
||||||
let nav = ctx.link().navigator().unwrap();
|
|
||||||
nav.push(&crate::Route::Admin)
|
|
||||||
}
|
|
||||||
Err(err) => {
|
|
||||||
if let Some(err_ctx) = get_error_context(ctx) {
|
|
||||||
err_ctx.dispatch(err.to_string());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
self.awaiting_response = false;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
Msg::UpdateInput(value) => {
|
|
||||||
self.input_value = value;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn view(&self, ctx: &yew::Context<Self>) -> Html {
|
|
||||||
let link = ctx.link().clone();
|
|
||||||
let nav = ctx.link().navigator().unwrap();
|
|
||||||
|
|
||||||
let onclick_go_back = Callback::from(move |_: web_sys::MouseEvent| {
|
|
||||||
nav.push(&crate::Route::Admin);
|
nav.push(&crate::Route::Admin);
|
||||||
});
|
})
|
||||||
|
};
|
||||||
|
|
||||||
let onsubmit = link.callback(|e: web_sys::SubmitEvent| {
|
let onsubmit = {
|
||||||
|
let input_value = input_value.clone();
|
||||||
|
let awaiting_response = awaiting_response.clone();
|
||||||
|
|
||||||
|
Callback::from(move |e: yew::SubmitEvent| {
|
||||||
e.prevent_default();
|
e.prevent_default();
|
||||||
Msg::Submit
|
|
||||||
});
|
|
||||||
|
|
||||||
let oninput = link.callback(|e: web_sys::InputEvent| {
|
log::info!("Creating milestone");
|
||||||
|
let Ok(goal) = input_value.parse::<f64>() else {
|
||||||
|
log::error!("Input parse error");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let goal = goal as usize;
|
||||||
|
let payload = CreateMilestone { goal };
|
||||||
|
{
|
||||||
|
let nav = nav.clone();
|
||||||
|
let err_ctx = Rc::clone(&err_ctx);
|
||||||
|
awaiting_response.set(true);
|
||||||
|
let awaiting_response = awaiting_response.clone();
|
||||||
|
spawn_local(async move {
|
||||||
|
match RestService::create_milestone(payload).await {
|
||||||
|
Ok(_response) => nav.push(&crate::Route::Admin),
|
||||||
|
Err(err) => {
|
||||||
|
if let Some(err_ctx) = &*err_ctx {
|
||||||
|
err_ctx.dispatch(err.to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
awaiting_response.set(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let oninput = {
|
||||||
|
let input_value = input_value.clone();
|
||||||
|
|
||||||
|
Callback::from(move |e: web_sys::InputEvent| {
|
||||||
let Some(input) = e
|
let Some(input) = e
|
||||||
.target()
|
.target()
|
||||||
.and_then(|t| t.dyn_into::<web_sys::HtmlInputElement>().ok()) else { unreachable!() };
|
.and_then(|t| t.dyn_into::<web_sys::HtmlInputElement>().ok()) else { unreachable!() };
|
||||||
Msg::UpdateInput(input.value())
|
input_value.set(input.value());
|
||||||
});
|
})
|
||||||
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<button onclick={onclick_go_back} class="button">{"Back"}</button>
|
<button onclick={onclick_go_back} class="button">{"Back"}</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<form {onsubmit} >
|
||||||
|
<hr />
|
||||||
|
<div class="row">
|
||||||
|
<div class="twelve columns">
|
||||||
|
<label for="milestoneInput">{"New milestone"}</label>
|
||||||
|
<input ref={input_ref.clone()} {oninput} value={input_value.to_string()} class="u-full-width" type="number" id="milestoneInput" />
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<form {onsubmit} >
|
<input class="button-primary" type="submit" value="Submit" disabled={*awaiting_response} />
|
||||||
<hr />
|
</form>
|
||||||
<div class="row">
|
</>
|
||||||
<div class="twelve columns">
|
|
||||||
<label for="milestoneInput">{"New milestone"}</label>
|
|
||||||
<input ref={self.input_ref.clone()} {oninput} value={self.input_value.to_string()} class="u-full-width" type="number" id="milestoneInput" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input class="button-primary" type="submit" value="Submit" disabled={self.awaiting_response} />
|
|
||||||
</form>
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user