'use client' import { useState, useEffect, useCallback } from 'react' import { ChevronLeft, ChevronRight } from 'lucide-react' interface CalendarEvent { id: string title: string start: string end: string allDay: boolean description: string | null location: string | null owner: string ownerName: string color: string } function formatTime(iso: string): string { const d = new Date(iso) return d.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }) } function formatDayHeader(dateStr: string): string { const d = new Date(dateStr + (dateStr.length === 10 ? 'T00:00:00' : '')) return d.toLocaleDateString('ru-RU', { weekday: 'long', day: 'numeric', month: 'long' }) } function groupByDate(events: CalendarEvent[]): Record { const groups: Record = {} for (const ev of events) { const dateKey = ev.start.substring(0, 10) if (!groups[dateKey]) groups[dateKey] = [] groups[dateKey].push(ev) } return groups } function EventCard({ event }: { event: CalendarEvent }) { return (
{event.title}
{event.allDay ? 'Весь день' : `${formatTime(event.start)} — ${formatTime(event.end)}`} {event.ownerName}
{event.location && (
📍 {event.location}
)}
) } function TimelineView({ range }: { range: 'today' | 'week' }) { const [events, setEvents] = useState([]) const [loading, setLoading] = useState(true) useEffect(() => { setLoading(true) fetch(`/api/calendar?range=${range}`) .then(r => r.json()) .then(d => setEvents(d.events || [])) .catch(() => setEvents([])) .finally(() => setLoading(false)) }, [range]) if (loading) return (
Загрузка...
) if (events.length === 0) return (
🎉 Свободный день!
) const grouped = groupByDate(events) return (
{Object.entries(grouped).map(([dateKey, dayEvents]) => (
{formatDayHeader(dateKey)}
{dayEvents.map(ev => )}
))}
) } function MonthView() { const [year, setYear] = useState(() => new Date().getFullYear()) const [month, setMonth] = useState(() => new Date().getMonth()) const [events, setEvents] = useState([]) const [loading, setLoading] = useState(true) const [selectedDay, setSelectedDay] = useState(null) useEffect(() => { setLoading(true) fetch('/api/calendar?range=month') .then(r => r.json()) .then(d => setEvents(d.events || [])) .catch(() => setEvents([])) .finally(() => setLoading(false)) }, [year, month]) const today = new Date() const firstDay = new Date(year, month, 1) const lastDay = new Date(year, month + 1, 0) const startDow = (firstDay.getDay() + 6) % 7 // Mon=0 const totalCells = Math.ceil((startDow + lastDay.getDate()) / 7) * 7 const monthName = firstDay.toLocaleDateString('ru-RU', { month: 'long', year: 'numeric' }) const eventsByDate: Record = {} for (const ev of events) { const dk = ev.start.substring(0, 10) if (!eventsByDate[dk]) eventsByDate[dk] = [] eventsByDate[dk].push(ev) } const prevMonth = () => { if (month === 0) { setYear(y => y - 1); setMonth(11) } else setMonth(m => m - 1) setSelectedDay(null) } const nextMonth = () => { if (month === 11) { setYear(y => y + 1); setMonth(0) } else setMonth(m => m + 1) setSelectedDay(null) } const selectedEvents = selectedDay ? (eventsByDate[selectedDay] || []) : [] return (
{/* Month header */}
{monthName}
{/* Day of week headers */}
{['Пн','Вт','Ср','Чт','Пт','Сб','Вс'].map(d => (
{d}
))}
{/* Calendar grid */} {loading ? (
Загрузка...
) : (
{Array.from({ length: totalCells }).map((_, idx) => { const dayNum = idx - startDow + 1 if (dayNum < 1 || dayNum > lastDay.getDate()) { return
} const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(dayNum).padStart(2, '0')}` const hasEvents = !!eventsByDate[dateStr] const isToday = today.getFullYear() === year && today.getMonth() === month && today.getDate() === dayNum const isSelected = selectedDay === dateStr const dayEvents = eventsByDate[dateStr] || [] return ( ) })}
)} {/* Selected day events */} {selectedDay && (
{formatDayHeader(selectedDay)}
{selectedEvents.length === 0 ? (
Событий нет 🎉
) : ( selectedEvents.map(ev => ) )}
)}
) } export default function CalendarTab() { const [view, setView] = useState<'week' | 'month'>('week') const viewOptions: { id: 'week' | 'month'; label: string }[] = [ { id: 'week', label: 'Неделя' }, { id: 'month', label: 'Месяц' }, ] return (
{/* View switcher */}
{viewOptions.map(opt => ( ))}
{view === 'week' && } {view === 'month' && }
) }