"use client"; import { MILLISECONDS_PER_DAY } from "@nexus/shared"; export const HOLIDAY_SOURCE_LABELS = { CALENDAR: "Holiday Calendar", LEGACY_PUBLIC_HOLIDAY: "Legacy import", CALENDAR_AND_LEGACY: "Holiday Calendar + legacy", } as const; export type VacationExplainabilityEntry = { startDate: Date | string; endDate: Date | string; isHalfDay?: boolean | null; deductedDays?: number | null; holidayCountryCode?: string | null; holidayCountryName?: string | null; holidayFederalState?: string | null; holidayMetroCityName?: string | null; holidayCalendarDates?: unknown; holidayLegacyPublicHolidayDates?: unknown; }; function toSortedDateList(value: unknown): string[] { return Array.isArray(value) && value.every((entry) => typeof entry === "string") ? [...value].sort() : []; } export function getRequestedDays( vacation: Pick, ): number { if (vacation.isHalfDay) { return 0.5; } const start = new Date(vacation.startDate); const end = new Date(vacation.endDate); return Math.round((end.getTime() - start.getTime()) / MILLISECONDS_PER_DAY) + 1; } export function getHolidayBasis(vacation: VacationExplainabilityEntry): string[] { return [ vacation.holidayCountryName ?? vacation.holidayCountryCode ?? null, vacation.holidayFederalState ?? null, vacation.holidayMetroCityName ?? null, ].filter((value): value is string => Boolean(value)); } export function getHolidayBreakdown( vacation: VacationExplainabilityEntry, ): Array<{ date: string; source: string }> { const calendarDates = toSortedDateList(vacation.holidayCalendarDates); const legacyDates = toSortedDateList(vacation.holidayLegacyPublicHolidayDates); const uniqueDates = [...new Set([...calendarDates, ...legacyDates])].sort(); return uniqueDates.map((date) => ({ date, source: calendarDates.includes(date) && legacyDates.includes(date) ? HOLIDAY_SOURCE_LABELS.CALENDAR_AND_LEGACY : calendarDates.includes(date) ? HOLIDAY_SOURCE_LABELS.CALENDAR : HOLIDAY_SOURCE_LABELS.LEGACY_PUBLIC_HOLIDAY, })); } export function buildVacationExplainabilityTooltip( vacation: VacationExplainabilityEntry & { type?: string | null }, ): string | null { const requestedDays = getRequestedDays(vacation); const deductedDays = typeof vacation.deductedDays === "number" ? vacation.deductedDays : null; const holidayBasis = getHolidayBasis(vacation); const holidayBreakdown = getHolidayBreakdown(vacation); const lines = [`Requested: ${requestedDays}d`]; if (deductedDays !== null) { lines.push(`Deducted: ${deductedDays}d`); } if (holidayBasis.length > 0) { lines.push(`Holiday basis: ${holidayBasis.join(" / ")}`); } if (holidayBreakdown.length > 0) { lines.push( `Excluded holidays: ${holidayBreakdown.map((holiday) => `${holiday.date} (${holiday.source})`).join(", ")}`, ); } if ((vacation.type === "SICK" || vacation.type === "PUBLIC_HOLIDAY") && deductedDays === 0) { lines.push("Does not reduce annual vacation entitlement."); } return lines.length > 0 ? lines.join("\n") : null; }