import type { Metadata } from "next"; import { headers } from "next/headers"; import { auth } from "@/lib/auth/server"; import { db, recipes, pantryItems } from "@epicure/db"; import { eq } from "@epicure/db"; import { getPublicUrl } from "@/lib/storage"; import { CanCookContent } from "@/components/recipe/can-cook-content"; export const metadata: Metadata = {}; const EXPIRING_WITHIN_DAYS = 3; function isExpiringSoon(expiresAt: Date | null): boolean { if (!expiresAt) return false; const days = Math.ceil((expiresAt.getTime() - Date.now()) / (1000 * 60 * 60 * 24)); return days >= 0 && days <= EXPIRING_WITHIN_DAYS; } export default async function CanCookPage() { const session = await auth.api.getSession({ headers: await headers() }); if (!session) return null; const [userRecipes, pantry] = await Promise.all([ db.query.recipes.findMany({ where: eq(recipes.authorId, session.user.id), with: { ingredients: true, photos: true, }, }), db.query.pantryItems.findMany({ where: eq(pantryItems.userId, session.user.id), }), ]); const pantryKeys = new Set(pantry.map((p) => p.rawName.toLowerCase())); const expiringSoonKeys = new Set( pantry .filter((p) => isExpiringSoon(p.expiresAt)) .map((p) => p.rawName.toLowerCase()) ); const scored = userRecipes .filter((r) => r.ingredients.length > 0) .map((recipe) => { const matched = recipe.ingredients.filter((ing) => pantryKeys.has(ing.rawName.toLowerCase()) ).length; const missing = recipe.ingredients .filter((ing) => !pantryKeys.has(ing.rawName.toLowerCase())) .map((ing) => ing.rawName) .slice(0, 5); const usesExpiring = recipe.ingredients .filter((ing) => expiringSoonKeys.has(ing.rawName.toLowerCase())) .map((ing) => ing.rawName); const total = recipe.ingredients.length; const cover = recipe.photos?.find((p) => p.isCover) ?? recipe.photos?.[0]; return { recipe: { id: recipe.id, title: recipe.title, description: recipe.description, photos: cover ? [{ url: getPublicUrl(cover.storageKey) }] : [], }, matched, total, pct: Math.round((matched / total) * 100), missing, usesExpiring, }; }) .sort((a, b) => { if (a.usesExpiring.length > 0 !== b.usesExpiring.length > 0) { return a.usesExpiring.length > 0 ? -1 : 1; } return b.pct - a.pct; }); return ; }