diff --git a/web/src/app_state.rs b/web/src/app_state.rs index 0e0479f..d2a1b4a 100644 --- a/web/src/app_state.rs +++ b/web/src/app_state.rs @@ -30,7 +30,7 @@ pub struct AppState { pub extras: BTreeSet<(String, String)>, pub staples: Option, pub recipes: BTreeMap, - pub category_map: BTreeMap, + pub category_map: String, pub filtered_ingredients: BTreeSet, pub modified_amts: BTreeMap, pub auth: Option, @@ -43,7 +43,7 @@ impl AppState { extras: BTreeSet::new(), staples: None, recipes: BTreeMap::new(), - category_map: BTreeMap::new(), + category_map: String::new(), filtered_ingredients: BTreeSet::new(), modified_amts: BTreeMap::new(), auth: None, @@ -63,7 +63,8 @@ pub enum Message { SetRecipe(String, Recipe), RemoveRecipe(String), SetStaples(Option), - SetCategoryMap(BTreeMap), + SetCategoryMap(String), + UpdateCategories, InitFilteredIngredient(BTreeSet), AddFilteredIngredient(IngredientKey), RemoveFilteredIngredient(IngredientKey), @@ -154,14 +155,7 @@ impl StateMachine { match store.get_categories().await { Ok(Some(categories_content)) => { debug!(categories=?categories_content); - match recipes::parse::as_categories(&categories_content) { - Ok(category_map) => { - state.category_map = category_map; - } - Err(err) => { - error!(?err) - } - }; + state.category_map = categories_content; } Ok(None) => { warn!("There is no category file"); @@ -233,8 +227,29 @@ impl MessageMapper for StateMachine { Message::RemoveRecipe(id) => { original_copy.recipes.remove(&id); } - Message::SetCategoryMap(map) => { - original_copy.category_map = map; + Message::SetCategoryMap(category_text) => { + let store = self.0.clone(); + original_copy.category_map = category_text.clone(); + spawn_local_scoped(cx, async move { + if let Err(e) = store.save_categories(category_text).await { + error!(?e, "Failed to save categories"); + } + }); + } + Message::UpdateCategories => { + let store = self.0.clone(); + let mut original_copy = original_copy.clone(); + spawn_local_scoped(cx, async move { + if let Some(categories) = match store.get_categories().await { + Ok(js) => js, + Err(e) => { + error!(err=?e, "Failed to get categories."); + return; + } + } { + original_copy.category_map = categories; + }; + }); } Message::InitFilteredIngredient(set) => { original_copy.filtered_ingredients = set; diff --git a/web/src/components/categories.rs b/web/src/components/categories.rs index 68338d6..935f468 100644 --- a/web/src/components/categories.rs +++ b/web/src/components/categories.rs @@ -11,14 +11,16 @@ // 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 crate::{ + app_state::{Message, StateHandler}, + js_lib::get_element_by_id, +}; use sycamore::{futures::spawn_local_scoped, prelude::*}; use tracing::{debug, error, instrument}; use web_sys::HtmlDialogElement; use recipes::parse; -use crate::js_lib::get_element_by_id; - fn get_error_dialog() -> HtmlDialogElement { get_element_by_id::("error-dialog") .expect("error-dialog isn't an html dialog element!") @@ -38,9 +40,9 @@ fn check_category_text_parses(unparsed: &str, error_text: &Signal) -> bo } } -#[instrument] +#[instrument(skip_all)] #[component] -pub fn Categories(cx: Scope) -> View { +pub fn Categories<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View { let save_signal = create_signal(cx, ()); let error_text = create_signal(cx, String::new()); let category_text: &Signal = create_signal(cx, String::new()); @@ -65,18 +67,11 @@ pub fn Categories(cx: Scope) -> View { return; } spawn_local_scoped(cx, { - let store = crate::api::HttpStore::get_from_context(cx); async move { - // TODO(jwall): Save the categories. - if let Err(e) = store - .save_categories(category_text.get_untracked().as_ref().clone()) - .await - { - error!(?e, "Failed to save categories"); - error_text.set(format!("{:?}", e)); - } else { - dirty.set(false); - } + sh.dispatch( + cx, + Message::SetCategoryMap(category_text.get_untracked().as_ref().clone()), + ); } }); }); diff --git a/web/src/pages/manage/categories.rs b/web/src/pages/manage/categories.rs index ac78bf6..fb46e92 100644 --- a/web/src/pages/manage/categories.rs +++ b/web/src/pages/manage/categories.rs @@ -21,6 +21,6 @@ pub fn CategoryPage<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> V view! {cx, ManagePage( selected=Some("Categories".to_owned()), - ) { Categories() } + ) { Categories(sh) } } } diff --git a/web/src/web.rs b/web/src/web.rs index a50ea74..d217ba9 100644 --- a/web/src/web.rs +++ b/web/src/web.rs @@ -21,8 +21,8 @@ use crate::{api, routing::Handler as RouteHandler}; #[instrument] #[component] pub fn UI(cx: Scope) -> View { - api::HttpStore::provide_context(cx, "/api".to_owned()); // 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"); let app_state = crate::app_state::AppState::new();