diff --git a/web/src/app_state.rs b/web/src/app_state.rs index 81e921e..63f2322 100644 --- a/web/src/app_state.rs +++ b/web/src/app_state.rs @@ -131,10 +131,9 @@ impl MessageMapper for StateMachine { } } -pub fn get_state_handler<'ctx>( - cx: Scope<'ctx>, - initial: AppState, -) -> &'ctx Handler<'ctx, StateMachine, AppState, Message> { +pub type StateHandler<'ctx> = &'ctx Handler<'ctx, StateMachine, AppState, Message>; + +pub fn get_state_handler<'ctx>(cx: Scope<'ctx>, initial: AppState) -> StateHandler<'ctx> { Handler::new(cx, initial, StateMachine()) } #[derive(Debug)] diff --git a/web/src/components/header.rs b/web/src/components/header.rs index 80cf0a5..438c866 100644 --- a/web/src/components/header.rs +++ b/web/src/components/header.rs @@ -14,14 +14,10 @@ use sycamore::prelude::*; -use crate::app_state::{AppState, Message, StateMachine}; -use sycamore_state::Handler; +use crate::app_state::StateHandler; #[component] -pub fn Header<'ctx, G: Html>( - cx: Scope<'ctx>, - h: &'ctx Handler<'ctx, StateMachine, AppState, Message>, -) -> View { +pub fn Header<'ctx, G: Html>(cx: Scope<'ctx>, h: StateHandler<'ctx>) -> View { let login = h.get_selector(cx, |sig| match &sig.get().auth { Some(id) => id.user_id.clone(), None => "Login".to_owned(), diff --git a/web/src/routing/mod.rs b/web/src/routing/mod.rs index 8e87c20..c8c3024 100644 --- a/web/src/routing/mod.rs +++ b/web/src/routing/mod.rs @@ -12,19 +12,25 @@ // See the License for the specific language governing permissions and // limitations under the License. +use crate::app_state::StateHandler; use sycamore::prelude::*; use sycamore_router::{HistoryIntegration, Route, Router}; + use tracing::{debug, instrument}; use crate::pages::*; -#[instrument] -fn route_switch<'a, G: Html>(cx: Scope<'a>, route: &'a ReadSignal) -> View { +#[instrument(skip_all, fields(?route))] +fn route_switch<'ctx, G: Html>( + cx: Scope<'ctx>, + sh: StateHandler<'ctx>, + route: &'ctx 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 // avoid conditionals in the `view!` macro calls here. - let switcher = |cx: Scope, route: &Routes| { + let switcher = |cx: Scope, sh: StateHandler, route: &Routes| { debug!(?route, "Dispatching for route"); match route { Routes::Planning(Plan) => view! {cx, @@ -65,7 +71,7 @@ fn route_switch<'a, G: Html>(cx: Scope<'a>, route: &'a ReadSignal) -> Vi }; use PlanningRoutes::*; view! {cx, - (switcher(cx, route.get().as_ref())) + (switcher(cx, sh, route.get().as_ref())) } } @@ -117,12 +123,20 @@ pub enum PlanningRoutes { NotFound, } +#[derive(Props)] +pub struct HandlerProps<'ctx> { + sh: StateHandler<'ctx>, +} + #[component] -pub fn Handler(cx: Scope) -> View { +pub fn Handler<'ctx, G: Html>(cx: Scope<'ctx>, props: HandlerProps<'ctx>) -> View { + let HandlerProps { sh } = props; view! {cx, Router( integration=HistoryIntegration::new(), - view=route_switch, + view=|cx, route| { + route_switch(cx, sh, route) + }, ) } } diff --git a/web/src/web.rs b/web/src/web.rs index efedbf3..a16932d 100644 --- a/web/src/web.rs +++ b/web/src/web.rs @@ -34,7 +34,7 @@ pub fn UI(cx: Scope) -> View { view.set(view! { cx, div(class="app") { Header(handler) - RouteHandler() + RouteHandler(sh=handler) Footer { } } });