- packages/date-tools: parseDateOnly/formatDateOnly/toDateOnly, getWeekStart/addWeeks/buildCalendarMonth, sur Luxon DateTime (UTC) - packages/shared: WEEK_DAYS/WeekDay, MEALS/Meal (contrat de valeurs documenté pour PlanningItemView.weekDay/.meal, pas encore enforcé en base), getPlanningByDateSchema (validation de forme de ?date=)
40 lines
1.5 KiB
TypeScript
40 lines
1.5 KiB
TypeScript
import type { DateTime } from "luxon";
|
||
|
||
/**
|
||
* The Monday of the week containing `date` (UTC midnight, same time-of-day
|
||
* handling as `date-only.ts`). Luxon's `startOf("week")` is Monday-first by
|
||
* default (ISO 8601 week numbering) regardless of locale, which already
|
||
* matches the French week this app uses — no locale option needed.
|
||
*/
|
||
export function getWeekStart(date: DateTime): DateTime {
|
||
return date.startOf("week");
|
||
}
|
||
|
||
/** Shifts `date` by `n` weeks (negative to go back) — `date` need not already be a week start. */
|
||
export function addWeeks(date: DateTime, n: number): DateTime {
|
||
return date.plus({ weeks: n });
|
||
}
|
||
|
||
/**
|
||
* Builds a fixed 6×7 (weeks × days, Monday-first) calendar grid covering
|
||
* `month`, the same shape every month-picker UI in this app should use —
|
||
* always 6 rows regardless of how many weeks the month actually spans, so
|
||
* the grid never resizes/reflows switching between months. Leading/trailing
|
||
* days from the adjacent month are included (a caller distinguishes them
|
||
* with `day.hasSame(month, "month")`), not omitted.
|
||
*/
|
||
export function buildCalendarMonth(month: DateTime): DateTime[][] {
|
||
const gridStart = getWeekStart(month.startOf("month"));
|
||
|
||
const weeks: DateTime[][] = [];
|
||
let cursor = gridStart;
|
||
for (let week = 0; week < 6; week++) {
|
||
const days: DateTime[] = [];
|
||
for (let day = 0; day < 7; day++) {
|
||
days.push(cursor);
|
||
cursor = cursor.plus({ days: 1 });
|
||
}
|
||
weeks.push(days);
|
||
}
|
||
return weeks;
|
||
}
|