mirror of
https://github.com/zaphar/kitchen.git
synced 2025-07-22 19:40:14 -04:00
Make State Management ssr safe
This commit is contained in:
parent
c9bcfe220e
commit
a83b60e016
@ -21,23 +21,26 @@ pub struct TabState<G: GenericNode> {
|
||||
#[component(TabbedView<G>)]
|
||||
pub fn tabbed_view(state: TabState<G>) -> View<G> {
|
||||
cloned!((state) => view! {
|
||||
header(class="no-print") {
|
||||
nav {
|
||||
ul {
|
||||
li { a(href="/ui/plan", class="no-print") { "Plan" } " > "
|
||||
// NOTE(jwall): this needs to be a single node or the Router freaks out.
|
||||
div {
|
||||
header(class="no-print") {
|
||||
nav {
|
||||
ul {
|
||||
li { a(href="/ui/plan", class="no-print") { "Plan" } " > "
|
||||
}
|
||||
li { a(href="/ui/inventory", class="no-print") { "Inventory" } " > "
|
||||
}
|
||||
li { a(href="/ui/cook", class="no-print") { "Cook" }
|
||||
}
|
||||
}
|
||||
li { a(href="/ui/inventory", class="no-print") { "Inventory" } " > "
|
||||
ul {
|
||||
li { a(href="https://github.com/zaphar/kitchen") { "Github" } }
|
||||
}
|
||||
li { a(href="/ui/cook", class="no-print") { "Cook" }
|
||||
}
|
||||
}
|
||||
ul {
|
||||
li { a(href="https://github.com/zaphar/kitchen") { "Github" } }
|
||||
}
|
||||
}
|
||||
}
|
||||
main(class=".conatiner-fluid") {
|
||||
(state.inner)
|
||||
main(class=".conatiner-fluid") {
|
||||
(state.inner)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -13,9 +13,15 @@
|
||||
// limitations under the License.
|
||||
use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use serde_json::{from_str, to_string};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use serde_json::from_str;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use serde_json::to_string;
|
||||
use sycamore::{context::use_context, prelude::*};
|
||||
use tracing::{debug, error, info, instrument, warn};
|
||||
use tracing::{debug, instrument, warn};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use tracing::{error, info};
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
use web_sys::{window, Storage};
|
||||
|
||||
use recipe_store::*;
|
||||
@ -56,6 +62,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
fn get_storage(&self) -> Result<Option<Storage>, String> {
|
||||
window()
|
||||
.unwrap()
|
||||
@ -63,9 +70,19 @@ where
|
||||
.map_err(|e| format!("{:?}", e))
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
#[instrument(skip(self))]
|
||||
async fn synchronize(&self) -> Result<(), String> {
|
||||
pub async fn init(&self, force: bool) -> Result<(), String> {
|
||||
// TODO(jwall): Allow this to work for the ssr case.
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[instrument(skip(self))]
|
||||
pub async fn init(&self, force: bool) -> Result<(), String> {
|
||||
info!("Synchronizing Recipes");
|
||||
// TODO(jwall): Check to see if we already have them in storage
|
||||
// only fetch via http if force is true.
|
||||
let storage = self.get_storage()?.unwrap();
|
||||
let recipes = self
|
||||
.store
|
||||
@ -96,10 +113,9 @@ where
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[instrument(skip(self))]
|
||||
pub fn fetch_categories_from_storage(
|
||||
&self,
|
||||
) -> Result<Option<BTreeMap<String, String>>, String> {
|
||||
fn fetch_categories_from_storage(&self) -> Result<Option<BTreeMap<String, String>>, String> {
|
||||
let storage = self.get_storage()?.unwrap();
|
||||
match storage
|
||||
.get_item("categories")
|
||||
@ -119,8 +135,9 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
#[instrument(skip(self))]
|
||||
pub fn fetch_recipes_from_storage(
|
||||
fn fetch_recipes_from_storage(
|
||||
&self,
|
||||
) -> Result<(Option<Recipe>, Option<BTreeMap<String, Recipe>>), String> {
|
||||
let storage = self.get_storage()?.unwrap();
|
||||
@ -153,19 +170,32 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
async fn fetch_recipes(
|
||||
&self,
|
||||
) -> Result<(Option<Recipe>, Option<BTreeMap<String, Recipe>>), String> {
|
||||
Ok(self.fetch_recipes_from_storage()?)
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
async fn fetch_recipes(
|
||||
&self,
|
||||
) -> Result<(Option<Recipe>, Option<BTreeMap<String, Recipe>>), String> {
|
||||
Ok((None, None))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
async fn fetch_categories(&self) -> Result<Option<BTreeMap<String, String>>, String> {
|
||||
Ok(self.fetch_categories_from_storage()?)
|
||||
}
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
async fn fetch_categories(&self) -> Result<Option<BTreeMap<String, String>>, String> {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
// FIXME(jwall): Stays public
|
||||
#[instrument(skip(self))]
|
||||
pub async fn refresh(&mut self) -> Result<(), String> {
|
||||
self.synchronize().await?;
|
||||
self.init(true).await?;
|
||||
debug!("refreshing recipes");
|
||||
if let (staples, Some(r)) = self.fetch_recipes().await? {
|
||||
self.set_recipes(r);
|
||||
@ -182,6 +212,7 @@ where
|
||||
self.recipes.get().get(idx).map(|r| r.clone())
|
||||
}
|
||||
|
||||
// FIXME(jwall): Stays public
|
||||
#[instrument(skip(self))]
|
||||
pub fn get_shopping_list(
|
||||
&self,
|
||||
@ -243,7 +274,7 @@ where
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn set_recipes(&mut self, mut recipes: BTreeMap<String, Recipe>) {
|
||||
pub fn set_recipes(&mut self, recipes: BTreeMap<String, Recipe>) {
|
||||
self.recipes.set(
|
||||
recipes
|
||||
.iter()
|
||||
|
@ -27,7 +27,7 @@ fn route_switch<G: Html>(route: ReadSignal<AppRoutes>) -> 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.
|
||||
cloned!((route) => match route.get().as_ref() {
|
||||
let node = cloned!((route) => match route.get().as_ref() {
|
||||
AppRoutes::Plan => view! {
|
||||
PlanPage()
|
||||
},
|
||||
@ -50,7 +50,9 @@ fn route_switch<G: Html>(route: ReadSignal<AppRoutes>) -> View<G> {
|
||||
"Error: " (e)
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
debug!(node=?node, "routing to new page");
|
||||
node
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
@ -95,17 +97,11 @@ pub fn ui(route: Option<AppRoutes>) -> View<G> {
|
||||
children: || {
|
||||
create_effect(move || {
|
||||
spawn_local_in_scope({
|
||||
let mut app_service = app_service.clone();
|
||||
let app_service = app_service.clone();
|
||||
async move {
|
||||
debug!("fetching recipes");
|
||||
match app_service.fetch_recipes_from_storage() {
|
||||
Ok((_, Some(recipes))) => {
|
||||
app_service.set_recipes(recipes);
|
||||
}
|
||||
Ok((_, None)) => {
|
||||
error!("No recipes to find");
|
||||
}
|
||||
Err(msg) => error!("Failed to get recipes {}", msg),
|
||||
if let Err(msg) = app_service.init(false).await {
|
||||
error!("Failed to get recipes {}", msg)
|
||||
}
|
||||
}
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user