diff --git a/package.json b/package.json index c4e695a..bbbb992 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "my-weekly-todo-list", - "version": "1.66.0", + "version": "1.66.1", "description": "A web-based weekly task management application that organizes to-dos and calendar events in a single, intuitive weekly view", "main": "index.js", "scripts": { diff --git a/src/components/WeeklyView.tsx b/src/components/WeeklyView.tsx index 1f960f1..2695503 100644 --- a/src/components/WeeklyView.tsx +++ b/src/components/WeeklyView.tsx @@ -1613,11 +1613,29 @@ export default function WeeklyView() { const [weatherData, setWeatherData] = useState>({}); // Extend events with editable flag from connections, deduplicate by id + // Also deduplicate recurring series masters vs expanded instances: + // When a recurring event is created, the master is cached. Then the sync + // returns expanded instances with different IDs but the same recurringEventId. + // We keep instances and discard masters that overlap with them. const calendarEvents = useMemo(() => { const seen = new Set(); + const seenSlot = new Set(); + // Collect recurring event IDs that have expanded instances + const seriesWithInstances = new Set(); + for (const event of rawCalendarEvents) { + if (event.recurringEventId && event.id !== event.recurringEventId) { + seriesWithInstances.add(event.recurringEventId); + } + } return rawCalendarEvents.filter((event) => { if (seen.has(event.id)) return false; seen.add(event.id); + // Skip series master if expanded instances exist for this series + if (seriesWithInstances.has(event.id)) return false; + // Deduplicate by title+startTime+calendarId (catches optimistic add + cache read) + const slotKey = `${event.title}|${event.startTime}|${event.calendarId}`; + if (seenSlot.has(slotKey)) return false; + seenSlot.add(slotKey); return true; }).map((event) => { let isEditable = false;