"use client"; import { useState } from "react"; import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import { Plus, Trash2, AlertTriangle } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { PantryScanDialog } from "@/components/pantry/pantry-scan-dialog"; import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, } from "@/components/ui/alert-dialog"; type PantryItem = { id: string; rawName: string; quantity: string | null; unit: string | null; expiresAt: string | null; }; function daysUntilExpiry(dateStr: string): number { const diff = new Date(dateStr).getTime() - Date.now(); return Math.ceil(diff / (1000 * 60 * 60 * 24)); } export function PantryManager({ initialItems }: { initialItems: PantryItem[] }) { const t = useTranslations("pantry"); const tCommon = useTranslations("common"); const router = useRouter(); const [items, setItems] = useState(initialItems); const [name, setName] = useState(""); const [quantity, setQuantity] = useState(""); const [unit, setUnit] = useState(""); const [expiresAt, setExpiresAt] = useState(""); const [adding, setAdding] = useState(false); const [confirmId, setConfirmId] = useState(null); async function add() { if (!name.trim()) return; setAdding(true); try { const res = await fetch("/api/v1/pantry", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ rawName: name.trim(), quantity: quantity.trim() || undefined, unit: unit.trim() || undefined, expiresAt: expiresAt ? new Date(expiresAt).toISOString() : undefined, }), }); if (!res.ok) { toast.error(t("addFailed")); return; } const { id } = await res.json() as { id: string }; setItems((prev) => [...prev, { id, rawName: name.trim(), quantity: quantity || null, unit: unit || null, expiresAt: expiresAt ? new Date(expiresAt).toISOString() : null }]); setName(""); setQuantity(""); setUnit(""); setExpiresAt(""); } finally { setAdding(false); } } async function remove(id: string) { const res = await fetch(`/api/v1/pantry/${id}`, { method: "DELETE" }); if (res.ok) setItems((prev) => prev.filter((i) => i.id !== id)); else toast.error(t("removeFailed")); } const itemPendingDelete = items.find((i) => i.id === confirmId) ?? null; const sorted = [...items].sort((a, b) => { if (a.expiresAt && b.expiresAt) return new Date(a.expiresAt).getTime() - new Date(b.expiresAt).getTime(); if (a.expiresAt) return -1; if (b.expiresAt) return 1; return a.rawName.localeCompare(b.rawName); }); return (
{/* Add form */}
setName(e.target.value)} placeholder={t("itemNamePlaceholder")} className="flex-1 min-w-[160px]" onKeyDown={(e) => e.key === "Enter" && add()} /> setQuantity(e.target.value)} placeholder={t("qtyPlaceholder")} className="w-20" /> setUnit(e.target.value)} placeholder={t("unitPlaceholder")} className="w-20" /> setExpiresAt(e.target.value)} className="w-36" /> router.refresh()} />
{/* Item list */} {items.length === 0 ? (

{t("empty")}

) : (
{sorted.map((item) => { const days = item.expiresAt ? daysUntilExpiry(item.expiresAt) : null; const expiring = days !== null && days <= 3; const expired = days !== null && days < 0; return (
{item.rawName} {item.quantity && {item.quantity}{item.unit ? ` ${item.unit}` : ""}} {expired && {t("expired")}} {expiring && !expired && {t("expiresInDays", { days })}}
{item.expiresAt && !expired && !expiring && (

{t("expiresOn", { date: new Date(item.expiresAt).toLocaleDateString() })}

)}
); })}
)} !open && setConfirmId(null)}> {t("removeConfirmTitle")} {itemPendingDelete ? t("removeConfirmDescription", { name: itemPendingDelete.rawName }) : ""} {tCommon("cancel")} { if (confirmId) void remove(confirmId); setConfirmId(null); }} className="bg-destructive text-destructive-foreground hover:bg-destructive/90" > {tCommon("delete")}
); }