/** * Calendar Widget - displays upcoming events */ import { useState, useEffect } from "react"; import { Calendar as CalendarIcon, Clock, MapPin } from "lucide-react"; import type { WidgetProps, Event } from "@mosaic/shared"; import { fetchEvents } from "@/lib/api/events"; export function CalendarWidget({ id: _id, config: _config }: WidgetProps): React.JSX.Element { const [events, setEvents] = useState([]); const [isLoading, setIsLoading] = useState(true); useEffect(() => { let isMounted = true; const loadEvents = async (): Promise => { setIsLoading(true); try { const data = await fetchEvents(); if (isMounted) { setEvents(data); } } catch { if (isMounted) { setEvents([]); } } finally { if (isMounted) { setIsLoading(false); } } }; void loadEvents(); return (): void => { isMounted = false; }; }, []); const formatTime = (dateValue: Date | string): string => { const date = new Date(dateValue); return date.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit", hour12: true, }); }; const formatDay = (dateValue: Date | string): string => { const date = new Date(dateValue); const today = new Date(); const tomorrow = new Date(today); tomorrow.setDate(tomorrow.getDate() + 1); if (date.toDateString() === today.toDateString()) { return "Today"; } else if (date.toDateString() === tomorrow.toDateString()) { return "Tomorrow"; } return date.toLocaleDateString("en-US", { weekday: "short", month: "short", day: "numeric" }); }; const getUpcomingEvents = (): Event[] => { const now = new Date(); return events .filter((e) => new Date(e.startTime) > now) .sort((a, b) => new Date(a.startTime).getTime() - new Date(b.startTime).getTime()) .slice(0, 5); }; if (isLoading) { return (
Loading events...
); } const upcomingEvents = getUpcomingEvents(); return (
{/* Header */}
Upcoming Events
{/* Event list */}
{upcomingEvents.length === 0 ? (
No upcoming events
) : ( upcomingEvents.map((event) => (
{event.title}
{!event.allDay && (
{formatTime(event.startTime)} {event.endTime && ` - ${formatTime(event.endTime)}`}
)} {event.location && (
{event.location}
)}
{formatDay(event.startTime)}
)) )}
); }