From 731e54101386c5fcd68422e02128ec9c94df276b Mon Sep 17 00:00:00 2001 From: Craig Date: Sun, 26 Jul 2026 17:45:11 +0100 Subject: [PATCH] =?UTF-8?q?TICKET-008=20(frontend):=20Foods=20library=20vi?= =?UTF-8?q?ew=20=E2=80=94=20search,=20pagination,=20edit,=20delete,=20rest?= =?UTF-8?q?ore?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/App.svelte | 7 + frontend/src/components/FoodEditor.svelte | 24 +- frontend/src/components/FoodLibrary.svelte | 340 ++++++++++++++++++++- frontend/src/lib/api.js | 4 + 4 files changed, 367 insertions(+), 8 deletions(-) diff --git a/frontend/src/App.svelte b/frontend/src/App.svelte index 8892ba6..03ece95 100644 --- a/frontend/src/App.svelte +++ b/frontend/src/App.svelte @@ -14,6 +14,7 @@ import Dashboard from './components/Dashboard.svelte' import FoodSearch from './components/FoodSearch.svelte' import FoodEditor from './components/FoodEditor.svelte' + import FoodLibrary from './components/FoodLibrary.svelte' import BarcodeScanner from './components/BarcodeScanner.svelte' // Health check β€” every async view handles loading/error states (spec Β§8.2 rule 4) @@ -233,6 +234,9 @@ + @@ -337,6 +341,9 @@ {:else if appView.current === 'createFood'} + {:else if appView.current === 'foods'} + + {:else if appView.current === 'editMeal'} diff --git a/frontend/src/components/FoodEditor.svelte b/frontend/src/components/FoodEditor.svelte index 6c5d885..b89db27 100644 --- a/frontend/src/components/FoodEditor.svelte +++ b/frontend/src/components/FoodEditor.svelte @@ -121,6 +121,9 @@ let saving = $state(false) let error = $state(null) + // Edit mode: an existing food (with id) was passed in β€” update, don't create. + let isEdit = $derived(!!food?.id) + // ── Pre-fill from food prop ───────────────────────────────────────────── $effect(() => { if (food) { @@ -176,12 +179,21 @@ serving_size_g: servingSizeG ? parseFloat(servingSizeG) : null, serving_name: servingName.trim() || null, source, - is_meal: false, + is_meal: food?.is_meal ?? false, } // Include barcode when present if (barcode.trim()) payload.barcode = barcode.trim() else payload.barcode = null + if (isEdit) { + const saved = await api.updateFood(food.id, payload) + // Nutrition edits affect historical log rendering β€” refresh the day + await refreshDayData() + if (onSaved) onSaved(saved) + else appView.current = 'dashboard' + return + } + const saved = await api.createFood(payload) // After save, offer to log the new food justSaved = { food: saved } @@ -224,10 +236,10 @@ function goBack() { reset() - if (mealId) { - appView.current = 'dashboard' - } else if (onCancel) { + if (onCancel) { onCancel() + } else if (mealId) { + appView.current = 'dashboard' } else if (onSaved) { // Came from scan flow with no cancel β€” go to dashboard appView.current = 'dashboard' @@ -355,7 +367,7 @@ {:else} -

{isPrefilled ? 'Confirm & edit food' : 'Create food'}

+

{isEdit ? 'Edit food' : isPrefilled ? 'Confirm & edit food' : 'Create food'}