diff --git a/web/dist/index.html b/web/dist/index.html index b581e63..824f509 100644 --- a/web/dist/index.html +++ b/web/dist/index.html @@ -4,9 +4,9 @@ Yew App - - + + - \ No newline at end of file + \ No newline at end of file diff --git a/web/src/components/mod.rs b/web/src/components/mod.rs index 1a66f87..f7fc7ee 100644 --- a/web/src/components/mod.rs +++ b/web/src/components/mod.rs @@ -11,10 +11,21 @@ use wasm_bindgen::{JsCast, UnwrapThrowExt}; use web_sys::{Event, HtmlInputElement, InputEvent}; use yew::prelude::*; +#[derive(Clone, PartialEq)] +pub struct Binding { + pub onchange: Callback, + pub value: T, +} + +impl Binding { + pub fn new(value: T, onchange: Callback) -> Self { + Self { value, onchange } + } +} + #[derive(Clone, PartialEq, Properties)] pub struct InputProps { - pub value: String, - pub onchange: Callback, + pub bind: Binding, pub class: Classes, } @@ -29,9 +40,8 @@ fn get_value_from_input_event(e: InputEvent) -> String { #[function_component(TextInput)] pub fn text_input(props: &InputProps) -> Html { let InputProps { - value, - onchange, class, + bind: Binding { onchange, value }, } = props.clone(); let oninput = Callback::from(move |input_event: InputEvent| { diff --git a/web/src/pages/events.rs b/web/src/pages/events.rs index 9373e02..00d6682 100644 --- a/web/src/pages/events.rs +++ b/web/src/pages/events.rs @@ -1,4 +1,8 @@ -use crate::components::{Page, RenderEvent}; +use crate::{ + components::{Page, RenderEvent}, + init, +}; +use wasm_bindgen_futures::spawn_local; use yew::prelude::*; use yew_hooks::*; @@ -6,25 +10,18 @@ use crate::{clone, util::api_request}; #[function_component(EventsPage)] pub fn events_page() -> Html { - let events: UseAsyncHandle, _> = use_async(async move { - api_request::<_, Vec>("GET", "/event", Option::<()>::None) + let events = use_state(|| Vec::new()); + + init!(events => { + events.set(api_request::<_, Vec>("GET", "/event", Option::<()>::None) .await .map(|inner| inner.unwrap()) - .map_err(|_| "failed to load users") + .unwrap()) }); - clone!(events; use_effect_with_deps(move |_| { - if events.data.is_none() { - events.run(); - } - || () - }, ())); - html! { - { if let Some(events) = &events.data { - events.view() - } else { html! {} }} + { events.view() } } } diff --git a/web/src/pages/users.rs b/web/src/pages/users.rs index 3595b61..6454796 100644 --- a/web/src/pages/users.rs +++ b/web/src/pages/users.rs @@ -1,11 +1,13 @@ use crate::{ - clone, clone_cb, - components::{Button, Loading, Page, Table, TextInput}, + bind, bind_change, bind_value, clone, clone_cb, clone_cb_spawn, + components::{Binding, Button, Loading, Page, Table, TextInput}, + init, util::api_request, }; use lan_party_core::user::User; use wasm_bindgen_futures::spawn_local; use yew::prelude::*; +use yew_hooks::*; #[function_component(UsersPage)] pub fn users_page() -> Html { @@ -16,59 +18,44 @@ pub fn users_page() -> Html { let current_score = use_state(|| String::new()); let users = use_state(|| Vec::new()); - clone!(users; use_effect_with_deps(move |_| { - spawn_local(async move { - users.set(api_request::<_, Vec>("GET", "/user", Option::<()>::None) - .await - .map(|inner| inner.unwrap()) - .unwrap()); - }); - || () - }, ())); - - let oncheck = clone_cb!(score_edit, current_score, users; move |_| { - clone!(score_edit, users, current_score; { - spawn_local(async move { - if let Some(score_edit) = *score_edit { - if let Ok(score) = current_score.parse() { - let user: &User = &users[score_edit]; - api_request::<_, ()>("POST", &format!("/user/{}/score", user.name), Some(score)).await.unwrap(); - let mut cloned = (*users).clone(); - cloned[score_edit].score = score; - users.set(cloned); - } - } - score_edit.set(None); - }); - }); + init!(users => { + users.set(api_request::<_, Vec>("GET", "/user", Option::<()>::None) + .await + .map(|inner| inner.unwrap()) + .unwrap()); }); - let onedit = clone_cb!(current_score, score_edit, users; i => move |_| { + let oncheck = clone_cb_spawn!(score_edit, current_score, users => { + if let (Some(score_edit), Ok(score)) = (*score_edit, current_score.parse()) { + let user: &User = &users[score_edit]; + api_request::<_, ()>("POST", &format!("/user/{}/score", user.name), Some(score)) + .await + .unwrap(); + let mut cloned = (*users).clone(); + cloned[score_edit].score = score; + users.set(cloned); + } + score_edit.set(None); + }); + + let onedit = clone_cb!(current_score, score_edit, users => i => move |_| { let user: &User = &users[i]; current_score.set(user.score.to_string()); score_edit.set(Some(i)); }); - let ondelete = clone_cb!(users; i => move |_| { - clone!(users; { - spawn_local(async move { - let user: &User = &users[i]; - api_request::<_, ()>("DELETE", &format!("/user/{}", user.name), Option::<()>::None).await.unwrap(); - let cloned = users.iter().cloned().filter(|u| u.name != user.name).collect(); - users.set(cloned); - }); - }); + let ondelete = clone_cb_spawn!(users => i => { + let user: &User = &users[i]; + api_request::<_, ()>("DELETE", &format!("/user/{}", user.name), Option::<()>::None).await.unwrap(); + let cloned = users.iter().cloned().filter(|u| u.name != user.name).collect(); + users.set(cloned); }); - let onadd = clone_cb!(new_username, users; move |_| { - clone!(new_username, users; { - spawn_local(async move { - let user = api_request::("POST", "/user", Some((*new_username).clone())).await.unwrap(); - let mut cloned = (*users).clone(); - cloned.push(user.unwrap()); - users.set(cloned); - }); - }); + let onadd = clone_cb_spawn!(new_username, users => { + let user = api_request::("POST", "/user", Some((*new_username).clone())).await.unwrap(); + let mut cloned = (*users).clone(); + cloned.push(user.unwrap()); + users.set(cloned); }); html! { @@ -83,8 +70,7 @@ pub fn users_page() -> Html {