Category is assigned and shown in shopping list

relates to issue #6
This commit is contained in:
Jeremy Wall 2022-04-28 21:43:30 -04:00
parent b37995edb5
commit 5df20b1d23
6 changed files with 77 additions and 15 deletions

View File

@ -135,6 +135,7 @@ impl IngredientAccumulator {
self.inner self.inner
} }
} }
/// A Recipe step. It has the time for the step if there is one, instructions, and an ingredients /// A Recipe step. It has the time for the step if there is one, instructions, and an ingredients
/// list. /// list.
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)] #[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq)]

View File

@ -111,7 +111,7 @@ make_fn!(
_ => either!( _ => either!(
discard!(text_token!("|")), discard!(text_token!("|")),
discard!(eoi), discard!(eoi),
discard!(text_token!("\n")) discard!(peek!(text_token!("\n")))
), ),
(ingredient.trim().to_owned()) (ingredient.trim().to_owned())
) )

View File

@ -507,7 +507,7 @@ step: ";
} }
#[test] #[test]
fn test_category_line_happy_path() { fn test_category_single_line_happy_path() {
let line = "Produce: onion|green pepper|bell pepper|corn|potato|green onion|scallions|lettuce"; let line = "Produce: onion|green pepper|bell pepper|corn|potato|green onion|scallions|lettuce";
match parse::as_categories(line) { match parse::as_categories(line) {
Ok(map) => { Ok(map) => {
@ -525,13 +525,58 @@ fn test_category_line_happy_path() {
} }
} }
#[test]
fn test_category_double_line_happy_path() {
let line = "Produce: onion|green pepper|bell pepper|corn|potato|green onion|scallions|lettuce\nDairy: milk|butter";
match parse::as_categories(line) {
Ok(map) => {
assert_eq!(map.len(), 10);
assert!(
map.contains_key("onion"),
"map does not contain onion {:?}",
map
);
assert!(
map.contains_key("milk"),
"map does not contain milk {:?}",
map
);
assert_eq!(map["milk"], "Dairy");
println!("{:?}", map);
}
Err(e) => {
assert!(false, "{:?}", e);
}
}
}
#[test]
fn test_triple_line() {
let line = "Produce: onion|green pepper|bell pepper|corn|potato|green onion|scallions|lettuce
Meat: ground beef|beef|pork|chicken|sausage|hot dogs|bacon|lamb
Dairy: milk|butter|heavy cream|cheddar cheese|mozarella|cheddar|white american|american|swiss";
match parse::as_categories(line) {
Ok(map) => {
let mut categories = BTreeSet::new();
categories.extend(map.values());
println!("map: {:?}", map);
assert_eq!(categories.len(), 3);
}
Err(e) => {
assert!(false, "{:?}", e);
}
}
}
#[test] #[test]
fn test_category_single_ingredient_happy_paths() { fn test_category_single_ingredient_happy_paths() {
let ingredients = vec!["foo", "foo\n", "foo|"]; let ingredients = vec!["foo", "foo\n", "foo|", "foo\nCategory: "];
for ingredient in ingredients { for ingredient in ingredients {
match parse::cat_ingredient(StrIter::new(ingredient)) { match parse::cat_ingredient(StrIter::new(ingredient)) {
ParseResult::Complete(_itr, _i) => { ParseResult::Complete(_itr, _i) => {
// yay we pass // yay we pass
assert_eq!(_i, "foo");
} }
res => { res => {
assert!(false, "{:?}", res); assert!(false, "{:?}", res);

2
run.sh
View File

@ -16,6 +16,8 @@ make clean kitchen
pushd web pushd web
trunk serve \ trunk serve \
--public-url /ui \ --public-url /ui \
--watch . \
--watch ../recipes \
--proxy-backend http://localhost:3030/api/v1 & --proxy-backend http://localhost:3030/api/v1 &
trunkpid=$! trunkpid=$!
popd popd

View File

@ -54,8 +54,9 @@ pub fn shopping_list() -> View<G> {
let amt = modified_amt_set.entry(k.clone()).or_insert(Signal::new(format!("{}", i.amt.normalize()))).clone(); let amt = modified_amt_set.entry(k.clone()).or_insert(Signal::new(format!("{}", i.amt.normalize()))).clone();
modified_amts.set(modified_amt_set); modified_amts.set(modified_amt_set);
let name = i.name; let name = i.name;
let category = if i.category == "" { "other".to_owned() } else { i.category };
let form = i.form.map(|form| format!("({})", form)).unwrap_or_default(); let form = i.form.map(|form| format!("({})", form)).unwrap_or_default();
let names = rs.iter().fold(String::new(), |acc, s| format!("{}{},", acc, s)).trim_end_matches(",").to_owned(); let recipes = rs.iter().fold(String::new(), |acc, s| format!("{}{},", acc, s)).trim_end_matches(",").to_owned();
view! { view! {
tr { tr {
td { td {
@ -68,8 +69,8 @@ pub fn shopping_list() -> View<G> {
filtered_keys.set(keyset); filtered_keys.set(keyset);
})) }))
} }
td { (name) " " (form) } td { (name) " " (form) "" br {} "" (category) "" }
td { (names) } td { (recipes) }
} }
} }
}), }),
@ -82,7 +83,6 @@ pub fn shopping_list() -> View<G> {
} }
}), }),
); );
// TODO(jwall): Sort by categories and names.
view! { view! {
h1 { "Shopping List " } h1 { "Shopping List " }
(table_view.get().as_ref().clone()) (table_view.get().as_ref().clone())

View File

@ -85,6 +85,7 @@ impl AppService {
console_log!("Synchronizing categories"); console_log!("Synchronizing categories");
match Self::fetch_categories_http().await { match Self::fetch_categories_http().await {
Ok(Some(categories_content)) => { Ok(Some(categories_content)) => {
console_debug!("categories: {}", categories_content);
storage storage
.set_item("categories", &categories_content) .set_item("categories", &categories_content)
.map_err(|e| format!("{:?}", e))?; .map_err(|e| format!("{:?}", e))?;
@ -105,13 +106,16 @@ impl AppService {
.get_item("categories") .get_item("categories")
.map_err(|e| format!("{:?}", e))? .map_err(|e| format!("{:?}", e))?
{ {
Some(s) => match parse::as_categories(&s) { Some(s) => {
let parsed = serde_json::from_str::<String>(&s).map_err(|e| format!("{}", e))?;
match parse::as_categories(&parsed) {
Ok(categories) => Ok(Some(categories)), Ok(categories) => Ok(Some(categories)),
Err(e) => { Err(e) => {
console_debug!("Error parsing categories {}", e); console_debug!("Error parsing categories {}", e);
Err(format!("Error parsing categories {}", e)) Err(format!("Error parsing categories {}", e))
} }
}, }
}
None => Ok(None), None => Ok(None),
} }
} }
@ -136,7 +140,7 @@ impl AppService {
continue; continue;
} }
}; };
console_debug!("We parsed a recipe {}", recipe.title); //console_debug!("We parsed a recipe {}", recipe.title);
if recipe.title == "Staples" { if recipe.title == "Staples" {
staples = Some(recipe); staples = Some(recipe);
} else { } else {
@ -186,7 +190,17 @@ impl AppService {
if let Some(staples) = self.staples.get().as_ref() { if let Some(staples) = self.staples.get().as_ref() {
acc.accumulate_from(staples); acc.accumulate_from(staples);
} }
acc.ingredients() let mut ingredients = acc.ingredients();
self.category_map.get().as_ref().as_ref().map(|cm| {
for (_, (i, _)) in ingredients.iter_mut() {
if let Some(cat) = cm.get(&i.name) {
i.category = cat.clone();
}
}
});
console_debug!("{:?}", self.category_map);
// TODO(jwall): Sort by categories and names.
ingredients
} }
pub fn set_recipe_count_by_index(&mut self, i: usize, count: usize) { pub fn set_recipe_count_by_index(&mut self, i: usize, count: usize) {