From 1b1a95da1dc75b3884b10b0bf4b33b35ee02188c Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Fri, 22 Aug 2025 12:10:33 -0600 Subject: [PATCH] Fix display of repeated multi day events --- src/components/EventOverlay.vue | 59 ++++++++++++++++++++------------- 1 file changed, 36 insertions(+), 23 deletions(-) diff --git a/src/components/EventOverlay.vue b/src/components/EventOverlay.vue index 0cbaa3a..cd363e6 100644 --- a/src/components/EventOverlay.vue +++ b/src/components/EventOverlay.vue @@ -62,41 +62,51 @@ function generateRepeatOccurrencesForDate(targetDateStr) { if (baseEvent.repeat === 'weeks') { const repeatWeekdays = baseEvent.repeatWeekdays - const targetWeekday = targetDate.getDay() - if (!repeatWeekdays[targetWeekday]) continue if (targetDate < baseStartDate) continue - const maxOccurrences = - baseEvent.repeatCount === 'unlimited' ? Infinity : parseInt(baseEvent.repeatCount, 10) - const interval = baseEvent.repeatInterval || 1 + const maxOccurrences = baseEvent.repeatCount === 'unlimited' ? Infinity : parseInt(baseEvent.repeatCount, 10) if (maxOccurrences === 0) continue - // Count occurrences from start up to (and including) target + const interval = baseEvent.repeatInterval || 1 + const msPerDay = 24*60*60*1000 + + // Determine if targetDate lies within some occurrence span. We look backwards up to spanDays to find a start day. + let occStart = null + for (let back=0; back<=spanDays; back++) { + const cand = new Date(targetDate) + cand.setDate(cand.getDate() - back) + if (cand < baseStartDate) break + const daysDiff = Math.floor((cand - baseStartDate)/msPerDay) + const weeksDiff = Math.floor(daysDiff / 7) + if (weeksDiff % interval !== 0) continue + if (repeatWeekdays[cand.getDay()]) { + // candidate start must produce span covering targetDate + const candEnd = new Date(cand) + candEnd.setDate(candEnd.getDate() + spanDays) + if (targetDate <= candEnd) { + occStart = cand + break + } + } + } + if (!occStart) continue + // Skip base occurrence if this is within its span (base already physically stored) + if (occStart.getTime() === baseStartDate.getTime()) continue + // Compute occurrence index (number of previous start days) let occIdx = 0 - // Determine the week distance from baseStartDate to targetDate - const msPerDay = 24 * 60 * 60 * 1000 - const daysDiff = Math.floor((targetDate - baseStartDate) / msPerDay) - const weeksDiff = Math.floor(daysDiff / 7) - if (weeksDiff % interval !== 0) continue - // Count occurrences only among valid weeks and selected weekdays const cursor = new Date(baseStartDate) - while (cursor < targetDate && occIdx < maxOccurrences) { - const cDaysDiff = Math.floor((cursor - baseStartDate) / msPerDay) + while (cursor < occStart && occIdx < maxOccurrences) { + const cDaysDiff = Math.floor((cursor - baseStartDate)/msPerDay) const cWeeksDiff = Math.floor(cDaysDiff / 7) if (cWeeksDiff % interval === 0 && repeatWeekdays[cursor.getDay()]) occIdx++ - cursor.setDate(cursor.getDate() + 1) - } - if (targetDate.getTime() === baseStartDate.getTime()) { - // skip base occurrence - continue + cursor.setDate(cursor.getDate()+1) } if (occIdx >= maxOccurrences) continue - const occStart = new Date(targetDate) const occEnd = new Date(occStart) occEnd.setDate(occStart.getDate() + spanDays) const occStartStr = toLocalString(occStart) const occEndStr = toLocalString(occEnd) occurrences.push({ ...baseEvent, - id: `${baseEvent.id}_repeat_${occIdx}_${targetWeekday}`, + id: `${baseEvent.id}_repeat_${occIdx}_${occStart.getDay()}`, startDate: occStartStr, endDate: occEndStr, isRepeatOccurrence: true, @@ -123,12 +133,15 @@ function generateRepeatOccurrencesForDate(targetDateStr) { if (maxOccurrences === 0) continue const i = intervalsPassed if (i >= maxOccurrences) continue - // Skip base occurrence - if (i === 0) continue const currentStart = new Date(baseStartDate) currentStart.setMonth(baseStartDate.getMonth() + i) const currentEnd = new Date(currentStart) currentEnd.setDate(currentStart.getDate() + spanDays) + // If target day lies within base (i===0) we skip because base is stored already + if (i === 0) { + // only skip if targetDate within base span + if (targetDate >= baseStartDate && targetDate <= baseEndDate) continue + } const currentStartStr = toLocalString(currentStart) const currentEndStr = toLocalString(currentEnd) if (currentStartStr <= targetDateStr && targetDateStr <= currentEndStr) {