import type { Metadata } from "next"; import { headers } from "next/headers"; import Link from "next/link"; import { ChevronLeft, ChevronRight, ShoppingCart, Printer } from "lucide-react"; import { auth } from "@/lib/auth/server"; import { db, mealPlans, mealPlanMembers, recipes, userNutritionGoals, eq, and, desc } from "@epicure/db"; import { buttonVariants } from "@/components/ui/button"; import { MealPlanner } from "@/components/meal-plan/meal-planner"; import { ShareMealPlanButton } from "@/components/meal-plan/share-meal-plan-button"; import { NewShoppingListButton } from "@/components/meal-plan/new-shopping-list-button"; import { WeeklyNutritionBar } from "@/components/nutrition/weekly-nutrition-bar"; import { cn } from "@/lib/utils"; import { ExportMarkdownButton } from "@/components/shared/export-markdown-button"; import { mealPlanToMarkdown } from "@/lib/markdown/meal-plan"; import { getMessages, formatMessage } from "@/lib/i18n/server"; export const metadata: Metadata = {}; function getMonday(dateStr?: string): Date { const d = dateStr ? new Date(dateStr) : new Date(); const day = d.getDay(); const diff = (day === 0 ? -6 : 1 - day); d.setDate(d.getDate() + diff); d.setHours(0, 0, 0, 0); return d; } function toDateStr(d: Date): string { return d.toISOString().slice(0, 10); } function addWeeks(d: Date, n: number): Date { const copy = new Date(d); copy.setDate(copy.getDate() + n * 7); return copy; } export default async function MealPlanPage({ searchParams, }: { searchParams: Promise<{ week?: string }>; }) { const { week } = await searchParams; const session = await auth.api.getSession({ headers: await headers() }); if (!session) return null; const msgs = getMessages((session.user as { locale?: string }).locale); const monday = getMonday(week); const weekStart = toDateStr(monday); const prevWeek = toDateStr(addWeeks(monday, -1)); const nextWeek = toDateStr(addWeeks(monday, 1)); const sunday = addWeeks(monday, 1); sunday.setDate(sunday.getDate() - 1); const [plan, userRecipes, sharedMemberships, nutritionGoals] = await Promise.all([ db.query.mealPlans.findFirst({ where: and(eq(mealPlans.userId, session.user.id), eq(mealPlans.weekStart, weekStart)), with: { entries: { with: { recipe: { with: { photos: true } } }, }, }, }), db.query.recipes.findMany({ where: eq(recipes.authorId, session.user.id), orderBy: desc(recipes.updatedAt), columns: { id: true, title: true }, }), db.query.mealPlanMembers.findMany({ where: eq(mealPlanMembers.userId, session.user.id), with: { mealPlan: { with: { user: true } } }, }), db.query.userNutritionGoals.findFirst({ where: eq(userNutritionGoals.userId, session.user.id), }), ]); const hasNutritionGoals = !!( nutritionGoals && (nutritionGoals.caloriesKcal || nutritionGoals.proteinG || nutritionGoals.carbsG || nutritionGoals.fatG) ); const entries = (plan?.entries ?? []).map((e) => ({ id: e.id, day: e.day, mealType: e.mealType, servings: e.servings, note: e.note, recipe: e.recipe ? { id: e.recipe.id, title: e.recipe.title } : null, })); const label = `${monday.toLocaleDateString("en-US", { month: "short", day: "numeric" })} – ${sunday.toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" })}`; return (
{label}
{formatMessage(msgs.mealPlan.sharedPlanOf, { name: membership.mealPlan.user?.name ?? "?" })}
{formatMessage(msgs.mealPlan.weekOf, { date: membership.mealPlan.weekStart })} · {msgs.shareDialog[membership.role]}