feat: Allow restoring deleted inventory items

This commit is contained in:
Jeremy Wall 2024-09-27 19:42:35 -04:00
parent c77fa24515
commit 4ed0b6f8fb
2 changed files with 128 additions and 0 deletions

View File

@ -86,6 +86,7 @@ pub enum Message {
UpdateCategory(String, String, Option<Box<dyn FnOnce()>>), UpdateCategory(String, String, Option<Box<dyn FnOnce()>>),
ResetInventory, ResetInventory,
AddFilteredIngredient(IngredientKey), AddFilteredIngredient(IngredientKey),
RemoveFilteredIngredient(IngredientKey),
UpdateAmt(IngredientKey, String), UpdateAmt(IngredientKey, String),
SetUserData(UserData), SetUserData(UserData),
SaveState(Option<Box<dyn FnOnce()>>), SaveState(Option<Box<dyn FnOnce()>>),
@ -124,6 +125,9 @@ impl Debug for Message {
Self::AddFilteredIngredient(arg0) => { Self::AddFilteredIngredient(arg0) => {
f.debug_tuple("AddFilteredIngredient").field(arg0).finish() f.debug_tuple("AddFilteredIngredient").field(arg0).finish()
} }
Self::RemoveFilteredIngredient(arg0) => {
f.debug_tuple("RemoveFilteredIngredient").field(arg0).finish()
}
Self::UpdateAmt(arg0, arg1) => { Self::UpdateAmt(arg0, arg1) => {
f.debug_tuple("UpdateAmt").field(arg0).field(arg1).finish() f.debug_tuple("UpdateAmt").field(arg0).field(arg1).finish()
} }
@ -393,6 +397,9 @@ impl MessageMapper<Message, AppState> for StateMachine {
Message::AddFilteredIngredient(key) => { Message::AddFilteredIngredient(key) => {
original_copy.filtered_ingredients.insert(key); original_copy.filtered_ingredients.insert(key);
} }
Message::RemoveFilteredIngredient(key) => {
original_copy.filtered_ingredients.remove(&key);
}
Message::UpdateAmt(key, amt) => { Message::UpdateAmt(key, amt) => {
original_copy.modified_amts.insert(key, amt); original_copy.modified_amts.insert(key, amt);
} }

View File

@ -19,6 +19,115 @@ use tracing::{debug, info, instrument};
use crate::app_state::{Message, StateHandler}; use crate::app_state::{Message, StateHandler};
#[instrument(skip_all)]
fn make_deleted_ingredients_rows<'ctx, G: Html>(
cx: Scope<'ctx>,
sh: StateHandler<'ctx>,
show_staples: &'ctx ReadSignal<bool>,
) -> View<G> {
debug!("Making ingredients rows");
let ingredients = sh.get_selector(cx, move |state| {
let state = state.get();
let category_map = &state.category_map;
debug!("building ingredient list from state");
let mut acc = IngredientAccumulator::new();
for (id, count) in state.recipe_counts.iter() {
for _ in 0..(*count) {
acc.accumulate_from(
state
.recipes
.get(id)
.expect(&format!("No such recipe id exists: {}", id)),
);
}
}
if *show_staples.get() {
if let Some(staples) = &state.staples {
acc.accumulate_ingredients_for("Staples", staples.iter());
}
}
let mut ingredients = acc
.ingredients()
.into_iter()
// First we filter out any filtered ingredients
.filter(|(i, _)| state.filtered_ingredients.contains(i))
// Then we take into account our modified amts
.map(|(k, (i, rs))| {
let category = category_map
.get(&i.name)
.cloned()
.unwrap_or_else(|| String::new());
if state.modified_amts.contains_key(&k) {
(
k.clone(),
(
i.name,
i.form,
category,
state.modified_amts.get(&k).unwrap().clone(),
rs,
),
)
} else {
(
k.clone(),
(
i.name,
i.form,
category,
format!("{}", i.amt.normalize()),
rs,
),
)
}
})
.collect::<Vec<(
IngredientKey,
(String, Option<String>, String, String, BTreeSet<String>),
)>>();
ingredients.sort_by(|tpl1, tpl2| (&tpl1.1 .2, &tpl1.1 .0).cmp(&(&tpl2.1 .2, &tpl2.1 .0)));
ingredients
});
view!(
cx,
Indexed(
iterable = ingredients,
view = move |cx, (k, (name, form, category, amt, rs))| {
let category = if category == "" {
"other".to_owned()
} else {
category
};
let amt_signal = create_signal(cx, amt);
let k_clone = k.clone();
let form = form.map(|form| format!("({})", form)).unwrap_or_default();
let recipes = rs
.iter()
.fold(String::new(), |acc, s| format!("{}{},", acc, s))
.trim_end_matches(",")
.to_owned();
view! {cx,
tr {
td {
input(bind:value=amt_signal, class="width-5", type="text", on:change=move |_| {
sh.dispatch(cx, Message::UpdateAmt(k_clone.clone(), amt_signal.get_untracked().as_ref().clone()));
})
}
td {
input(type="button", class="fit-content no-print", value="Undo", on:click={
move |_| {
sh.dispatch(cx, Message::RemoveFilteredIngredient(k.clone()));
}})
}
td { (name) " " (form) "" br {} "" (category) "" }
td { (recipes) }
}
}
}
)
)
}
#[instrument(skip_all)] #[instrument(skip_all)]
fn make_ingredients_rows<'ctx, G: Html>( fn make_ingredients_rows<'ctx, G: Html>(
cx: Scope<'ctx>, cx: Scope<'ctx>,
@ -188,6 +297,18 @@ fn make_shopping_table<'ctx, G: Html>(
(make_extras_rows(cx, sh)) (make_extras_rows(cx, sh))
} }
} }
("Deleted Items")
table(class="pad-top shopping-list page-breaker container-fluid", role="grid") {
tr {
th { " Quantity " }
th { " Delete " }
th { " Ingredient " }
th { " Recipes " }
}
tbody {
(make_deleted_ingredients_rows(cx, sh, show_staples))
}
}
} }
} }