Store the use_staples setting in localstore

This commit is contained in:
Jeremy Wall 2023-07-24 19:37:31 -04:00
parent 2ea0339ad1
commit db03d603c3
4 changed files with 31 additions and 6 deletions

View File

@ -99,7 +99,6 @@ impl LocalStore {
.expect("Failed to set our app state"); .expect("Failed to set our app state");
} }
// TODO(jwall): Is this never used?
pub fn fetch_app_state(&self) -> Option<AppState> { pub fn fetch_app_state(&self) -> Option<AppState> {
self.store.get("app_state").map_or(None, |val| { self.store.get("app_state").map_or(None, |val| {
val.map(|s| from_str(&s).expect("Failed to deserialize app state")) val.map(|s| from_str(&s).expect("Failed to deserialize app state"))

View File

@ -31,6 +31,10 @@ use crate::{
components, linear::LinearSignal, components, linear::LinearSignal,
}; };
fn bool_true() -> bool {
true
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AppState { pub struct AppState {
pub recipe_counts: BTreeMap<String, usize>, pub recipe_counts: BTreeMap<String, usize>,
@ -46,6 +50,8 @@ pub struct AppState {
pub auth: Option<UserData>, pub auth: Option<UserData>,
pub plan_dates: BTreeSet<NaiveDate>, pub plan_dates: BTreeSet<NaiveDate>,
pub selected_plan_date: Option<NaiveDate>, pub selected_plan_date: Option<NaiveDate>,
#[serde(default = "bool_true")]
pub use_staples: bool,
} }
impl AppState { impl AppState {
@ -62,6 +68,7 @@ impl AppState {
auth: None, auth: None,
plan_dates: BTreeSet::new(), plan_dates: BTreeSet::new(),
selected_plan_date: None, selected_plan_date: None,
use_staples: true,
} }
} }
} }
@ -84,6 +91,7 @@ pub enum Message {
UpdateStaples(String, Option<Box<dyn FnOnce()>>), UpdateStaples(String, Option<Box<dyn FnOnce()>>),
DeletePlan(NaiveDate, Option<Box<dyn FnOnce()>>), DeletePlan(NaiveDate, Option<Box<dyn FnOnce()>>),
SelectPlanDate(NaiveDate, Option<Box<dyn FnOnce()>>), SelectPlanDate(NaiveDate, Option<Box<dyn FnOnce()>>),
UpdateUseStaples(bool), // TODO(jwall): Should this just be various settings?
} }
impl Debug for Message { impl Debug for Message {
@ -121,6 +129,7 @@ impl Debug for Message {
Self::SaveState(_) => write!(f, "SaveState"), Self::SaveState(_) => write!(f, "SaveState"),
Self::LoadState(_) => write!(f, "LoadState"), Self::LoadState(_) => write!(f, "LoadState"),
Self::UpdateStaples(arg, _) => f.debug_tuple("UpdateStaples").field(arg).finish(), Self::UpdateStaples(arg, _) => f.debug_tuple("UpdateStaples").field(arg).finish(),
Self::UpdateUseStaples(arg) => f.debug_tuple("UpdateUseStaples").field(arg).finish(),
Self::SelectPlanDate(arg, _) => f.debug_tuple("SelectPlanDate").field(arg).finish(), Self::SelectPlanDate(arg, _) => f.debug_tuple("SelectPlanDate").field(arg).finish(),
Self::DeletePlan(arg, _) => f.debug_tuple("DeletePlan").field(arg).finish(), Self::DeletePlan(arg, _) => f.debug_tuple("DeletePlan").field(arg).finish(),
} }
@ -165,8 +174,12 @@ impl StateMachine {
local_store: &LocalStore, local_store: &LocalStore,
original: &Signal<AppState>, original: &Signal<AppState>,
) -> Result<(), crate::api::Error> { ) -> Result<(), crate::api::Error> {
// TODO(jwall): Load plan state from local_store first. // TODO(jwall): We use a linear Signal in here to ensure that we only
let original: LinearSignal<AppState> = original.into(); // call set on the signal once.
let mut original: LinearSignal<AppState> = original.into();
if let Some(state) = local_store.fetch_app_state() {
original = original.update(state);
}
let mut state = original.get().as_ref().clone(); let mut state = original.get().as_ref().clone();
info!("Synchronizing Recipes"); info!("Synchronizing Recipes");
let recipe_entries = &store.fetch_recipes().await?; let recipe_entries = &store.fetch_recipes().await?;
@ -449,6 +462,9 @@ impl MessageMapper<Message, AppState> for StateMachine {
}); });
return; return;
} }
Message::UpdateUseStaples(value) => {
original_copy.use_staples = value;
}
Message::SelectPlanDate(date, callback) => { Message::SelectPlanDate(date, callback) => {
let store = self.store.clone(); let store = self.store.clone();
let local_store = self.local_store.clone(); let local_store = self.local_store.clone();

View File

@ -194,11 +194,16 @@ fn make_shopping_table<'ctx, G: Html>(
#[instrument(skip_all)] #[instrument(skip_all)]
#[component] #[component]
pub fn ShoppingList<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> { pub fn ShoppingList<'ctx, G: Html>(cx: Scope<'ctx>, sh: StateHandler<'ctx>) -> View<G> {
let show_staples = create_signal(cx, true); let show_staples = sh.get_selector(cx, |state| {
state.get().use_staples
});
view! {cx, view! {cx,
h1 { "Shopping List " } h1 { "Shopping List " }
label(for="show_staples_cb") { "Show staples" } label(for="show_staples_cb") { "Show staples" }
input(id="show_staples_cb", type="checkbox", bind:checked=show_staples) input(id="show_staples_cb", type="checkbox", checked=*show_staples.get(), on:change=move|_| {
let value = !*show_staples.get_untracked();
sh.dispatch(cx, Message::UpdateUseStaples(value));
})
(make_shopping_table(cx, sh, show_staples)) (make_shopping_table(cx, sh, show_staples))
span(role="button", class="no-print", on:click=move |_| { span(role="button", class="no-print", on:click=move |_| {
info!("Registering add item request for inventory"); info!("Registering add item request for inventory");

View File

@ -23,7 +23,12 @@ pub fn UI<G: Html>(cx: Scope) -> View<G> {
api::HttpStore::provide_context(cx, "/api".to_owned()); api::HttpStore::provide_context(cx, "/api".to_owned());
let store = api::HttpStore::get_from_context(cx).as_ref().clone(); let store = api::HttpStore::get_from_context(cx).as_ref().clone();
info!("Starting UI"); info!("Starting UI");
let app_state = crate::app_state::AppState::new(); let local_store = api::LocalStore::new();
let app_state = if let Some(app_state) = local_store.fetch_app_state() {
app_state
} else {
crate::app_state::AppState::new()
};
let sh = crate::app_state::get_state_handler(cx, app_state, store); let sh = crate::app_state::get_state_handler(cx, app_state, store);
let view = create_signal(cx, View::empty()); let view = create_signal(cx, View::empty());
spawn_local_scoped(cx, { spawn_local_scoped(cx, {