feat: admin Ingredients CRUD UI; fix "page not found" after deleting shopping list/recipe/collection (v0.85.0)

Admin > Ingredients lets admins add/edit/delete canonical ingredients and their aliases (e.g. "sel"/"sel fin"/"table salt") without touching code — previously only settable by hand in packages/db/src/seed.ts. Deleting just unlinks referencing pantry items/recipe ingredients (onDelete: set null), nothing else changes.

Fixed: deleting a shopping list, recipe, or collection from its own detail page used router.push to navigate away, leaving the deleted resource's URL in browser history — one back-button press landed on a real "Page not found" screen. All three now use router.replace so the dead URL never sits in history.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Arnaud
2026-07-24 18:42:42 +02:00
parent ebe3216c04
commit 4ae0bd580e
14 changed files with 389 additions and 8 deletions
+31
View File
@@ -0,0 +1,31 @@
import type { Metadata } from "next";
import { db, ingredients, asc } from "@epicure/db";
import { requireFullAdminPage } from "@/lib/require-admin-page";
import { IngredientsManager } from "@/components/admin/ingredients-manager";
export const metadata: Metadata = {};
export default async function AdminIngredientsPage() {
await requireFullAdminPage();
const rows = await db.select().from(ingredients).orderBy(asc(ingredients.name));
return (
<div className="space-y-6">
<div>
<h1 className="text-2xl font-bold tracking-tight">Ingredients</h1>
<p className="text-muted-foreground text-sm mt-1">
Canonical ingredients and their name variants (e.g. &quot;sel&quot;, &quot;sel fin&quot;, &quot;table salt&quot;) lets pantry items and recipe ingredients written differently still be recognized as the same thing. Used by pantry add/edit, can-cook scoring, auto-deduct on cook, and shopping-list pantry-awareness.
</p>
</div>
<IngredientsManager
initialIngredients={rows.map((r) => ({
id: r.id,
name: r.name,
aliases: r.aliases,
category: r.category,
}))}
/>
</div>
);
}
+2 -1
View File
@@ -1,5 +1,5 @@
import Link from "next/link";
import { Shield, Users, BookOpen, Settings, BarChart3, ClipboardList, HardDrive, Bot, ArrowLeft, Gauge, Mail, Flag, History, LifeBuoy, TrendingUp, Webhook, CreditCard } from "lucide-react";
import { Shield, Users, BookOpen, Settings, BarChart3, ClipboardList, HardDrive, Bot, ArrowLeft, Gauge, Mail, Flag, History, LifeBuoy, TrendingUp, Webhook, CreditCard, Tag } from "lucide-react";
import { cn } from "@/lib/utils";
import { getStaffRole } from "@/lib/require-admin-page";
import { redirect } from "next/navigation";
@@ -16,6 +16,7 @@ const adminNav = [
{ href: "/admin/reports", label: "Reports", icon: Flag, adminOnly: false },
{ href: "/admin/support", label: "Support", icon: LifeBuoy, adminOnly: true },
{ href: "/admin/tiers", label: "Tier Limits", icon: Gauge, adminOnly: true },
{ href: "/admin/ingredients", label: "Ingredients", icon: Tag, adminOnly: true },
{ href: "/admin/billing", label: "Billing", icon: CreditCard, adminOnly: true },
{ href: "/admin/webhooks", label: "Webhooks", icon: Webhook, adminOnly: true },
{ href: "/admin/audit-logs", label: "Audit Logs", icon: ClipboardList, adminOnly: true },