Distinguish picked-up from removed shopping list items

Soft-remove items via RemovedAt/RemovedByUserId instead of hard
deleting so the row survives for undo and future history reporting.
DELETE now sets the removal fields; a new POST .../restore clears
them. Active list reads (summary, detail, check toggle) filter to
RemovedAt IS NULL. Frontend surfaces an Undo toast on remove and
handles a new ItemRestored SignalR event.
This commit is contained in:
Josh Rogers
2026-05-08 20:07:41 -05:00
parent 9b2db931ee
commit 7fcae09afb
8 changed files with 682 additions and 15 deletions
@@ -1,4 +1,4 @@
// <auto-generated />
// <auto-generated />
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
@@ -223,6 +223,12 @@ namespace YesChef.Api.Migrations
b.Property<int?>("RecipeId")
.HasColumnType("integer");
b.Property<DateTime?>("RemovedAt")
.HasColumnType("timestamp with time zone");
b.Property<int?>("RemovedByUserId")
.HasColumnType("integer");
b.Property<int>("ShoppingListId")
.HasColumnType("integer");
@@ -237,6 +243,8 @@ namespace YesChef.Api.Migrations
b.HasIndex("RecipeId");
b.HasIndex("RemovedByUserId");
b.HasIndex("ShoppingListId");
b.ToTable("ShoppingListItems");
@@ -402,6 +410,11 @@ namespace YesChef.Api.Migrations
.HasForeignKey("RecipeId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("YesChef.Api.Entities.User", "RemovedByUser")
.WithMany()
.HasForeignKey("RemovedByUserId")
.OnDelete(DeleteBehavior.SetNull);
b.HasOne("YesChef.Api.Entities.ShoppingList", "ShoppingList")
.WithMany("Items")
.HasForeignKey("ShoppingListId")
@@ -414,6 +427,8 @@ namespace YesChef.Api.Migrations
b.Navigation("Recipe");
b.Navigation("RemovedByUser");
b.Navigation("ShoppingList");
});