import { useMemo } from 'react' import { useTranslation } from '../../i18n' import { isWeekend } from './holidays' import type { HolidaysMap, VacayEntry } from '../../types' const WEEKDAY_KEYS = ['vacay.mon', 'vacay.tue', 'vacay.wed', 'vacay.thu', 'vacay.fri', 'vacay.sat', 'vacay.sun'] as const function hexToRgba(hex: string, alpha: number): string { const r = parseInt(hex.slice(1, 3), 16) const g = parseInt(hex.slice(3, 5), 16) const b = parseInt(hex.slice(5, 7), 16) return `rgba(${r},${g},${b},${alpha})` } interface VacayMonthCardProps { year: number month: number holidays: HolidaysMap companyHolidaySet: Set companyHolidaysEnabled?: boolean entryMap: Record onCellClick: (date: string) => void companyMode: boolean blockWeekends: boolean weekendDays?: number[] tripDates?: Set weekStart?: number } export default function VacayMonthCard({ year, month, holidays, companyHolidaySet, companyHolidaysEnabled = true, entryMap, onCellClick, companyMode, blockWeekends, weekendDays = [0, 6], tripDates, weekStart = 1 }: VacayMonthCardProps) { const { t, locale } = useTranslation() const WEEKDAY_KEYS_SUNDAY = ['vacay.sun', 'vacay.mon', 'vacay.tue', 'vacay.wed', 'vacay.thu', 'vacay.fri', 'vacay.sat'] as const const orderedKeys = weekStart === 0 ? WEEKDAY_KEYS_SUNDAY : WEEKDAY_KEYS const weekdays = orderedKeys.map(k => t(k)) const monthName = useMemo(() => new Intl.DateTimeFormat(locale, { month: 'long' }).format(new Date(year, month, 1)), [locale, year, month]) const weeks = useMemo(() => { const firstDay = new Date(year, month, 1) const daysInMonth = new Date(year, month + 1, 0).getDate() let startDow = firstDay.getDay() - weekStart if (startDow < 0) startDow += 7 const cells = [] for (let i = 0; i < startDow; i++) cells.push(null) for (let d = 1; d <= daysInMonth; d++) cells.push(d) while (cells.length % 7 !== 0) cells.push(null) const w = [] for (let i = 0; i < cells.length; i += 7) w.push(cells.slice(i, i + 7)) return w }, [year, month]) const pad = (n) => String(n).padStart(2, '0') const todayStr = useMemo(() => { const d = new Date() return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}` }, []) return (
{monthName}
{weekdays.map((wd, i) => { // Map column index back to JS day (0=Sun..6=Sat) to check if it's a weekend column const jsDay = (i + weekStart) % 7 const isWeekendCol = weekendDays.includes(jsDay) return (
{wd}
) })}
{weeks.map((week, wi) => (
{week.map((day, di) => { if (day === null) return
const dateStr = `${year}-${pad(month + 1)}-${pad(day)}` const dayOfWeek = new Date(year, month, day).getDay() const weekend = weekendDays.includes(dayOfWeek) const holiday = holidays[dateStr] const isCompany = companyHolidaysEnabled && companyHolidaySet.has(dateStr) const dayEntries = entryMap[dateStr] || [] const isBlocked = (weekend && blockWeekends) || (isCompany && !companyMode) const isToday = dateStr === todayStr return (
onCellClick(dateStr)} onMouseEnter={e => { if (!isBlocked) e.currentTarget.style.background = 'var(--bg-hover)' }} onMouseLeave={e => { e.currentTarget.style.background = weekend ? 'var(--bg-secondary)' : 'transparent' }} > {holiday &&
} {isCompany &&
} {dayEntries.length === 1 && (
)} {dayEntries.length === 2 && (
)} {dayEntries.length === 3 && (
)} {dayEntries.length >= 4 && (
)} {tripDates?.has(dateStr) && ( )} 0 ? 700 : 500, color: isToday ? '#fff' : dayEntries.length > 0 ? 'var(--text-primary)' : holiday ? holiday.color : weekend ? 'var(--text-faint)' : 'var(--text-primary)', ...(isToday ? { display: 'inline-flex', alignItems: 'center', justifyContent: 'center', width: 18, height: 18, borderRadius: '50%', background: '#3b82f6', } : {}), }}> {day}
) })}
))}
) }