Add French holidays to the timesheet, including Easter Monday
Implements logic to calculate and display French national holidays, such as Easter Monday, within the timesheet view. Replit-Commit-Author: Agent Replit-Commit-Session-Id: 55837015-10e9-4be9-b857-7f5e6be73772 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Event-Id: 981f81d9-47f7-41fe-b3b4-19b5c1d2aa5d Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/1cc377db-7ea0-49f2-97ce-c3e87e0228cc/55837015-10e9-4be9-b857-7f5e6be73772/KSYTI3T Replit-Helium-Checkpoint-Created: true
This commit is contained in:
parent
3f8e83b6ad
commit
a36c4a444a
@ -38,6 +38,51 @@ import { useAdminUnlocked } from "@/lib/admin-mode";
|
||||
import { getDaysInMonth, isWeekend, format } from "date-fns";
|
||||
import { fr } from "date-fns/locale";
|
||||
|
||||
function addDays(date: Date, days: number) {
|
||||
const next = new Date(date);
|
||||
next.setDate(next.getDate() + days);
|
||||
return next;
|
||||
}
|
||||
|
||||
function getEasterSunday(year: number) {
|
||||
const a = year % 19;
|
||||
const b = Math.floor(year / 100);
|
||||
const c = year % 100;
|
||||
const d = Math.floor(b / 4);
|
||||
const e = b % 4;
|
||||
const f = Math.floor((b + 8) / 25);
|
||||
const g = Math.floor((b - f + 1) / 3);
|
||||
const h = (19 * a + b - d - g + 15) % 30;
|
||||
const i = Math.floor(c / 4);
|
||||
const k = c % 4;
|
||||
const l = (32 + 2 * e + 2 * i - h - k) % 7;
|
||||
const m = Math.floor((a + 11 * h + 22 * l) / 451);
|
||||
const month = Math.floor((h + l - 7 * m + 114) / 31);
|
||||
const day = ((h + l - 7 * m + 114) % 31) + 1;
|
||||
return new Date(year, month - 1, day);
|
||||
}
|
||||
|
||||
function getFrenchHolidayName(date: Date) {
|
||||
const year = date.getFullYear();
|
||||
const dateStr = format(date, "yyyy-MM-dd");
|
||||
const easterSunday = getEasterSunday(year);
|
||||
const holidays: Record<string, string> = {
|
||||
[`${year}-01-01`]: "Jour de l'an",
|
||||
[format(addDays(easterSunday, 1), "yyyy-MM-dd")]: "Lundi de Pâques",
|
||||
[`${year}-05-01`]: "Fête du Travail",
|
||||
[`${year}-05-08`]: "Victoire 1945",
|
||||
[format(addDays(easterSunday, 39), "yyyy-MM-dd")]: "Ascension",
|
||||
[format(addDays(easterSunday, 50), "yyyy-MM-dd")]: "Lundi de Pentecôte",
|
||||
[`${year}-07-14`]: "Fête nationale",
|
||||
[`${year}-08-15`]: "Assomption",
|
||||
[`${year}-11-01`]: "Toussaint",
|
||||
[`${year}-11-11`]: "Armistice 1918",
|
||||
[`${year}-12-25`]: "Noël",
|
||||
};
|
||||
|
||||
return holidays[dateStr] || null;
|
||||
}
|
||||
|
||||
type LocalEntry = {
|
||||
timesheetLineId: number;
|
||||
date: string;
|
||||
@ -100,10 +145,13 @@ export default function TimesheetDetailPage() {
|
||||
const daysCount = getDaysInMonth(new Date(timesheet.year, timesheet.month - 1));
|
||||
const arr = Array.from({ length: daysCount }, (_, i) => {
|
||||
const date = new Date(timesheet.year, timesheet.month - 1, i + 1);
|
||||
const holidayName = getFrenchHolidayName(date);
|
||||
return {
|
||||
dateStr: format(date, "yyyy-MM-dd"),
|
||||
dayNum: i + 1,
|
||||
isWeekendDay: isWeekend(date),
|
||||
isHoliday: Boolean(holidayName),
|
||||
holidayName,
|
||||
dayName: format(date, "EE", { locale: fr })
|
||||
};
|
||||
});
|
||||
@ -404,8 +452,9 @@ export default function TimesheetDetailPage() {
|
||||
key={day.dateStr}
|
||||
className={cn(
|
||||
"px-0 py-1 font-medium text-center border-b border-r",
|
||||
day.isWeekendDay ? "bg-muted/50" : ""
|
||||
day.isWeekendDay || day.isHoliday ? "bg-muted/50" : ""
|
||||
)}
|
||||
title={day.holidayName || undefined}
|
||||
>
|
||||
<div className="flex flex-col items-center leading-tight">
|
||||
<span className="text-[9px] uppercase opacity-60">{day.dayName.slice(0, 2)}</span>
|
||||
@ -466,11 +515,11 @@ export default function TimesheetDetailPage() {
|
||||
key={day.dateStr}
|
||||
className={cn(
|
||||
"p-0 text-center border-r transition-colors select-none",
|
||||
day.isWeekendDay ? "bg-muted/30" : "",
|
||||
day.isWeekendDay || day.isHoliday ? "bg-muted/30" : "",
|
||||
isEditable ? "cursor-pointer hover:bg-primary/10" : "",
|
||||
val > 0 ? "bg-primary/5 text-primary font-semibold" : ""
|
||||
)}
|
||||
title={desc || undefined}
|
||||
title={desc || day.holidayName || undefined}
|
||||
>
|
||||
{isEditable ? (
|
||||
<Popover>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user