diff --git a/web/src/app_state.rs b/web/src/app_state.rs index 88bbdca..81bbbd8 100644 --- a/web/src/app_state.rs +++ b/web/src/app_state.rs @@ -11,7 +11,10 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use std::collections::{BTreeMap, BTreeSet}; +use std::{ + collections::{BTreeMap, BTreeSet}, + fmt::Debug, +}; use client_api::UserData; use recipes::{parse, IngredientKey, Recipe, RecipeEntry}; @@ -50,7 +53,6 @@ impl AppState { } } -#[derive(Debug)] pub enum Message { ResetRecipeCounts, UpdateRecipeCount(String, usize), @@ -64,8 +66,46 @@ pub enum Message { AddFilteredIngredient(IngredientKey), UpdateAmt(IngredientKey, String), SetUserData(UserData), - SaveState, - LoadState, + SaveState(Option>), + LoadState(Option>), +} + +impl Debug for Message { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ResetRecipeCounts => write!(f, "ResetRecipeCounts"), + Self::UpdateRecipeCount(arg0, arg1) => f + .debug_tuple("UpdateRecipeCount") + .field(arg0) + .field(arg1) + .finish(), + Self::AddExtra(arg0, arg1) => { + f.debug_tuple("AddExtra").field(arg0).field(arg1).finish() + } + Self::RemoveExtra(arg0) => f.debug_tuple("RemoveExtra").field(arg0).finish(), + Self::UpdateExtra(arg0, arg1, arg2) => f + .debug_tuple("UpdateExtra") + .field(arg0) + .field(arg1) + .field(arg2) + .finish(), + Self::SaveRecipe(arg0) => f.debug_tuple("SaveRecipe").field(arg0).finish(), + Self::SetRecipe(arg0, arg1) => { + f.debug_tuple("SetRecipe").field(arg0).field(arg1).finish() + } + Self::SetCategoryMap(arg0) => f.debug_tuple("SetCategoryMap").field(arg0).finish(), + Self::ResetInventory => write!(f, "ResetInventory"), + Self::AddFilteredIngredient(arg0) => { + f.debug_tuple("AddFilteredIngredient").field(arg0).finish() + } + Self::UpdateAmt(arg0, arg1) => { + f.debug_tuple("UpdateAmt").field(arg0).field(arg1).finish() + } + Self::SetUserData(arg0) => f.debug_tuple("SetUserData").field(arg0).finish(), + Self::SaveState(_) => write!(f, "SaveState"), + Self::LoadState(_) => write!(f, "LoadState"), + } + } } pub struct StateMachine { @@ -284,16 +324,17 @@ impl MessageMapper for StateMachine { Message::SetUserData(user_data) => { original_copy.auth = Some(user_data); } - Message::SaveState => { + Message::SaveState(f) => { let original_copy = original_copy.clone(); let store = self.store.clone(); spawn_local_scoped(cx, async move { if let Err(e) = store.save_app_state(original_copy).await { error!(err=?e, "Error saving app state") }; + f.map(|f| f()); }); } - Message::LoadState => { + Message::LoadState(f) => { let store = self.store.clone(); let local_store = self.local_store.clone(); spawn_local_scoped(cx, async move { @@ -305,6 +346,7 @@ impl MessageMapper for StateMachine { &original.get().modified_amts, &original.get().extras, )); + f.map(|f| f()); }); return; } diff --git a/web/src/components/recipe_plan.rs b/web/src/components/recipe_plan.rs index 6c0c4ae..697c2ee 100644 --- a/web/src/components/recipe_plan.rs +++ b/web/src/components/recipe_plan.rs @@ -55,14 +55,14 @@ pub fn RecipePlan<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> Vie )) } input(type="button", value="Reset", on:click=move |_| { - sh.dispatch(cx, Message::LoadState); + sh.dispatch(cx, Message::LoadState(None)); }) input(type="button", value="Clear All", on:click=move |_| { sh.dispatch(cx, Message::ResetRecipeCounts); }) input(type="button", value="Save Plan", on:click=move |_| { // Poor man's click event signaling. - sh.dispatch(cx, Message::SaveState); + sh.dispatch(cx, Message::SaveState(None)); }) } } diff --git a/web/src/components/shopping_list.rs b/web/src/components/shopping_list.rs index 2d023d5..1a219e8 100644 --- a/web/src/components/shopping_list.rs +++ b/web/src/components/shopping_list.rs @@ -202,7 +202,7 @@ pub fn ShoppingList<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> V }) input(type="button", value="Save", class="no-print", on:click=move |_| { info!("Registering save request for inventory"); - sh.dispatch(cx, Message::SaveState); + sh.dispatch(cx, Message::SaveState(None)); }) } } diff --git a/web/src/pages/login.rs b/web/src/pages/login.rs index 614191f..d16c495 100644 --- a/web/src/pages/login.rs +++ b/web/src/pages/login.rs @@ -36,8 +36,7 @@ pub fn LoginForm<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View debug!("authenticating against ui"); if let Some(user_data) = store.authenticate(username, password).await { sh.dispatch(cx, Message::SetUserData(user_data)); - sh.dispatch(cx, Message::LoadState); - sycamore_router::navigate("/ui/planning/plan"); + sh.dispatch(cx, Message::LoadState(Some(Box::new(|| sycamore_router::navigate("/ui/planning/plan"))))); } }); } diff --git a/web/src/web.rs b/web/src/web.rs index 8791351..bff2228 100644 --- a/web/src/web.rs +++ b/web/src/web.rs @@ -20,7 +20,6 @@ use crate::{api, routing::Handler as RouteHandler}; #[instrument] #[component] pub fn UI(cx: Scope) -> View { - // FIXME(jwall): We shouldn't need to get the store from a context anymore. api::HttpStore::provide_context(cx, "/api".to_owned()); let store = api::HttpStore::get_from_context(cx).as_ref().clone(); info!("Starting UI"); @@ -29,8 +28,7 @@ pub fn UI(cx: Scope) -> View { let view = create_signal(cx, View::empty()); spawn_local_scoped(cx, { async move { - sh.dispatch(cx, Message::LoadState); - // TODO(jwall): This needs to be moved into the RouteHandler + sh.dispatch(cx, Message::LoadState(None)); view.set(view! { cx, RouteHandler(sh=sh) });