"use client"; import { useState } from "react"; import { AlertTriangle, ChevronDown, ChevronRight, UtensilsCrossed } from "lucide-react"; import { PantryItemDialog } from "./pantry-item-dialog"; import { UseItemDialog } from "./use-item-dialog"; export type PantryItem = { id: string; name: string; description: string | null; quantity: number; unit: string | null; packageSize: string | null; storedAt: Date | null; bestBefore: Date | null; source: string | null; locationId: string | null; locationName: string | null; plantId: string | null; plantName: string | null; pantryCategory: string | null; pantrySubcategory: string | null; pricePaid: number | null; priceUnit: string | null; notes: string | null; }; export type LocationOption = { id: string; name: string; path: string | null }; export type PlantOption = { id: string; commonName: string; variety: string | null }; const SOURCE_LABELS: Record = { GARDEN: "Our garden", HOMEMADE: "Homemade", STORE: "Store", FARMERS_MARKET: "Farmers market", GIFTED: "Gifted", OTHER: "Other", }; function daysUntil(date: Date) { return Math.ceil((new Date(date).getTime() - Date.now()) / 86_400_000); } function ExpiryBadge({ date }: { date: Date }) { const days = daysUntil(date); if (days < 0) return Expired; if (days <= 7) return Expires in {days}d; if (days <= 30) return Expires in {days}d; return {new Date(date).toLocaleDateString()}; } function ItemRow({ item, locations, plants, onRefresh }: { item: PantryItem; locations: LocationOption[]; plants: PlantOption[]; onRefresh: () => void; }) { const priceStr = item.pricePaid != null ? `$${item.pricePaid.toFixed(2)}${item.priceUnit && item.priceUnit !== "package" ? `/${item.priceUnit}` : ""}` : null; return (
{item.name} {item.description && {item.description}} {item.source && {SOURCE_LABELS[item.source] ?? item.source}} {item.plantName && ๐ŸŒฑ {item.plantName}}
{item.quantity} {item.unit ?? ""} {priceStr && {priceStr}} {item.locationName && ยท {item.locationName}} {item.storedAt && Stored {new Date(item.storedAt).toLocaleDateString()}} {item.bestBefore && }
{item.notes &&

{item.notes}

}
); } function SubcategoryGroup({ name, items, locations, plants, onRefresh }: { name: string; items: PantryItem[]; locations: LocationOption[]; plants: PlantOption[]; onRefresh: () => void; }) { const [open, setOpen] = useState(true); return (
{open && items.map(item => ( ))}
); } function CategoryGroup({ name, items, locations, plants, onRefresh }: { name: string; items: PantryItem[]; locations: LocationOption[]; plants: PlantOption[]; onRefresh: () => void; }) { const [open, setOpen] = useState(true); const expiring = items.filter(i => i.bestBefore && daysUntil(i.bestBefore) <= 30); // Group by subcategory const subcats = items.reduce>((acc, item) => { const key = item.pantrySubcategory ?? "โ€”"; if (!acc[key]) acc[key] = []; acc[key].push(item); return acc; }, {}); const hasSubcats = Object.keys(subcats).length > 1 || !subcats["โ€”"]; return (
{open && (
{hasSubcats ? Object.entries(subcats).sort(([a], [b]) => a.localeCompare(b)).map(([sub, subItems]) => ( )) : items.map(item => ( )) }
)}
); } export function PantryClient({ initialItems, locations, plants }: { initialItems: PantryItem[]; locations: LocationOption[]; plants: PlantOption[]; }) { const [items, setItems] = useState(initialItems); async function refresh() { const res = await fetch("/api/pantry"); if (res.ok) setItems(await res.json()); } const grouped = items.reduce>((acc, item) => { const key = item.pantryCategory ?? "Uncategorized"; if (!acc[key]) acc[key] = []; acc[key].push(item); return acc; }, {}); const expiringCount = items.filter(i => i.bestBefore && daysUntil(i.bestBefore) <= 30).length; return (

Pantry & Freezer

{expiringCount > 0 && (

{expiringCount} {expiringCount === 1 ? "item" : "items"} expiring within 30 days

)}
{items.length === 0 ? (

Nothing in the pantry yet โ€” add your first item.

) : (
{Object.entries(grouped) .sort(([a], [b]) => a === "Uncategorized" ? 1 : b === "Uncategorized" ? -1 : a.localeCompare(b)) .map(([name, catItems]) => ( ))}
)}
); }