import { useEffect, useState, useCallback } from 'react' import { ChevronLeft, ChevronRight, Plus } from 'lucide-react' import type { Calendar, EventSummary } from '../types' import { can } from '../types' import { useAuth } from '../components/AuthGate' import { fetchCalendars, fetchEvents } from '../api' import CalendarToggleList from '../components/CalendarToggleList' import ViewSwitcher, { type CalendarViewKey } from '../components/ViewSwitcher' import EventForm from '../components/EventForm' import MonthGrid from '../components/views/MonthGrid' import WeekGrid from '../components/views/WeekGrid' import DayGrid from '../components/views/DayGrid' import AgendaList from '../components/views/AgendaList' import { addDays, addMonths, monthGridDays, startOfWeek, toISODate, formatMonthLabel, formatWeekLabel, formatDateLabel, } from '../dateUtils' function rangeFor(view: CalendarViewKey, date: Date): { from: Date; to: Date } { if (view === 'month') { const days = monthGridDays(date) return { from: days[0], to: days[days.length - 1] } } if (view === 'week') { const start = startOfWeek(date) return { from: start, to: addDays(start, 6) } } if (view === 'day') { return { from: date, to: date } } // list/agenda — rolling 30-day window from the current date return { from: date, to: addDays(date, 30) } } function labelFor(view: CalendarViewKey, date: Date): string { if (view === 'month') return formatMonthLabel(date) if (view === 'week') return formatWeekLabel(date) if (view === 'day') return formatDateLabel(date) return `Next 30 days from ${formatDateLabel(date)}` } function shiftDate(view: CalendarViewKey, date: Date, dir: 1 | -1): Date { if (view === 'month') return addMonths(date, dir) if (view === 'week') return addDays(date, 7 * dir) return addDays(date, dir) } export default function CalendarView() { const { user } = useAuth() const [view, setView] = useState('month') const [currentDate, setCurrentDate] = useState(new Date()) const [calendars, setCalendars] = useState([]) const [visibleIds, setVisibleIds] = useState>(new Set()) const [events, setEvents] = useState([]) const [loading, setLoading] = useState(true) const [error, setError] = useState(null) const [formState, setFormState] = useState<{ open: boolean; eventId?: number; initialDate?: Date }>({ open: false }) useEffect(() => { fetchCalendars().then(cals => { setCalendars(cals) setVisibleIds(new Set(cals.map(c => c.id))) }).catch(err => setError(err.message)) }, []) const reload = useCallback(() => { const { from, to } = rangeFor(view, currentDate) setLoading(true) setError(null) fetchEvents({ from: toISODate(from), to: toISODate(to) }) .then(setEvents) .catch(err => setError(err.message)) .finally(() => setLoading(false)) }, [view, currentDate]) useEffect(() => { reload() }, [reload]) function toggleCalendar(id: number) { setVisibleIds(prev => { const next = new Set(prev) if (next.has(id)) next.delete(id) else next.add(id) return next }) } const visibleEvents = events.filter(ev => visibleIds.has(ev.calendar_id)) function openCreate(date: Date) { if (!can(user, 'create')) return setFormState({ open: true, initialDate: date }) } function openEdit(id: number) { setFormState({ open: true, eventId: id }) } function closeForm() { setFormState({ open: false }) } const viewProps = { events: visibleEvents, date: currentDate, onSelectDate: openCreate, onSelectEvent: openEdit, } return (

Calendar

{can(user, 'create') && ( )}
{error &&
{error}
}
Calendars
{labelFor(view, currentDate)}
{loading ? (
Loading…
) : view === 'month' ? ( ) : view === 'week' ? ( ) : view === 'day' ? ( ) : ( )}
{formState.open && ( )}
) }