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) <noreply@anthropic.com>
This commit is contained in:
@@ -185,6 +185,20 @@ public static class ShoppingListEndpoints
|
||||
return Results.NoContent();
|
||||
});
|
||||
|
||||
group.MapDelete("/{id:int}/permanent", async (int id, YesChefDb db, HttpContext http, IHubContext<ShoppingListHub> 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<ShoppingListHub> hub) =>
|
||||
{
|
||||
var familyId = http.User.GetFamilyId();
|
||||
|
||||
@@ -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: '👪' }
|
||||
];
|
||||
|
||||
|
||||
@@ -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}
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
<div class="mt-6 border-t border-gray-100 pt-4">
|
||||
<a href="/stores" class="flex items-center justify-between text-sm text-gray-500">
|
||||
<span>Manage stores</span>
|
||||
<span>›</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if loading}
|
||||
@@ -265,12 +271,20 @@
|
||||
<h2 class="text-2xl font-bold">{list.name}</h2>
|
||||
<p class="text-sm text-gray-500">{list.store.name}</p>
|
||||
</div>
|
||||
<button
|
||||
onclick={archiveList}
|
||||
class="rounded-lg border border-gray-300 px-3 py-1.5 text-sm text-gray-500"
|
||||
>
|
||||
Archive
|
||||
</button>
|
||||
<div class="flex gap-2">
|
||||
<button
|
||||
onclick={archiveList}
|
||||
class="rounded-lg border border-gray-300 px-3 py-1.5 text-sm text-gray-500"
|
||||
>
|
||||
Archive
|
||||
</button>
|
||||
<button
|
||||
onclick={deleteList}
|
||||
class="btn-danger-link text-sm"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form onsubmit={e => { e.preventDefault(); addItem(); }} class="mb-4 space-y-2">
|
||||
|
||||
@@ -152,7 +152,10 @@
|
||||
</script>
|
||||
|
||||
<div>
|
||||
<h2 class="mb-4 text-2xl font-bold">Stores</h2>
|
||||
<div class="mb-4">
|
||||
<a href="/lists" class="text-sm text-gray-500">← Back to lists</a>
|
||||
<h2 class="mt-1 text-2xl font-bold">Stores</h2>
|
||||
</div>
|
||||
|
||||
<form onsubmit={e => { e.preventDefault(); addStore(); }} class="mb-6 flex gap-2">
|
||||
<input
|
||||
|
||||
Reference in New Issue
Block a user