78d0599ffc
New AI-generated batch-cooking flow: pick N dinners/lunches + servings, get one unified recipe covering a full prep session — merged shopping list, steps tagged per-dish (a step can advance several dishes at once, e.g. a shared oven bake), and per-dish storage (fridge/freezer) + exact day-of reheat/finishing instructions. Schema: recipes.isBatchCook, recipeSteps.appliesTo (dish names), new recipeBatchDishes table. Batch recipes are excluded from the normal /recipes list and live under their own /batch-cooking section. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
72 lines
2.6 KiB
TypeScript
72 lines
2.6 KiB
TypeScript
"use client";
|
|
|
|
import { useState } from "react";
|
|
import Link from "next/link";
|
|
import { useTranslations, useLocale } from "next-intl";
|
|
import { ChefHat, PlusCircle, Utensils } from "lucide-react";
|
|
import { Button } from "@/components/ui/button";
|
|
import { BatchCookGenerateDialog } from "@/components/recipe/batch-cook-generate-dialog";
|
|
|
|
type Session = {
|
|
id: string;
|
|
title: string;
|
|
description: string | null;
|
|
baseServings: number;
|
|
createdAt: string;
|
|
dishCount: number;
|
|
};
|
|
|
|
export function BatchCookingPageContent({ sessions }: { sessions: Session[] }) {
|
|
const t = useTranslations("batchCooking");
|
|
const locale = useLocale();
|
|
const [open, setOpen] = useState(false);
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
<div className="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
<div>
|
|
<h1 className="text-3xl font-bold tracking-tight">{t("title")}</h1>
|
|
<p className="text-muted-foreground mt-1">{t("subtitle")}</p>
|
|
</div>
|
|
<Button size="sm" onClick={() => setOpen(true)}>
|
|
<PlusCircle className="h-4 w-4" />
|
|
{t("newSession")}
|
|
</Button>
|
|
</div>
|
|
|
|
{sessions.length === 0 ? (
|
|
<div className="flex flex-col items-center justify-center h-64 border-2 border-dashed rounded-xl gap-4">
|
|
<ChefHat className="h-12 w-12 text-muted-foreground/40" />
|
|
<p className="text-muted-foreground text-sm">{t("empty")}</p>
|
|
<Button size="sm" onClick={() => setOpen(true)}>
|
|
<PlusCircle className="h-4 w-4" />
|
|
{t("newSession")}
|
|
</Button>
|
|
</div>
|
|
) : (
|
|
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4">
|
|
{sessions.map((s) => (
|
|
<Link
|
|
key={s.id}
|
|
href={`/recipes/${s.id}`}
|
|
className="group rounded-xl border p-4 hover:shadow-sm transition-shadow space-y-2"
|
|
>
|
|
<h2 className="font-semibold group-hover:text-primary transition-colors line-clamp-1">{s.title}</h2>
|
|
{s.description && <p className="text-sm text-muted-foreground line-clamp-2">{s.description}</p>}
|
|
<div className="flex items-center gap-3 text-xs text-muted-foreground pt-1">
|
|
<span className="flex items-center gap-1">
|
|
<Utensils className="h-3.5 w-3.5" />
|
|
{t("dishCount", { count: s.dishCount })}
|
|
</span>
|
|
<span>{new Date(s.createdAt).toLocaleDateString(locale)}</span>
|
|
</div>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
)}
|
|
|
|
<BatchCookGenerateDialog open={open} onOpenChange={setOpen} />
|
|
</div>
|
|
);
|
|
}
|