import { useCallback } from "react"; import { CalendarDays, MapPin } from "lucide-react"; import { Link } from "react-router-dom"; import { DashboardWidgetList, DismissibleAlert, LoadingFrame, useDashboardWidgetData, type ApiSettings, type DashboardWidgetConfiguration } from "@govoplan/core-webui"; import { listCalendarEvents, type CalendarEvent } from "../../api/calendar"; export default function UpcomingEventsWidget({ settings, refreshKey, configuration }: { settings: ApiSettings; refreshKey: number; configuration: DashboardWidgetConfiguration; }) { const maxItems = numberSetting(configuration.maxItems, 5, 1, 12); const daysAhead = numberSetting(configuration.daysAhead, 14, 1, 90); const showLocation = configuration.showLocation !== false; const load = useCallback(async () => { const start = new Date(); const end = new Date(start); end.setDate(end.getDate() + daysAhead); const response = await listCalendarEvents(settings, { start_at: start.toISOString(), end_at: end.toISOString() }); return [...response.events] .filter((event) => event.status !== "cancelled") .sort( (left, right) => new Date(left.start_at).getTime() - new Date(right.start_at).getTime() ) .slice(0, maxItems); }, [daysAhead, maxItems, settings]); const { data: events, loading, error } = useDashboardWidgetData( load, refreshKey ); return ( {error && ( {error} )} ({ id: event.id, title: event.summary, detail: showLocation && event.location ? ( <> ); } function eventTimeLabel(event: CalendarEvent): string { const start = new Date(event.start_at); if (event.all_day) { return new Intl.DateTimeFormat(undefined, { weekday: "short", day: "2-digit", month: "short" }).format(start); } return new Intl.DateTimeFormat(undefined, { weekday: "short", day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" }).format(start); } function numberSetting( value: unknown, fallback: number, minimum: number, maximum: number ): number { const numeric = typeof value === "number" ? value : Number(value); return Number.isFinite(numeric) ? Math.max(minimum, Math.min(maximum, Math.floor(numeric))) : fallback; }