mirror of
https://github.com/zaphar/kitchen.git
synced 2025-07-22 19:40:14 -04:00
Sort out recipe saving
This commit is contained in:
parent
b95b297deb
commit
2f6375e381
@ -67,7 +67,6 @@ pub enum Message {
|
|||||||
RemoveExtra(usize),
|
RemoveExtra(usize),
|
||||||
UpdateExtra(usize, String, String),
|
UpdateExtra(usize, String, String),
|
||||||
SaveRecipe(RecipeEntry, Option<Box<dyn FnOnce()>>),
|
SaveRecipe(RecipeEntry, Option<Box<dyn FnOnce()>>),
|
||||||
SetRecipe(String, Recipe),
|
|
||||||
RemoveRecipe(String, Option<Box<dyn FnOnce()>>),
|
RemoveRecipe(String, Option<Box<dyn FnOnce()>>),
|
||||||
UpdateCategory(String, String, Option<Box<dyn FnOnce()>>),
|
UpdateCategory(String, String, Option<Box<dyn FnOnce()>>),
|
||||||
ResetInventory,
|
ResetInventory,
|
||||||
@ -101,9 +100,6 @@ impl Debug for Message {
|
|||||||
.field(arg2)
|
.field(arg2)
|
||||||
.finish(),
|
.finish(),
|
||||||
Self::SaveRecipe(arg0, _) => f.debug_tuple("SaveRecipe").field(arg0).finish(),
|
Self::SaveRecipe(arg0, _) => f.debug_tuple("SaveRecipe").field(arg0).finish(),
|
||||||
Self::SetRecipe(arg0, arg1) => {
|
|
||||||
f.debug_tuple("SetRecipe").field(arg0).field(arg1).finish()
|
|
||||||
}
|
|
||||||
Self::RemoveRecipe(arg0, _) => f.debug_tuple("SetCategoryMap").field(arg0).finish(),
|
Self::RemoveRecipe(arg0, _) => f.debug_tuple("SetCategoryMap").field(arg0).finish(),
|
||||||
Self::UpdateCategory(i, c, _) => {
|
Self::UpdateCategory(i, c, _) => {
|
||||||
f.debug_tuple("UpdateCategory").field(i).field(c).finish()
|
f.debug_tuple("UpdateCategory").field(i).field(c).finish()
|
||||||
@ -197,7 +193,7 @@ impl StateMachine {
|
|||||||
entry
|
entry
|
||||||
.category()
|
.category()
|
||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_else(|| "Unknown".to_owned()),
|
.unwrap_or_else(|| "Entree".to_owned()),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
.collect::<BTreeMap<String, String>>();
|
.collect::<BTreeMap<String, String>>();
|
||||||
@ -357,22 +353,29 @@ impl MessageMapper<Message, AppState> for StateMachine {
|
|||||||
&original_copy.extras,
|
&original_copy.extras,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Message::SetRecipe(id, recipe) => {
|
|
||||||
original_copy.recipes.insert(id, recipe);
|
|
||||||
}
|
|
||||||
Message::SaveRecipe(entry, callback) => {
|
Message::SaveRecipe(entry, callback) => {
|
||||||
let recipe =
|
let recipe =
|
||||||
parse::as_recipe(entry.recipe_text()).expect("Failed to parse RecipeEntry");
|
parse::as_recipe(entry.recipe_text()).expect("Failed to parse RecipeEntry");
|
||||||
original_copy
|
original_copy
|
||||||
.recipes
|
.recipes
|
||||||
.insert(entry.recipe_id().to_owned(), recipe);
|
.insert(entry.recipe_id().to_owned(), recipe);
|
||||||
|
if !original_copy.recipe_counts.contains_key(entry.recipe_id()) {
|
||||||
original_copy
|
original_copy
|
||||||
.recipe_counts
|
.recipe_counts
|
||||||
.insert(entry.recipe_id().to_owned(), 0);
|
.insert(entry.recipe_id().to_owned(), 0);
|
||||||
|
}
|
||||||
|
if let Some(cat) = entry.category().cloned() {
|
||||||
|
original_copy
|
||||||
|
.recipe_categories
|
||||||
|
.entry(entry.recipe_id().to_owned())
|
||||||
|
.and_modify(|c| *c = cat.clone())
|
||||||
|
.or_insert(cat);
|
||||||
|
}
|
||||||
let store = self.store.clone();
|
let store = self.store.clone();
|
||||||
self.local_store.set_recipe_entry(&entry);
|
self.local_store.set_recipe_entry(&entry);
|
||||||
spawn_local_scoped(cx, async move {
|
spawn_local_scoped(cx, async move {
|
||||||
if let Err(e) = store.store_recipes(vec![entry]).await {
|
if let Err(e) = store.store_recipes(vec![entry]).await {
|
||||||
|
// FIXME(jwall): We should have a global way to trigger error messages
|
||||||
error!(err=?e, "Unable to save Recipe");
|
error!(err=?e, "Unable to save Recipe");
|
||||||
}
|
}
|
||||||
callback.map(|f| f());
|
callback.map(|f| f());
|
||||||
|
@ -72,7 +72,14 @@ pub fn Editor<'ctx, G: Html>(cx: Scope<'ctx>, props: RecipeComponentProps<'ctx>)
|
|||||||
let id = create_memo(cx, || recipe.get().recipe_id().to_owned());
|
let id = create_memo(cx, || recipe.get().recipe_id().to_owned());
|
||||||
let dirty = create_signal(cx, false);
|
let dirty = create_signal(cx, false);
|
||||||
let ts = create_signal(cx, js_lib::get_ms_timestamp());
|
let ts = create_signal(cx, js_lib::get_ms_timestamp());
|
||||||
let category = create_signal(cx, recipe.get().category().cloned().unwrap_or_default());
|
let category = create_signal(
|
||||||
|
cx,
|
||||||
|
recipe
|
||||||
|
.get()
|
||||||
|
.category()
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| "Entree".to_owned()),
|
||||||
|
);
|
||||||
|
|
||||||
debug!("creating editor view");
|
debug!("creating editor view");
|
||||||
view! {cx,
|
view! {cx,
|
||||||
@ -103,40 +110,21 @@ pub fn Editor<'ctx, G: Html>(cx: Scope<'ctx>, props: RecipeComponentProps<'ctx>)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
debug!("Recipe text is changed");
|
debug!("Recipe text is changed");
|
||||||
spawn_local_scoped(cx, {
|
|
||||||
let store = crate::api::HttpStore::get_from_context(cx);
|
|
||||||
let category = category.get_untracked();
|
let category = category.get_untracked();
|
||||||
let category = if category.is_empty() {
|
let category = if category.is_empty() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some(category.as_ref().clone())
|
Some(category.as_ref().clone())
|
||||||
};
|
};
|
||||||
async move {
|
let recipe_entry = RecipeEntry(
|
||||||
debug!("Attempting to save recipe");
|
|
||||||
if let Err(e) = store
|
|
||||||
.store_recipes(vec![RecipeEntry(
|
|
||||||
id.get_untracked().as_ref().clone(),
|
id.get_untracked().as_ref().clone(),
|
||||||
text.get_untracked().as_ref().clone(),
|
text.get_untracked().as_ref().clone(),
|
||||||
category,
|
category,
|
||||||
)])
|
|
||||||
.await
|
|
||||||
{
|
|
||||||
error!(?e, "Failed to save recipe");
|
|
||||||
error_text.set(format!("{:?}", e));
|
|
||||||
} else {
|
|
||||||
// We also need to set recipe in our state
|
|
||||||
dirty.set(false);
|
|
||||||
if let Ok(recipe) = recipes::parse::as_recipe(text.get_untracked().as_ref()) {
|
|
||||||
sh.dispatch(
|
|
||||||
cx,
|
|
||||||
Message::SetRecipe(id.get_untracked().as_ref().to_owned(), recipe),
|
|
||||||
);
|
);
|
||||||
|
sh.dispatch(cx, Message::SaveRecipe(recipe_entry, None));
|
||||||
|
dirty.set(false);
|
||||||
}
|
}
|
||||||
};
|
// TODO(jwall): Show error message if trying to save when recipe doesn't parse.
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}) { "Save" } " "
|
}) { "Save" } " "
|
||||||
span(role="button", on:click=move |_| {
|
span(role="button", on:click=move |_| {
|
||||||
sh.dispatch(cx, Message::RemoveRecipe(id.get_untracked().as_ref().to_owned(), Some(Box::new(|| sycamore_router::navigate("/ui/planning/plan")))));
|
sh.dispatch(cx, Message::RemoveRecipe(id.get_untracked().as_ref().to_owned(), Some(Box::new(|| sycamore_router::navigate("/ui/planning/plan")))));
|
||||||
|
@ -14,7 +14,6 @@ use std::collections::BTreeMap;
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use recipes::Recipe;
|
use recipes::Recipe;
|
||||||
use reqwasm::websocket::State;
|
|
||||||
use sycamore::prelude::*;
|
use sycamore::prelude::*;
|
||||||
use tracing::{debug, instrument};
|
use tracing::{debug, instrument};
|
||||||
|
|
||||||
@ -39,7 +38,7 @@ pub fn CategoryGroup<'ctx, G: Html>(
|
|||||||
row_size,
|
row_size,
|
||||||
}: CategoryGroupProps<'ctx>,
|
}: CategoryGroupProps<'ctx>,
|
||||||
) -> View<G> {
|
) -> View<G> {
|
||||||
let rows = sh.get_selector(cx, move |state| {
|
let rows = create_signal(cx, {
|
||||||
let mut rows = Vec::new();
|
let mut rows = Vec::new();
|
||||||
for row in recipes
|
for row in recipes
|
||||||
.iter()
|
.iter()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user