feat: show serving count in the UI in all the places

This commit is contained in:
Jeremy Wall 2024-07-25 15:50:19 -04:00
parent aba1e114cf
commit 8000b7d317
5 changed files with 36 additions and 7 deletions

View File

@ -101,6 +101,7 @@ impl RecipeEntry {
pub struct Recipe {
pub title: String,
pub desc: Option<String>,
pub serving_count: Option<i64>,
pub steps: Vec<Step>,
}
@ -110,6 +111,7 @@ impl Recipe {
title: title.into(),
desc: desc.map(|s| s.into()),
steps: Vec::new(),
serving_count: Default::default(),
}
}

View File

@ -151,13 +151,14 @@ pub fn parse_recipes(
Some(parsed) => {
let mut parsed_map = BTreeMap::new();
for r in parsed {
let recipe = match parse::as_recipe(&r.recipe_text()) {
let mut recipe = match parse::as_recipe(&r.recipe_text()) {
Ok(r) => r,
Err(e) => {
error!("Error parsing recipe {}", e);
continue;
}
};
recipe.serving_count = r.serving_count;
parsed_map.insert(r.recipe_id().to_owned(), recipe);
}
Ok(Some(parsed_map))

View File

@ -49,7 +49,15 @@ pub fn Editor<'ctx, G: Html>(cx: Scope<'ctx>, props: RecipeComponentProps<'ctx>)
let store = crate::api::HttpStore::get_from_context(cx);
let recipe: &Signal<RecipeEntry> =
create_signal(cx, RecipeEntry::new(&recipe_id, String::new()));
let text = create_signal(cx, String::new());
let text = create_signal(cx, String::from("0"));
let serving_count_str = create_signal(cx, String::new());
let serving_count = create_memo(cx, || {
if let Ok(count) = serving_count_str.get().parse::<i64>() {
count
} else {
0
}
});
let error_text = create_signal(cx, String::from("Parse results..."));
let aria_hint = create_signal(cx, "false");
let category = create_signal(cx, "Entree".to_owned());
@ -83,6 +91,10 @@ pub fn Editor<'ctx, G: Html>(cx: Scope<'ctx>, props: RecipeComponentProps<'ctx>)
label(for="recipe_category") { "Category" }
input(name="recipe_category", bind:value=category, on:change=move |_| dirty.set(true))
}
div {
label(for="serving_count") { "Serving Count" }
input(name="serving_count", bind:value=serving_count_str, on:change=move |_| dirty.set(true))
}
div {
div(class="row-flex") {
label(for="recipe_text", class="block align-stretch expand-height") { "Recipe: " }
@ -119,7 +131,7 @@ pub fn Editor<'ctx, G: Html>(cx: Scope<'ctx>, props: RecipeComponentProps<'ctx>)
id: id.get_untracked().as_ref().clone(),
text: text.get_untracked().as_ref().clone(),
category,
serving_count: None,
serving_count: Some(*serving_count.get()),
};
sh.dispatch(cx, Message::SaveRecipe(recipe_entry, None));
dirty.set(false);
@ -171,18 +183,22 @@ pub fn Viewer<'ctx, G: Html>(cx: Scope<'ctx>, props: RecipeComponentProps<'ctx>)
let recipe_signal = sh.get_selector(cx, move |state| {
if let Some(recipe) = state.get().recipes.get(&recipe_id) {
let title = recipe.title.clone();
let serving_count = recipe.serving_count.clone();
let desc = recipe.desc.clone().unwrap_or_else(|| String::new());
let steps = recipe.steps.clone();
Some((title, desc, steps))
Some((title, serving_count, desc, steps))
} else {
None
}
});
if let Some((title, desc, steps)) = recipe_signal.get().as_ref().clone() {
if let Some((title, serving_count, desc, steps)) = recipe_signal.get().as_ref().clone() {
debug!("Viewing recipe.");
view.set(view! {cx,
div(class="recipe") {
h1(class="recipe_title") { (title) }
div(class="serving_count") {
"Serving Count: " (serving_count.map(|v| format!("{}", v)).unwrap_or_else(|| "Unconfigured".to_owned()))
}
div(class="recipe_description") {
(desc)
}

View File

@ -60,8 +60,14 @@ pub fn CategoryGroup<'ctx, G: Html>(
iterable=r,
view=move |cx, sig| {
let title = create_memo(cx, move || sig.get().1.title.clone());
let serving_count = create_memo(cx, move || sig.get().1.serving_count.clone());
view! {cx,
div(class="cell column-flex justify-end align-stretch") { RecipeSelection(i=sig.get().0.to_owned(), title=title, sh=sh) }
div(class="cell column-flex justify-end align-stretch") {
RecipeSelection(
i=sig.get().0.to_owned(),
title=title, sh=sh,
serving_count=serving_count,
) }
}
},
key=|sig| sig.get().0.to_owned(),

View File

@ -23,6 +23,7 @@ use crate::components::NumberField;
pub struct RecipeCheckBoxProps<'ctx> {
pub i: String,
pub title: &'ctx ReadSignal<String>,
pub serving_count: &'ctx ReadSignal<Option<i64>>,
pub sh: StateHandler<'ctx>,
}
@ -35,7 +36,7 @@ pub fn RecipeSelection<'ctx, G: Html>(
cx: Scope<'ctx>,
props: RecipeCheckBoxProps<'ctx>,
) -> View<G> {
let RecipeCheckBoxProps { i, title, sh } = props;
let RecipeCheckBoxProps { i, title, sh, serving_count, } = props;
let id = Rc::new(i);
let id_for_count = id.clone();
// NOTE(jwall): The below get's a little tricky. We need a separate signal to bind for the
@ -66,6 +67,9 @@ pub fn RecipeSelection<'ctx, G: Html>(
let for_id = name.clone();
view! {cx,
label(for=for_id, class="flex-item-grow") { a(href=href) { (*title) } }
div {
"Serves: " (serving_count.get().map(|v| v.to_string()).unwrap_or("Unconfigured".to_owned()))
}
NumberField(name=name, class="flex-item-shrink".to_string(), counter=count, min=0.0, on_change=Some(move |_| {
debug!(idx=%id, count=%(*count.get_untracked()), "setting recipe count");
sh.dispatch(cx, Message::UpdateRecipeCount(id.as_ref().clone(), *count.get_untracked() as u32));