diff --git a/frontend-spec.md b/frontend-spec.md index 91aaa40..ce641f1 100644 --- a/frontend-spec.md +++ b/frontend-spec.md @@ -303,3 +303,11 @@ Google OAuth is planned next. - Remove now-unused legacy stubs from SDK/composable in a cleanup pass (non-functional, safe to delete). - Remove the legacy username login shim (`login(username: string)`) and any fallback UI; standardize on email/password (and Google) only. - Rollout flag: default `VUE_APP_MULTITENANT_ENABLED` to true across environments and plan removal of legacy flat routes and related tests once stable. + +--- + +## Ingredients & Sides UX (Updated Nov 2, 2025) + +- Controlled inputs: The parent meal edit page owns the latest extra ingredient line text immediately as the user types. Preview parsing still occurs on blur/Enter. +- Partial parse on Save: Only lines edited since the last parse are sent to `GET /ingredients/parse?lines=...`. Existing parsed lines are not re-parsed. Empty rows are dropped and a final guard filters zero-quantity items. +- Outcome: You can click Save mid-typing without losing changes or hitting validation errors, and we avoid unnecessary parsing work. diff --git a/src/components/ingredients/EditableIngredientsPanel.vue b/src/components/ingredients/EditableIngredientsPanel.vue index 1af3050..31aeaa5 100644 --- a/src/components/ingredients/EditableIngredientsPanel.vue +++ b/src/components/ingredients/EditableIngredientsPanel.vue @@ -38,6 +38,7 @@

@@ -73,11 +74,13 @@ const emit = defineEmits<{ (e: 'on-add'): void (e: 'on-delete', ingredient: Ingredient): void (e: 'on-update-ingredient', ingredient: Ingredient, newIngredient: Ingredient): void + (e: 'on-update-line', ingredient: Ingredient, newLine: string): void (e: 'on-editing', isEditing: boolean): void }>() const editing = ref(props.editOnly ?? false) + async function updateProduct(): Promise { // parseProduct is not available in v2 API; ignore for now } @@ -92,6 +95,7 @@ function toggleEditing() { editing.value = !editing.value emit('on-editing', editing.value) } +