import { useEffect, useMemo, useState } from 'react'; import { api } from '../lib/api.ts'; interface CalendarEvent { id: string; channel_id: string; creator_id: string; title: string; description: string | null; start_time: string; end_time: string | null; recurrence_rule: string | null; location: string | null; color: string | null; going_count: number; maybe_count: number; no_count: number; user_status: string; } interface CalendarViewProps { channelId: string; channelName: string; } export function CalendarView({ channelId, channelName }: CalendarViewProps) { const [events, setEvents] = useState([]); const [date, setDate] = useState(() => new Date()); const [loading, setLoading] = useState(false); const [showForm, setShowForm] = useState(false); const [title, setTitle] = useState(''); const [start, setStart] = useState(''); const [end, setEnd] = useState(''); const [description, setDescription] = useState(''); const [selectedEvent, setSelectedEvent] = useState(null); const monthStart = useMemo(() => new Date(date.getFullYear(), date.getMonth(), 1), [date]); const monthEnd = useMemo(() => new Date(date.getFullYear(), date.getMonth() + 1, 0), [date]); const days: (number | null)[] = useMemo(() => { const startDay = monthStart.getDay(); const total = monthEnd.getDate(); const arr: (number | null)[] = Array(startDay).fill(null); for (let i = 1; i <= total; i++) arr.push(i); return arr; }, [monthStart, monthEnd]); useEffect(() => { const from = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-01T00:00:00Z`; const to = `${date.getFullYear()}-${String(date.getMonth() + 2).padStart(2, '0')}-01T00:00:00Z`; setLoading(true); api.get(`/channels/${channelId}/events?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`) .then((data) => setEvents(Array.isArray(data) ? data : [])) .finally(() => setLoading(false)); }, [channelId, date]); const eventsForDay = (day: number) => { const d = new Date(date.getFullYear(), date.getMonth(), day); return events.filter((e) => { const start = new Date(e.start_time); return start.getFullYear() === d.getFullYear() && start.getMonth() === d.getMonth() && start.getDate() === d.getDate(); }); }; const handleCreate = async () => { if (!title || !start) return; const payload = { title, start_time: start, end_time: end || undefined, description: description || undefined }; const ev = await api.post(`/channels/${channelId}/events`, payload); setEvents((prev) => [...prev, ev]); setShowForm(false); setTitle(''); setStart(''); setEnd(''); setDescription(''); }; const handleRSVP = async (eventId: string, status: 'going' | 'maybe' | 'no') => { await api.post(`/events/${eventId}/rsvp`, { status }); setEvents((prev) => prev.map((e) => e.id === eventId ? { ...e, user_status: status } : e)); }; const prevMonth = () => setDate((d) => new Date(d.getFullYear(), d.getMonth() - 1, 1)); const nextMonth = () => setDate((d) => new Date(d.getFullYear(), d.getMonth() + 1, 1)); return (
○ {channelName}
{showForm && (
setTitle(e.target.value)} placeholder="title" className="terminal-input w-full" /> setStart(e.target.value)} className="terminal-input w-full" /> setEnd(e.target.value)} className="terminal-input w-full" />