diff options
author | Kjetil Orbekk <kj@orbekk.com> | 2022-11-13 16:07:27 -0500 |
---|---|---|
committer | Kjetil Orbekk <kj@orbekk.com> | 2022-11-13 16:07:27 -0500 |
commit | d4650a3160d52d289686fb59efbf8f0a436b71eb (patch) | |
tree | 0b38d0143824a3a7cab83e189fe1a2302f9685a7 /webapp/src/components | |
parent | 0012c25c9ab94754f3d6396e91dc3ae63d19ac9c (diff) |
Add create/leave table options
Diffstat (limited to 'webapp/src/components')
-rw-r--r-- | webapp/src/components/app_context_provider.rs | 141 | ||||
-rw-r--r-- | webapp/src/components/error_info.rs | 4 | ||||
-rw-r--r-- | webapp/src/components/table.rs | 21 |
3 files changed, 129 insertions, 37 deletions
diff --git a/webapp/src/components/app_context_provider.rs b/webapp/src/components/app_context_provider.rs index 4cf233b..19e7611 100644 --- a/webapp/src/components/app_context_provider.rs +++ b/webapp/src/components/app_context_provider.rs @@ -1,17 +1,89 @@ +use crate::routing::Route; use gloo_net::http::Request; +use log::info; use protocol::UserInfo; -use std::rc::Rc; +use uuid::Uuid; +use std::{future::Future, rc::Rc}; +use wasm_bindgen_futures::spawn_local; use yew::prelude::*; +use yew_router::prelude::*; #[derive(Properties, Clone, PartialEq, Debug)] pub struct ErrorInfoProperties { pub message: String, } -#[derive(Clone, Debug, PartialEq, Default)] +#[derive(Clone, PartialEq)] +pub struct AppState { + user: UseStateHandle<Option<UserInfo>>, + error: UseStateHandle<Option<ErrorInfoProperties>>, +} + +#[derive(Clone, PartialEq)] pub struct AppContext { - pub error: Option<ErrorInfoProperties>, - pub user: Option<UserInfo>, + state: AppState, + history: AnyHistory, +} + +impl AppContext { + fn spawn_async<F>(&self, f: F) + where + F: Future<Output = Result<(), anyhow::Error>> + 'static, + { + let error = self.state.error.clone(); + spawn_local(async move { + if let Err(err) = f.await { + error.set(Some(ErrorInfoProperties { + message: format!("Some error occured: {:?}", err), + })); + } + }); + } + + pub fn user(&self) -> Option<&UserInfo> { + self.state.user.as_ref() + } + + pub fn error(&self) -> Option<&ErrorInfoProperties> { + self.state.error.as_ref() + } + + pub fn create_table(&self) { + let user = self.state.user.clone(); + let history = self.history.clone(); + self.spawn_async(async move { + let response = Request::post("/api/table").send().await?; + let table_id: Uuid = response.json().await?; + info!("Created table {table_id}"); + if let Some(user_info) = user.as_ref() { + user.set(Some(UserInfo { + table: Some(protocol::Table { id: table_id }), + ..(user_info.clone()) + })); + } + history.push(Route::Home); + Ok(()) + }); + } + + pub fn leave_table(&self) { + let user = self.state.user.clone(); + let history = self.history.clone(); + self.spawn_async(async move { + let response = Request::delete("/api/table").send().await?; + if !response.ok() { + anyhow::bail!("error while leaving table"); + } + if let Some(user_info) = user.as_ref() { + user.set(Some(UserInfo { + table: None, + ..(user_info.clone()) + })); + } + history.push(Route::Home); + Ok(()) + }); + } } #[derive(Properties, Clone, PartialEq)] @@ -32,30 +104,30 @@ async fn initialize_user_info() -> Result<UserInfo, anyhow::Error> { Ok(user_info) } +pub fn use_app_context() -> AppContext { + let state : AppState = use_context::<AppState>().unwrap(); + let history = use_history().unwrap(); + + AppContext { state: state, history } +} + #[function_component(AppContextProvider)] pub fn app_context_provider(props: &Props) -> Html { - let context: UseStateHandle<Option<Rc<AppContext>>> = use_state(|| None); + let user: UseStateHandle<Option<UserInfo>> = use_state(|| None); + let error: UseStateHandle<Option<ErrorInfoProperties>> = use_state(|| None); { - let context = context.clone(); + let user = user.clone(); + let error = error.clone(); use_effect_with_deps( move |_| { - wasm_bindgen_futures::spawn_local(async move { - let previous_context: AppContext = context - .as_ref() - .map_or(Default::default(), |c| (**c).clone()); - context.set(Some(Rc::new(match initialize_user_info().await { - Ok(user_info) => AppContext { - user: Some(user_info), - ..previous_context - }, - Err(e) => AppContext { - error: Some(ErrorInfoProperties { - message: format!("Could not contact server"), - }), - ..previous_context - }, - }))); + spawn_local(async move { + match initialize_user_info().await { + Ok(user_info) => user.set(Some(user_info)), + Err(e) => error.set(Some(ErrorInfoProperties { + message: format!("Could not contact server"), + })), + }; }); || () }, @@ -63,14 +135,23 @@ pub fn app_context_provider(props: &Props) -> Html { ); } - match &*context { - None => html! { - <p>{ "Loading app..." }</p> - }, - Some(context) => html! { - <ContextProvider<Rc<AppContext>> {context}> + if user.is_none() && error.is_none() { + return html! { + <p>{ "Loading app..." }</p> + }; + } + + info!("Recomputing state"); + info!("User is {:?}", *user); + + let state = AppState { + user, + error, + }; + + html! { + <ContextProvider<AppState> context={state}> { for props.children.iter() } - </ContextProvider<Rc<AppContext>>> - }, + </ContextProvider<AppState>> } } diff --git a/webapp/src/components/error_info.rs b/webapp/src/components/error_info.rs index 4ec5ba9..cb5a9c1 100644 --- a/webapp/src/components/error_info.rs +++ b/webapp/src/components/error_info.rs @@ -9,9 +9,9 @@ pub fn error_info(props: &ErrorInfoProperties) -> Html { html! { <div class="error-box"> <p> - { format!("Error: {}. ", props.message) } + { format!("Error: {}. ", props.message) } <button onclick={reload}>{ "Reload" }</button> - </p> + </p> </div> } } diff --git a/webapp/src/components/table.rs b/webapp/src/components/table.rs index 8e8b5c8..829441e 100644 --- a/webapp/src/components/table.rs +++ b/webapp/src/components/table.rs @@ -1,15 +1,26 @@ use yew::prelude::*; +use yew_router::prelude::*; + +use crate::use_app_context; #[function_component(Table)] pub fn table(props: &TableProps) -> Html { - // let leave_table = { - // Callback::from(move |_| { - // }); - // }; + let ctx = use_app_context(); + let history = use_history().unwrap(); + + let leave_table = { + let ctx = ctx.clone(); + Callback::from(move |_| { + ctx.leave_table(); + }) + }; html! { <> - <p>{ format!("This is table {}", props.table.id) }</p> + <p>{ format!("This is table {}", props.table.id) }</p> + <button onclick={leave_table}> + { "Leave table" } + </button> </> } } |