import { addCivilDays, civilDayOfWeek } from '@/lib/schedule/civil'; import { periodsOverlap, type Period } from '@/lib/schedule/vacations'; const MONTHS_FR = [ 'Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin', 'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre', ]; type LabelledPeriod = Period & { labelFr: string }; type Day = { date: string; isWeekend: boolean; label: string | null }; type Month = { key: string; label: string; days: Day[] }; /** * Twelve months from today, with closure days filled in. * * A list of date ranges is precise and hard to picture; a year at a glance is * how anyone actually checks "have I left a gap in August?". Rendered on the * server: it only changes when the data does. */ export default function YearCalendar({ from, periods, }: { from: string; periods: LabelledPeriod[]; }) { const months = buildMonths(from, periods); return (
{months.map((month) => ( ))}
Calendrier des douze prochains mois, jours de fermeture marqués
{month.label}
{month.days.map((day) => ( ))}

fermeture week-end

); } function buildMonths(from: string, periods: LabelledPeriod[]): Month[] { const months: Month[] = []; let cursor = `${from.slice(0, 7)}-01`; for (let index = 0; index < 12; index += 1) { const prefix = cursor.slice(0, 7); const [year, month] = prefix.split('-').map(Number); const days: Day[] = []; let day = cursor; while (day.startsWith(prefix)) { const covering = periods.find((period) => periodsOverlap({ startDate: day, endDate: day }, period), ); days.push({ date: day, isWeekend: [0, 6].includes(civilDayOfWeek(day)), label: covering?.labelFr ?? null, }); day = addCivilDays(day, 1); } months.push({ key: prefix, label: `${MONTHS_FR[(month ?? 1) - 1]} ${year}`, days }); cursor = day; } return months; }