import { type DateTime, toDateOnly } from "@batch-cooking/date-tools"; import type { PlanningView } from "@batch-cooking/shared"; import { prisma } from "../../db/prisma.js"; /** * Finds the household's planning that covers `date` and shapes it into a * {@link PlanningView} (recipes resolved to `{id, name}`). `date` is * whatever the caller wants "now" to mean — the current `/planning` route * passes a `date-tools`-parsed `?date=` query param, letting a caller look * up any week's planning, not just the one covering today. * * Returns `null` for two distinct, both entirely normal states — a * `houseId` of `null` (the profile has no household yet — households are no * longer created automatically at signup, see `auth.service.ts`) and "no * planning row covers this date" (the expected case until planning * creation is built) — neither is an error, so both collapse to the same * "nothing to show yet" result rather than throwing. */ export async function getPlanningForDate( houseId: number | null, date: DateTime, ): Promise { if (houseId === null) { return null; } // `startDate`/`finishDate` are `@db.Date` columns (no time-of-day // component) — comparing against a UTC-midnight JS `Date` lines up with // how Postgres stores/returns them, regardless of the server's local // timezone. const dateOnly = toDateOnly(date).toJSDate(); const planning = await prisma.planning.findFirst({ where: { houseId, startDate: { lte: dateOnly }, finishDate: { gte: dateOnly }, }, // A household should never have two plannings covering the same day, // but nothing in the schema enforces that yet — pick the most recently // started one rather than letting the query fail if it ever happens. orderBy: { startDate: "desc" }, include: { items: { include: { recipe: { select: { id: true, name: true } } }, }, }, }); if (!planning) { return null; } return { id: planning.id, startDate: planning.startDate.toISOString(), finishDate: planning.finishDate.toISOString(), items: planning.items.map((item) => ({ id: item.id, weekDay: item.weekDay, meal: item.meal, recipe: item.recipe, })), }; }