Thread statehandler through router to pages

This commit is contained in:
Jeremy Wall 2022-12-26 21:56:28 -05:00
parent e21353eeba
commit 90346d55eb
11 changed files with 67 additions and 83 deletions

View File

@ -14,7 +14,7 @@
use sycamore::{futures::spawn_local_scoped, prelude::*}; use sycamore::{futures::spawn_local_scoped, prelude::*};
use tracing::{debug, info}; use tracing::{debug, info};
use crate::app_state; use crate::app_state::{self, StateHandler};
#[component] #[component]
pub fn LoginForm<G: Html>(cx: Scope) -> View<G> { pub fn LoginForm<G: Html>(cx: Scope) -> View<G> {
@ -50,7 +50,7 @@ pub fn LoginForm<G: Html>(cx: Scope) -> View<G> {
} }
#[component] #[component]
pub fn LoginPage<G: Html>(cx: Scope) -> View<G> { pub fn LoginPage<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
view! {cx, view! {cx,
LoginForm() LoginForm()
} }

View File

@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use super::ManagePage; use super::ManagePage;
use crate::components::add_recipe::AddRecipe; use crate::{app_state::StateHandler, components::add_recipe::AddRecipe};
use sycamore::prelude::*; use sycamore::prelude::*;
#[component] #[component]
pub fn AddRecipePage<G: Html>(cx: Scope) -> View<G> { pub fn AddRecipePage<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
view! {cx, view! {cx,
ManagePage( ManagePage(
selected=Some("New Recipe".to_owned()), selected=Some("New Recipe".to_owned()),

View File

@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use super::ManagePage; use super::ManagePage;
use crate::components::categories::*; use crate::{app_state::StateHandler, components::categories::*};
use sycamore::prelude::*; use sycamore::prelude::*;
#[component()] #[component()]
pub fn CategoryPage<G: Html>(cx: Scope) -> View<G> { pub fn CategoryPage<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
view! {cx, view! {cx,
ManagePage( ManagePage(
selected=Some("Categories".to_owned()), selected=Some("Categories".to_owned()),

View File

@ -12,14 +12,14 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use super::ManagePage; use super::ManagePage;
use crate::components::recipe::Editor; use crate::{app_state::StateHandler, components::recipe::Editor};
use sycamore::prelude::*; use sycamore::prelude::*;
use tracing::instrument; use tracing::instrument;
#[instrument] #[instrument(skip_all)]
#[component()] #[component()]
pub fn StaplesPage<G: Html>(cx: Scope) -> View<G> { pub fn StaplesPage<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
view! {cx, view! {cx,
ManagePage( ManagePage(
selected=Some("Staples".to_owned()), selected=Some("Staples".to_owned()),

View File

@ -14,10 +14,10 @@
use sycamore::prelude::*; use sycamore::prelude::*;
use super::PlanningPage; use super::PlanningPage;
use crate::components::recipe_list::*; use crate::{app_state::StateHandler, components::recipe_list::*};
#[component] #[component]
pub fn CookPage<G: Html>(cx: Scope) -> View<G> { pub fn CookPage<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
view! {cx, view! {cx,
PlanningPage( PlanningPage(
selected=Some("Cook".to_owned()), selected=Some("Cook".to_owned()),

View File

@ -14,10 +14,10 @@
use sycamore::prelude::*; use sycamore::prelude::*;
use super::PlanningPage; use super::PlanningPage;
use crate::components::shopping_list::*; use crate::{app_state::StateHandler, components::shopping_list::*};
#[component] #[component]
pub fn InventoryPage<G: Html>(cx: Scope) -> View<G> { pub fn InventoryPage<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
view! {cx, view! {cx,
PlanningPage( PlanningPage(
selected=Some("Inventory".to_owned()), selected=Some("Inventory".to_owned()),

View File

@ -12,12 +12,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use super::PlanningPage; use super::PlanningPage;
use crate::components::recipe_plan::*; use crate::{app_state::StateHandler, components::recipe_plan::*};
use sycamore::prelude::*; use sycamore::prelude::*;
#[component] #[component]
pub fn PlanPage<G: Html>(cx: Scope) -> View<G> { pub fn PlanPage<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
view! {cx, view! {cx,
PlanningPage( PlanningPage(
selected=Some("Plan".to_owned()), selected=Some("Plan".to_owned()),

View File

@ -17,13 +17,14 @@ use crate::components::recipe::Editor;
use sycamore::prelude::*; use sycamore::prelude::*;
use tracing::instrument; use tracing::instrument;
#[instrument] #[instrument(skip_all, fields(recipe=props.recipe))]
#[component()] #[component()]
pub fn RecipeEditPage<G: Html>(cx: Scope, props: RecipePageProps) -> View<G> { pub fn RecipeEditPage<G: Html>(cx: Scope, props: RecipePageProps) -> View<G> {
let RecipePageProps { recipe, sh } = props;
view! {cx, view! {cx,
RecipePage( RecipePage(
selected=Some("Edit".to_owned()), selected=Some("Edit".to_owned()),
recipe=props.recipe.clone(), recipe=recipe.clone(),
) { Editor(props.recipe) } ) { Editor(recipe) }
} }
} }

View File

@ -13,16 +13,17 @@
// limitations under the License. // limitations under the License.
use sycamore::prelude::*; use sycamore::prelude::*;
use crate::components::tabs::*; use crate::{app_state::StateHandler, components::tabs::*};
mod edit; mod edit;
mod view; mod view;
pub use edit::*; pub use edit::*;
pub use view::*; pub use view::*;
#[derive(Debug, Props)] #[derive(Props)]
pub struct RecipePageProps { pub struct RecipePageProps<'ctx> {
pub recipe: String, pub recipe: String,
pub sh: StateHandler<'ctx>,
} }
#[derive(Props)] #[derive(Props)]

View File

@ -18,13 +18,14 @@ use tracing::instrument;
use super::{RecipePage, RecipePageProps}; use super::{RecipePage, RecipePageProps};
#[instrument] #[instrument(skip_all, fields(recipe=props.recipe))]
#[component()] #[component()]
pub fn RecipeViewPage<G: Html>(cx: Scope, props: RecipePageProps) -> View<G> { pub fn RecipeViewPage<G: Html>(cx: Scope, props: RecipePageProps) -> View<G> {
let RecipePageProps { recipe, sh } = props;
view! {cx, view! {cx,
RecipePage( RecipePage(
selected=Some("View".to_owned()), selected=Some("View".to_owned()),
recipe=props.recipe.clone(), recipe=recipe.clone(),
) { Viewer(props.recipe) } ) { Viewer(recipe) }
} }
} }

View File

@ -16,65 +16,8 @@ use crate::app_state::StateHandler;
use sycamore::prelude::*; use sycamore::prelude::*;
use sycamore_router::{HistoryIntegration, Route, Router}; use sycamore_router::{HistoryIntegration, Route, Router};
use tracing::{debug, instrument};
use crate::pages::*; use crate::pages::*;
#[instrument(skip_all, fields(?route))]
fn route_switch<'ctx, G: Html>(
cx: Scope<'ctx>,
sh: StateHandler<'ctx>,
route: &'ctx ReadSignal<Routes>,
) -> View<G> {
// 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, sh: StateHandler, route: &Routes| {
debug!(?route, "Dispatching for route");
match route {
Routes::Planning(Plan) => view! {cx,
PlanPage()
},
Routes::Planning(Inventory) => view! {cx,
InventoryPage()
},
Routes::Planning(Cook) => view! {cx,
CookPage()
},
Routes::Login => view! {cx,
LoginPage()
},
Routes::Recipe(RecipeRoutes::View(id)) => view! {cx,
RecipeViewPage(recipe=id.clone())
},
Routes::Recipe(RecipeRoutes::Edit(id)) => view! {cx,
RecipeEditPage(recipe=id.clone())
},
Routes::Manage(ManageRoutes::Categories) => view! {cx,
CategoryPage()
},
Routes::Manage(ManageRoutes::NewRecipe) => view! {cx,
AddRecipePage()
},
Routes::Manage(ManageRoutes::Staples) => view! {cx,
StaplesPage()
},
Routes::NotFound
| Routes::Manage(ManageRoutes::NotFound)
| Routes::Planning(PlanningRoutes::NotFound)
| Routes::Recipe(RecipeRoutes::NotFound) => view! {cx,
// TODO(Create a real one)
PlanPage()
},
}
};
use PlanningRoutes::*;
view! {cx,
(switcher(cx, sh, route.get().as_ref()))
}
}
#[derive(Route, Debug)] #[derive(Route, Debug)]
pub enum Routes { pub enum Routes {
#[to("/ui/planning/<_..>")] #[to("/ui/planning/<_..>")]
@ -131,11 +74,49 @@ pub struct HandlerProps<'ctx> {
#[component] #[component]
pub fn Handler<'ctx, G: Html>(cx: Scope<'ctx>, props: HandlerProps<'ctx>) -> View<G> { pub fn Handler<'ctx, G: Html>(cx: Scope<'ctx>, props: HandlerProps<'ctx>) -> View<G> {
let HandlerProps { sh } = props; let HandlerProps { sh } = props;
use ManageRoutes::*;
use PlanningRoutes::*;
view! {cx, view! {cx,
Router( Router(
integration=HistoryIntegration::new(), integration=HistoryIntegration::new(),
view=|cx, route| { view=move |cx: Scope, route: &ReadSignal<Routes>| {
route_switch(cx, sh, route) match route.get().as_ref() {
Routes::Planning(Plan) => view! {cx,
PlanPage(sh)
},
Routes::Planning(Inventory) => view! {cx,
InventoryPage(sh)
},
Routes::Planning(Cook) => view! {cx,
CookPage(sh)
},
Routes::Login => view! {cx,
LoginPage(sh)
},
Routes::Recipe(RecipeRoutes::View(id)) => view! {cx,
RecipeViewPage(recipe=id.clone(), sh=sh)
},
Routes::Recipe(RecipeRoutes::Edit(id)) => view! {cx,
RecipeEditPage(recipe=id.clone(), sh=sh)
},
Routes::Manage(Categories) => view! {cx,
CategoryPage(sh)
},
Routes::Manage(NewRecipe) => view! {cx,
AddRecipePage(sh)
},
Routes::Manage(Staples) => view! {cx,
StaplesPage(sh)
},
Routes::NotFound
| Routes::Manage(ManageRoutes::NotFound)
| Routes::Planning(PlanningRoutes::NotFound)
| Routes::Recipe(RecipeRoutes::NotFound) => view! {cx,
// TODO(Create a real one)
PlanPage(sh)
},
}
}, },
) )
} }