"use client"; import { useState } from "react"; import { useTranslations } from "next-intl"; import { useRouter } from "next/navigation"; import { Wand2, Loader2, X } from "lucide-react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, } from "@/components/ui/dialog"; import { Textarea } from "@/components/ui/textarea"; import { Label } from "@/components/ui/label"; import { cn } from "@/lib/utils"; type Ingredient = { rawName: string }; export function AdaptRecipeButton({ recipeId, ingredients, }: { recipeId: string; ingredients: Ingredient[]; }) { const t = useTranslations("recipe"); const tCommon = useTranslations("common"); const router = useRouter(); const [open, setOpen] = useState(false); const [excluded, setExcluded] = useState>(new Set()); const [extraConstraints, setExtraConstraints] = useState(""); const [adapting, setAdapting] = useState(false); const [adaptationNotes, setAdaptationNotes] = useState(""); function toggleExclude(name: string) { setExcluded((prev) => { const next = new Set(prev); if (next.has(name)) next.delete(name); else next.add(name); return next; }); } function reset() { setExcluded(new Set()); setExtraConstraints(""); setAdaptationNotes(""); } async function handleAdapt() { if (excluded.size === 0 && !extraConstraints.trim()) { toast.error(t("adaptConstraintRequired")); return; } setAdapting(true); setAdaptationNotes(""); try { const res = await fetch(`/api/v1/ai/adapt/${recipeId}`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ excludeIngredients: Array.from(excluded), extraConstraints: extraConstraints.trim() || undefined, }), }); if (!res.ok) { const err = await res.json() as { error?: string }; toast.error(err.error ?? t("adaptFailed")); return; } const { id, adaptationNotes: notes } = await res.json() as { id: string; adaptationNotes: string }; setAdaptationNotes(notes); toast.success(t("adapted")); setOpen(false); reset(); router.push(`/recipes/${id}/edit`); } finally { setAdapting(false); } } const hasConstraints = excluded.size > 0 || extraConstraints.trim().length > 0; return ( <> setOpen(true)}> } /> {t("adaptTooltip")} { setOpen(v); if (!v) reset(); }}> {t("adaptTitle")} {t("adaptDescription")}
{/* Ingredient chips */}
{ingredients.map((ing, idx) => { const isExcluded = excluded.has(ing.rawName); return ( ); })}
{/* Free-text constraints */}