"use client"; import { useState, useMemo, useRef } from "react"; import { PackageOpen } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"; import { Label } from "@/components/ui/label"; import { cn } from "@/lib/utils"; import { PANTRY_USE_REASONS, type PantryUseReason } from "@/lib/pantry/core"; import type { PantryItem } from "./pantry-client"; const QUICK_REASONS = ["Family dinner", "Dinner party", "Taking on a trip", "Meal prep", "Gave it away"]; type Pull = { amount: string }; export function PullDialog({ items, onSuccess }: { items: PantryItem[]; onSuccess: () => void }) { const [open, setOpen] = useState(false); const [search, setSearch] = useState(""); const [pulls, setPulls] = useState>({}); const [reason, setReason] = useState(""); const [disposition, setDisposition] = useState("consumed"); const [selectedReason, setSelectedReason] = useState(null); const [saving, setSaving] = useState(false); const [error, setError] = useState(null); const searchRef = useRef(null); const filtered = useMemo(() => { const q = search.trim().toLowerCase(); if (!q) return items; return items.filter(i => i.name.toLowerCase().includes(q) || i.pantryCategory?.toLowerCase().includes(q) || i.pantrySubcategory?.toLowerCase().includes(q) || i.tags?.some(t => t.toLowerCase().includes(q)) ); }, [items, search]); const activePulls = Object.entries(pulls).filter(([, p]) => { const n = parseFloat(p.amount); return !isNaN(n) && n > 0; }); function setAmount(id: string, val: string) { setPulls(prev => ({ ...prev, [id]: { amount: val } })); } function pickReason(r: string) { if (selectedReason === r) { setSelectedReason(null); setReason(""); } else { setSelectedReason(r); setReason(r); } } function reset() { setSearch(""); setPulls({}); setReason(""); setDisposition("consumed"); setSelectedReason(null); setError(null); } async function handleSubmit(e: React.FormEvent) { e.preventDefault(); if (activePulls.length === 0) { setError("Enter a quantity for at least one item."); return; } // Validate amounts against stock for (const [id, p] of activePulls) { const item = items.find(i => i.id === id); const amt = parseFloat(p.amount); if (item && amt > item.quantity) { setError(`Only ${item.quantity} ${item.unit ?? ""} of "${item.name}" on hand.`.trim()); return; } } setSaving(true); setError(null); try { const res = await fetch("/api/v1/pantry/bulk-use", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ pulls: activePulls.map(([id, p]) => ({ id, amount: parseFloat(p.amount) })), notes: reason.trim() || null, reason: disposition, }), }); const data = await res.json(); if (!res.ok) throw new Error(data.error ?? "Failed"); if (data.skipped?.length > 0) { // Someone else deleted these since the list loaded — say so instead of // pretending the whole pull worked. const names = data.skipped.map( (s: { id: string }) => items.find(i => i.id === s.id)?.name ?? "an item", ); setPulls({}); setError( `Couldn't pull ${names.join(", ")} — no longer in the pantry. Everything else was pulled.`, ); onSuccess(); return; } setOpen(false); reset(); onSuccess(); } catch (err) { setError(String(err).replace("Error: ", "")); } finally { setSaving(false); } } const inputCls = "w-full rounded-md border bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring"; return ( <> { setOpen(o); if (!o) reset(); }}> Pull from pantry
{/* Reason */}
{PANTRY_USE_REASONS.map(r => ( ))}
{QUICK_REASONS.map(r => ( ))}
{ setReason(e.target.value); setSelectedReason(null); }} />
{/* Search */}
setSearch(e.target.value)} autoFocus />
{/* Items list */}
{filtered.length === 0 && (

No items match.

)} {filtered.map(item => { const amt = pulls[item.id]?.amount ?? ""; const n = parseFloat(amt); const active = !isNaN(n) && n > 0; const over = active && n > item.quantity; return (

{item.name}

{item.quantity} {item.unit ?? "on hand"} {item.pantryCategory && <> · {item.pantryCategory}} {item.tags?.length > 0 && <> · {item.tags.join(", ")}}

setAmount(item.id, e.target.value)} /> {over &&

Max {item.quantity}

}
{item.unit ?? ""}
); })}
{/* Footer */}
{activePulls.length > 0 && (

Pulling {activePulls.length} item{activePulls.length !== 1 ? "s" : ""} {reason && <> for {reason}}

)} {error &&

{error}

}
); }