diff --git a/app/agenda/page.tsx b/app/agenda/page.tsx index 2876c8c..f5d80f4 100644 --- a/app/agenda/page.tsx +++ b/app/agenda/page.tsx @@ -556,6 +556,35 @@ export default async function CalendarPage() { } } + // Auto-sync Microsoft calendars if needed (background, don't block page load) + const microsoftSyncConfigs = await prisma.calendarSync.findMany({ + where: { + provider: 'microsoft', + syncEnabled: true, + calendar: { + userId: session?.user?.id || '' + } + } + }); + + // Trigger sync for Microsoft calendars that need it (async, don't wait) + for (const syncConfig of microsoftSyncConfigs) { + const needsSync = !syncConfig.lastSyncAt || + (Date.now() - syncConfig.lastSyncAt.getTime()) / (1000 * 60) >= syncConfig.syncFrequency; + + if (needsSync) { + // Trigger sync in background (don't await to avoid blocking page load) + import('@/lib/services/microsoft-calendar-sync').then(({ syncMicrosoftCalendar }) => { + syncMicrosoftCalendar(syncConfig.id, false).catch((error) => { + console.error('Background sync failed for Microsoft calendar', { + calendarSyncId: syncConfig.id, + error: error instanceof Error ? error.message : String(error), + }); + }); + }); + } + } + // Refresh calendars after auto-setup and cleanup // Exclude "Privée" and "Default" calendars that are not synced // IMPORTANT: Include all "Privée"/"Default" calendars that have ANY syncConfig (enabled or disabled) diff --git a/components/calendar/calendar-client.tsx b/components/calendar/calendar-client.tsx index d313320..9bbf3f5 100644 --- a/components/calendar/calendar-client.tsx +++ b/components/calendar/calendar-client.tsx @@ -680,8 +680,8 @@ function EventPreview({ event, calendar }: { event: Event; calendar: Calendar }) {isExpanded && (
- {event.description && ( -

{event.description}

+ {cleanDescription(event.description) && ( +

{cleanDescription(event.description)}

)}
@@ -995,7 +995,7 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend setSelectedEvent(event.extendedProps.originalEvent); setEventForm({ title: event.title, - description: event.extendedProps.description, + description: cleanDescription(event.extendedProps.description), start: startDate.toISOString().slice(0, 16), end: endDate.toISOString().slice(0, 16), allDay: event.isAllDay, @@ -1148,6 +1148,14 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend } }; + // Helper function to clean description by removing Microsoft ID prefix + const cleanDescription = (description: string | null | undefined): string | null => { + if (!description) return null; + // Remove [MS_ID:xxx] prefix if present + const cleaned = description.replace(/^\[MS_ID:[^\]]+\]\n?/, ''); + return cleaned.trim() || null; + }; + const getCalendarDisplayName = (calendar: CalendarWithMission) => { // If calendar is synced to an external account, use the same display name as in courrier if (calendar.syncConfig?.syncEnabled && calendar.syncConfig?.mailCredential) { @@ -1465,7 +1473,7 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend start: new Date(event.start), end: new Date(event.end), allDay: event.isAllDay, - description: event.description, + description: cleanDescription(event.description), location: event.location, calendarId: event.calendarId, backgroundColor: `${cal.color}dd`, @@ -1474,7 +1482,7 @@ export function CalendarClient({ initialCalendars, userId, userProfile }: Calend extendedProps: { calendarName: cal.name, location: event.location, - description: event.description, + description: cleanDescription(event.description), calendarId: event.calendarId, originalEvent: event, color: cal.color diff --git a/lib/services/microsoft-calendar-sync.ts b/lib/services/microsoft-calendar-sync.ts index 7b4c7e1..351277c 100644 --- a/lib/services/microsoft-calendar-sync.ts +++ b/lib/services/microsoft-calendar-sync.ts @@ -288,16 +288,32 @@ export async function syncMicrosoftCalendar( // Sync events: create or update for (const caldavEvent of caldavEvents) { - // Try to find existing event by matching title and start date - const existingEvent = existingEvents.find( - (e) => - e.title === caldavEvent.summary && - Math.abs(new Date(e.start).getTime() - caldavEvent.start.getTime()) < 60000 // Within 1 minute - ); + // Store Microsoft ID in description with a special prefix for matching + const microsoftId = caldavEvent.uid; + const descriptionWithId = caldavEvent.description + ? `[MS_ID:${microsoftId}]\n${caldavEvent.description}` + : `[MS_ID:${microsoftId}]`; + + // Try to find existing event by Microsoft ID first (most reliable) + let existingEvent = existingEvents.find((e) => { + if (e.description && e.description.includes(`[MS_ID:${microsoftId}]`)) { + return true; + } + return false; + }); + + // Fallback: try to find by matching title and start date (for events created before this fix) + if (!existingEvent) { + existingEvent = existingEvents.find( + (e) => + e.title === caldavEvent.summary && + Math.abs(new Date(e.start).getTime() - caldavEvent.start.getTime()) < 60000 // Within 1 minute + ); + } const eventData = { title: caldavEvent.summary, - description: caldavEvent.description || null, + description: descriptionWithId, start: caldavEvent.start, end: caldavEvent.end, location: caldavEvent.location || null,