'use client' import { useMemo } from 'react' import { useTheme } from '@/lib/ThemeContext' import type { PublicEvent, SchoolEvent } from '@/app/schulkalender/types' import { EVENT_TYPE_COLOR } from '@/app/schulkalender/types' interface MonthViewProps { year: number month: number // 1-12 holidays: PublicEvent[] schoolEvents?: SchoolEvent[] onPrev: () => void onNext: () => void onToday: () => void onDayClick?: (iso: string) => void onAddEvent?: () => void onRollover?: () => void } const WEEKDAYS_DE = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'] const MONTHS_DE = [ 'Januar', 'Februar', 'Maerz', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember', ] interface Cell { date: Date inMonth: boolean events: PublicEvent[] } function buildMonthGrid(year: number, month: number, holidays: PublicEvent[]): Cell[] { // First Monday on or before the 1st of the month. const first = new Date(Date.UTC(year, month - 1, 1)) const firstWeekday = (first.getUTCDay() + 6) % 7 // Monday = 0 const start = new Date(first) start.setUTCDate(first.getUTCDate() - firstWeekday) const cells: Cell[] = [] for (let i = 0; i < 42; i++) { const d = new Date(start) d.setUTCDate(start.getUTCDate() + i) const iso = d.toISOString().slice(0, 10) const events = holidays.filter(h => iso >= h.start_date && iso <= h.end_date) cells.push({ date: d, inMonth: d.getUTCMonth() === month - 1, events, }) if (i >= 27 && d.getUTCMonth() !== month - 1) { // Stop a row early if the rest is fully outside the month. const restAllOutside = cells.slice(i + 1 - ((i + 1) % 7), i + 1).every(c => !c.inMonth) if (restAllOutside) break } } // Pad to multiple of 7 if we cut early. while (cells.length % 7 !== 0) { const last = cells[cells.length - 1].date const d = new Date(last) d.setUTCDate(last.getUTCDate() + 1) cells.push({ date: d, inMonth: false, events: [] }) } return cells } export function MonthView({ year, month, holidays, schoolEvents = [], onPrev, onNext, onToday, onDayClick, onAddEvent, onRollover }: MonthViewProps) { const { isDark } = useTheme() const cells = useMemo(() => buildMonthGrid(year, month, holidays), [year, month, holidays]) // School events per ISO date — quick lookup during cell render. const schoolEventsByDate = useMemo(() => { const map = new Map() for (const ev of schoolEvents) { const start = new Date(ev.start_date) const end = new Date(ev.end_date) for (let d = new Date(start); d <= end; d.setUTCDate(d.getUTCDate() + 1)) { const iso = d.toISOString().slice(0, 10) const arr = map.get(iso) || [] arr.push(ev) map.set(iso, arr) } } return map }, [schoolEvents]) const headerClass = isDark ? 'text-white' : 'text-slate-900' const subtleText = isDark ? 'text-white/40' : 'text-slate-400' const cardClass = isDark ? 'bg-white/10 border-white/20' : 'bg-white/80 border-black/10' const buttonClass = isDark ? 'bg-white/10 text-white/80 hover:bg-white/20' : 'bg-white text-slate-700 hover:bg-slate-100 border border-slate-200' const todayIso = new Date().toISOString().slice(0, 10) return (

{MONTHS_DE[month - 1]} {year}

{onAddEvent && ( )} {onRollover && ( )}
{WEEKDAYS_DE.map(w => (
{w}
))}
{cells.map((c, i) => { const iso = c.date.toISOString().slice(0, 10) const isToday = iso === todayIso const publicHoliday = c.events.find(e => e.event_type === 'public_holiday') const schoolHoliday = c.events.find(e => e.event_type === 'school_holiday') let bg = isDark ? 'bg-white/5' : 'bg-slate-50' if (schoolHoliday) bg = isDark ? 'bg-amber-500/20' : 'bg-amber-100' if (publicHoliday) bg = isDark ? 'bg-rose-500/25' : 'bg-rose-100' const dayEvents = schoolEventsByDate.get(iso) || [] return (
c.inMonth && onDayClick?.(iso)} className={`relative aspect-square rounded-lg p-2 text-sm border ${ onDayClick && c.inMonth ? 'cursor-pointer hover:ring-2 hover:ring-indigo-300/50' : '' } ${ isDark ? 'border-white/10' : 'border-black/5' } ${c.inMonth ? bg : (isDark ? 'bg-transparent' : 'bg-transparent')} ${ isToday ? (isDark ? 'ring-2 ring-indigo-400' : 'ring-2 ring-indigo-500') : '' }`} >
{c.date.getUTCDate()}
{c.events.length > 0 && (
{c.events.slice(0, 2).map(e => (
{e.name_de}
))} {c.events.length > 2 && (
+{c.events.length - 2}
)}
)} {dayEvents.length > 0 && (
{dayEvents.slice(0, 4).map(ev => ( ))}
)}
) })}
Feiertag Schulferien
) }