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,