From 71a4e093b918b6ccbac93651a574454459210c08 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Thu, 21 Jul 2022 16:33:55 -0400 Subject: [PATCH] Navigate to recipe view from plan page --- web/src/components/recipe.rs | 34 ++++++++++++++++---------- web/src/components/recipe_selection.rs | 2 +- web/src/pages/recipe.rs | 3 +++ web/src/router_integration.rs | 16 ++++++++++++ web/src/web.rs | 4 ++- 5 files changed, 44 insertions(+), 15 deletions(-) diff --git a/web/src/components/recipe.rs b/web/src/components/recipe.rs index 6705aeb..d5e82da 100644 --- a/web/src/components/recipe.rs +++ b/web/src/components/recipe.rs @@ -49,19 +49,27 @@ fn steps(steps: ReadSignal>) -> View { #[component(Recipe)] pub fn recipe(idx: ReadSignal) -> View { let app_service = use_context::(); - let recipe = app_service.get_recipes().get()[*idx.get()].1.clone(); - let title = create_memo(cloned!((recipe) => move || recipe.get().title.clone())); - let desc = create_memo( - cloned!((recipe) => move || recipe.clone().get().desc.clone().unwrap_or_else(|| String::new())), - ); - let steps = create_memo(cloned!((recipe) => move || recipe.get().steps.clone())); - view! { - div(class="recipe") { - h1(class="recipe_title") { (title.get()) } - div(class="recipe_description") { - (desc.get()) - } - Steps(steps) + let view = Signal::new(View::empty()); + create_effect(cloned!((app_service, view) => move || { + if let Some((_, recipe)) = app_service.get_recipes().get().get(*idx.get()) { + let recipe = recipe.clone(); + let title = create_memo(cloned!((recipe) => move || recipe.get().title.clone())); + let desc = create_memo( + cloned!((recipe) => move || recipe.clone().get().desc.clone().unwrap_or_else(|| String::new())), + ); + let steps = create_memo(cloned!((recipe) => move || recipe.get().steps.clone())); + view.set(view! { + div(class="recipe") { + h1(class="recipe_title") { (title.get()) } + div(class="recipe_description") { + (desc.get()) + } + Steps(steps) + } + }); } + })); + view! { + (view.get().as_ref()) } } diff --git a/web/src/components/recipe_selection.rs b/web/src/components/recipe_selection.rs index a687b4a..fc41524 100644 --- a/web/src/components/recipe_selection.rs +++ b/web/src/components/recipe_selection.rs @@ -38,7 +38,7 @@ pub fn recipe_selection(props: RecipeCheckBoxProps) -> View { let count = Signal::new(format!("{}", app_service.get_recipe_count_by_index(i))); view! { div() { - label(for=id_cloned_2) { (props.title.get()) } + label(for=id_cloned_2) { a(href=format!("#recipe/{}", i)) { (props.title.get()) } } input(type="number", class="item-count-sel", min="0", bind:value=count.clone(), name=format!("recipe_id:{}", i), value=id_as_str.clone(), on:change=move |_| { let mut app_service = app_service.clone(); debug!(idx=%i, count=%(*count.get()), "setting recipe count"); diff --git a/web/src/pages/recipe.rs b/web/src/pages/recipe.rs index 79eb8ef..674d150 100644 --- a/web/src/pages/recipe.rs +++ b/web/src/pages/recipe.rs @@ -14,11 +14,14 @@ use crate::components::{recipe::Recipe, tabs::*}; use sycamore::prelude::*; +use tracing::instrument; +#[derive(Debug)] pub struct RecipePageProps { pub recipe: Signal, } +#[instrument] #[component(RecipePage)] pub fn recipe_page(props: RecipePageProps) -> View { view! { diff --git a/web/src/router_integration.rs b/web/src/router_integration.rs index 0069f86..02c0655 100644 --- a/web/src/router_integration.rs +++ b/web/src/router_integration.rs @@ -37,6 +37,16 @@ impl BrowserIntegration { ))) } + #[instrument(skip(self, f))] + pub fn register_post_state_handler(&self, f: Box) { + let closure = Closure::wrap(f); + web_sys::window() + .unwrap_throw() + .add_event_listener_with_callback("popstate", closure.as_ref().unchecked_ref()) + .unwrap_throw(); + closure.forget(); + } + #[instrument(skip(self))] pub fn click_handler(&self) -> Box { let route_signal = self.0.clone(); @@ -130,6 +140,12 @@ where }), ); + let path_signal = integration.0.clone(); + integration.register_post_state_handler(Box::new(cloned!((path_signal) => move || { + let location = web_sys::window().unwrap_throw().location(); + path_signal.set((location.origin().unwrap_throw(), location.pathname().unwrap_throw(), location.hash().unwrap_throw())); + }))); + // NOTE(jwall): This needs to be a dynamic node so Sycamore knows to rerender it // based on the results of the effect above. view! { diff --git a/web/src/web.rs b/web/src/web.rs index 6cacb6a..cae6917 100644 --- a/web/src/web.rs +++ b/web/src/web.rs @@ -13,7 +13,7 @@ // limitations under the License. use crate::pages::*; use crate::{app_state::*, components::*, router_integration::*, service::AppService}; -use tracing::{error, info, instrument}; +use tracing::{debug, error, info, instrument}; use sycamore::{ context::{ContextProvider, ContextProviderProps}, @@ -21,6 +21,7 @@ use sycamore::{ prelude::*, }; +#[instrument] fn route_switch(route: ReadSignal) -> View { // NOTE(jwall): This needs to not be a dynamic node. The rules around // this are somewhat unclear and underdocumented for Sycamore. But basically @@ -66,6 +67,7 @@ pub fn ui() -> View { spawn_local_in_scope({ let mut app_service = app_service.clone(); async move { + debug!("fetching recipes"); match AppService::fetch_recipes_from_storage() { Ok((_, Some(recipes))) => { app_service.set_recipes(recipes);