From b7e4ebc15a2c90b66e9cf5052fa6bebd01c5a8ea Mon Sep 17 00:00:00 2001 From: Josh Rogers Date: Thu, 14 May 2026 21:38:53 -0500 Subject: [PATCH] Add permanent list delete; move stores out of main nav - Add DELETE /api/lists/{id}/permanent endpoint for hard-delete alongside existing soft-delete (archive) - Add Delete button with confirmation on list detail page next to Archive - Handle ListDeleted SignalR event on lists overview for real-time removal - Remove Stores from bottom nav; add Manage stores link at bottom of Lists page - Add back-to-lists navigation on the Stores page Co-Authored-By: Claude Sonnet 4.6 (1M context) --- .../ShoppingLists/ShoppingListEndpoints.cs | 14 ++++++++++ src/frontend/src/routes/+layout.svelte | 1 - src/frontend/src/routes/lists/+page.svelte | 11 ++++++++ .../src/routes/lists/[id]/+page.svelte | 26 ++++++++++++++----- src/frontend/src/routes/stores/+page.svelte | 5 +++- 5 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/backend/YesChef.Api/Features/ShoppingLists/ShoppingListEndpoints.cs b/src/backend/YesChef.Api/Features/ShoppingLists/ShoppingListEndpoints.cs index 242e2d9..1d62cf5 100644 --- a/src/backend/YesChef.Api/Features/ShoppingLists/ShoppingListEndpoints.cs +++ b/src/backend/YesChef.Api/Features/ShoppingLists/ShoppingListEndpoints.cs @@ -185,6 +185,20 @@ public static class ShoppingListEndpoints return Results.NoContent(); }); + group.MapDelete("/{id:int}/permanent", async (int id, YesChefDb db, HttpContext http, IHubContext hub) => + { + var familyId = http.User.GetFamilyId(); + var list = await db.ShoppingLists.FirstOrDefaultAsync(l => l.Id == id && l.FamilyId == familyId); + if (list is null) return Results.NotFound(); + + db.ShoppingLists.Remove(list); + await db.SaveChangesAsync(); + + await hub.Clients.Group(OverviewGroup(familyId)).SendAsync("ListDeleted", new { list.Id }); + + return Results.NoContent(); + }); + group.MapPost("/{listId:int}/items", async (int listId, AddItemRequest request, YesChefDb db, HttpContext http, IHubContext hub) => { var familyId = http.User.GetFamilyId(); diff --git a/src/frontend/src/routes/+layout.svelte b/src/frontend/src/routes/+layout.svelte index 03d7235..da44bb6 100644 --- a/src/frontend/src/routes/+layout.svelte +++ b/src/frontend/src/routes/+layout.svelte @@ -17,7 +17,6 @@ const navItems = [ { href: '/lists', label: 'Lists', icon: '📋' }, { href: '/recipes', label: 'Recipes', icon: '📖' }, - { href: '/stores', label: 'Stores', icon: '🏪' }, { href: '/family', label: 'Family', icon: '👪' } ]; diff --git a/src/frontend/src/routes/lists/+page.svelte b/src/frontend/src/routes/lists/+page.svelte index b4e3dab..a7039c3 100644 --- a/src/frontend/src/routes/lists/+page.svelte +++ b/src/frontend/src/routes/lists/+page.svelte @@ -46,6 +46,10 @@ lists = lists.filter((l) => l.id !== data.id); }); + connection.on('ListDeleted', (data: { id: number }) => { + lists = lists.filter((l) => l.id !== data.id); + }); + connection.on('ListSummaryUpdated', (data: ListSummary) => { lists = lists.map((l) => l.id === data.id ? { ...l, itemCount: data.itemCount, checkedCount: data.checkedCount, updatedAt: data.updatedAt } : l @@ -148,4 +152,11 @@ {/each} {/if} + + diff --git a/src/frontend/src/routes/lists/[id]/+page.svelte b/src/frontend/src/routes/lists/[id]/+page.svelte index 1088846..719e330 100644 --- a/src/frontend/src/routes/lists/[id]/+page.svelte +++ b/src/frontend/src/routes/lists/[id]/+page.svelte @@ -253,6 +253,12 @@ await api(`/api/lists/${listId}`, { method: 'DELETE' }); goto('/lists'); } + + async function deleteList() { + if (!confirm(`Permanently delete "${list!.name}"? This cannot be undone.`)) return; + await api(`/api/lists/${listId}/permanent`, { method: 'DELETE' }); + goto('/lists'); + } {#if loading} @@ -265,12 +271,20 @@

{list.name}

{list.store.name}

- +
+ + +
{ e.preventDefault(); addItem(); }} class="mb-4 space-y-2"> diff --git a/src/frontend/src/routes/stores/+page.svelte b/src/frontend/src/routes/stores/+page.svelte index 1fdc510..33ef59e 100644 --- a/src/frontend/src/routes/stores/+page.svelte +++ b/src/frontend/src/routes/stores/+page.svelte @@ -152,7 +152,10 @@
-

Stores

+
+ ← Back to lists +

Stores

+
{ e.preventDefault(); addStore(); }} class="mb-6 flex gap-2">