From 6722589b515ccee267212cf783fc0ebbaa20cd90 Mon Sep 17 00:00:00 2001 From: Martin Kagamino Lehoux Date: Mon, 27 Jul 2026 17:18:40 +0200 Subject: feat: catalog section + deduplicate items by name - Show all items split into List (unchecked) and Catalog (checked) sections - Tapping a catalog item unchecks it (returns to list) - Add action now upserts: unchecks existing item instead of creating duplicate - UNIQUE constraint on groceries.name as defense-in-depth - Tests for dedup behavior (insert, re-add from catalog, no-op on list) --- src/routes/+page.server.ts | 22 +++++++++++++++++----- src/routes/+page.svelte | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 51 insertions(+), 6 deletions(-) (limited to 'src/routes') diff --git a/src/routes/+page.server.ts b/src/routes/+page.server.ts index e6f3b0f..947cc3b 100644 --- a/src/routes/+page.server.ts +++ b/src/routes/+page.server.ts @@ -8,7 +8,6 @@ export const load: PageServerLoad = async () => { const items = await db .select() .from(groceries) - .where(eq(groceries.checked, false)) .orderBy(desc(groceries.createdAt)); return { items }; @@ -23,10 +22,23 @@ export const actions: Actions = { return fail(400, { error: 'Name is required' }); } - await db.insert(groceries).values({ - name, - createdAt: new Date().toISOString(), - }); + const [existing] = await db + .select() + .from(groceries) + .where(eq(groceries.name, name)) + .limit(1); + + if (existing) { + await db + .update(groceries) + .set({ checked: false }) + .where(eq(groceries.id, existing.id)); + } else { + await db.insert(groceries).values({ + name, + createdAt: new Date().toISOString(), + }); + } return { success: true }; }, diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 0e9e1ac..325d15a 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -4,6 +4,9 @@ let { data, form } = $props(); let name = $state(''); + + let listItems = $derived(data?.items?.filter((i) => !i.checked) ?? []); + let catalogItems = $derived(data?.items?.filter((i) => i.checked) ?? []);

Groceries

@@ -23,11 +26,31 @@

{form.error}

{/if} +

List

+ +
+ +
+ +{#if listItems.length === 0} +

Nothing to buy

+{/if} +
+

Catalog

+
+{#if catalogItems.length === 0} +

No items yet

+{/if} + -- cgit v1.3