"use client"; import { useEffect, useState } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { RefreshCw, Calendar as CalendarIcon } from "lucide-react"; import { useRouter } from "next/navigation"; interface Event { id: string; title: string; start: string; end: string; allDay: boolean; calendar: string; calendarColor: string; } export function Calendar() { const [events, setEvents] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const router = useRouter(); const fetchEvents = async () => { setLoading(true); try { const response = await fetch('/api/calendars?refresh=true'); if (!response.ok) { throw new Error('Failed to fetch events'); } const calendarsData = await response.json(); console.log('Calendar Widget - Fetched calendars:', calendarsData); // Get current date at the start of the day const now = new Date(); now.setHours(0, 0, 0, 0); // Helper function to get display name for calendar const getCalendarDisplayName = (calendar: any) => { // If calendar is synced to an external account, use the account name if (calendar.syncConfig?.syncEnabled && calendar.syncConfig?.mailCredential) { return calendar.syncConfig.mailCredential.display_name || calendar.syncConfig.mailCredential.email; } // For non-synced calendars, use the calendar name return calendar.name; }; // Extract and process events from all calendars const allEvents = calendarsData.flatMap((calendar: any) => (calendar.events || []).map((event: any) => ({ id: event.id, title: event.title, start: event.start, end: event.end, allDay: event.isAllDay, calendar: getCalendarDisplayName(calendar), calendarColor: calendar.color, externalEventId: event.externalEventId || null, // Add externalEventId for deduplication })) ); // Deduplicate events by externalEventId (if same event appears in multiple calendars) // Keep the first occurrence of each unique externalEventId const seenExternalIds = new Set(); const seenEventKeys = new Set(); // For events without externalEventId, use title+start+calendar as key const deduplicatedEvents = allEvents.filter((event: any) => { if (event.externalEventId) { // For events with externalEventId, deduplicate strictly by externalEventId if (seenExternalIds.has(event.externalEventId)) { console.log('Calendar Widget - Skipping duplicate by externalEventId:', { title: event.title, externalEventId: event.externalEventId, calendar: event.calendar, }); return false; // Skip duplicate } seenExternalIds.add(event.externalEventId); } else { // For events without externalEventId, use title + start date + calendar as key // This prevents false positives when same title/date appears in different calendars const eventKey = `${event.title}|${new Date(event.start).toISOString().split('T')[0]}|${event.calendar}`; if (seenEventKeys.has(eventKey)) { console.log('Calendar Widget - Skipping duplicate by title+date+calendar:', { title: event.title, start: event.start, calendar: event.calendar, }); return false; // Skip duplicate } seenEventKeys.add(eventKey); } return true; // Keep event }); console.log('Calendar Widget - Deduplication:', { totalBefore: allEvents.length, totalAfter: deduplicatedEvents.length, duplicatesRemoved: allEvents.length - deduplicatedEvents.length, }); // Filter for upcoming events const upcomingEvents = deduplicatedEvents .filter((event: any) => new Date(event.start) >= now) .sort((a: any, b: any) => new Date(a.start).getTime() - new Date(b.start).getTime()) .slice(0, 7); console.log('Calendar Widget - Processed events:', upcomingEvents); setEvents(upcomingEvents); setError(null); } catch (err) { console.error('Error fetching events:', err); setError('Failed to load events'); } finally { setLoading(false); } }; useEffect(() => { fetchEvents(); }, []); const formatDate = (dateString: string) => { const date = new Date(dateString); return new Intl.DateTimeFormat('fr-FR', { day: '2-digit', month: 'short' }).format(date); }; const formatTime = (dateString: string) => { const date = new Date(dateString); return new Intl.DateTimeFormat('fr-FR', { hour: '2-digit', minute: '2-digit', }).format(date); }; return ( Agenda {loading ? (
) : error ? (
{error}
) : events.length === 0 ? (
No upcoming events
) : (
{events.map((event) => (
{formatDate(event.start)} {formatTime(event.start)}

{event.title}

{!event.allDay && ( {formatTime(event.start)} - {formatTime(event.end)} )}
{event.calendar}
))}
)} ); }