A little better but still broken. I need easier tasks for a while.

This commit is contained in:
Leo Vasanko
2025-08-22 22:08:35 -06:00
parent 02442f5135
commit 8caaf33cb9
4 changed files with 345 additions and 216 deletions

View File

@@ -13,6 +13,9 @@ import {
daysInclusive,
addDaysStr,
formatDateRange,
getMondayOfISOWeek,
getOccurrenceIndex,
getVirtualOccurrenceEndDate,
} from '@/utils/date'
import { toLocalString, fromLocalString } from '@/utils/date'
@@ -153,25 +156,11 @@ function createWeek(virtualWeek) {
for (let i = 0; i < 7; i++) {
const dateStr = toLocalString(cur)
const storedEvents = []
const idSet = calendarStore.dates.get(dateStr)
if (idSet) {
// Support Set or Array; ignore unexpected shapes
if (idSet instanceof Set) {
idSet.forEach((id) => {
const ev = calendarStore.events.get(id)
if (ev) storedEvents.push(ev)
})
} else if (Array.isArray(idSet)) {
for (const id of idSet) {
const ev = calendarStore.events.get(id)
if (ev) storedEvents.push(ev)
}
} else if (typeof idSet === 'object' && idSet !== null) {
// If mistakenly hydrated as plain object {id:true,...}
for (const id of Object.keys(idSet)) {
const ev = calendarStore.events.get(id)
if (ev) storedEvents.push(ev)
}
// Find all non-repeating events that occur on this date
for (const ev of calendarStore.events.values()) {
if (!ev.isRepeating && dateStr >= ev.startDate && dateStr <= ev.endDate) {
storedEvents.push(ev)
}
}
// Build day events starting with stored (base/spanning) then virtual occurrences
@@ -179,56 +168,45 @@ function createWeek(virtualWeek) {
for (const base of repeatingBases) {
// Skip if the base itself already on this date (already in storedEvents)
if (dateStr >= base.startDate && dateStr <= base.endDate) continue
if (calendarStore.occursOnDate(base, dateStr)) {
// Determine sequential occurrence index: base event = 0, first repeat = 1, etc.
let recurrenceIndex = 0
try {
if (base.repeat === 'weeks') {
const pattern = base.repeatWeekdays || []
const interval = base.repeatInterval || 1
const baseStart = new Date(base.startDate + 'T00:00:00')
const baseEnd = new Date(base.endDate + 'T00:00:00')
const target = new Date(dateStr + 'T00:00:00')
const WEEK_MS = 7 * 86400000
const baseBlockStart = new Date(baseStart)
baseBlockStart.setDate(baseStart.getDate() - baseStart.getDay())
function isAligned(d) {
const blk = new Date(d)
blk.setDate(d.getDate() - d.getDay())
const diff = Math.floor((blk - baseBlockStart) / WEEK_MS)
return diff % interval === 0
// Check if any occurrence of this repeating event spans through this date
const baseStart = fromLocalString(base.startDate)
const baseEnd = fromLocalString(base.endDate)
const spanDays = Math.max(0, Math.round((baseEnd - baseStart) / (24 * 60 * 60 * 1000)))
const currentDate = fromLocalString(dateStr)
let occurrenceFound = false
// Check dates going backwards to find an occurrence that might span to this date
for (let offset = 0; offset <= spanDays && !occurrenceFound; offset++) {
const candidateStart = new Date(currentDate)
candidateStart.setDate(candidateStart.getDate() - offset)
const candidateStartStr = toLocalString(candidateStart)
const occurrenceIndex = getOccurrenceIndex(base, candidateStartStr)
if (occurrenceIndex !== null) {
// Calculate the end date of this occurrence
const virtualEndDate = getVirtualOccurrenceEndDate(base, candidateStartStr)
// Check if this occurrence spans through the current date
if (dateStr >= candidateStartStr && dateStr <= virtualEndDate) {
// Create virtual occurrence (if not already created)
const virtualId = base.id + '_v_' + candidateStartStr
const alreadyExists = dayEvents.some((ev) => ev.id === virtualId)
if (!alreadyExists) {
dayEvents.push({
...base,
id: virtualId,
startDate: candidateStartStr,
endDate: virtualEndDate,
_recurrenceIndex: occurrenceIndex,
_baseId: base.id,
})
}
// Count valid occurrences after base end and before target
let count = 0
const cursor = new Date(baseEnd)
cursor.setDate(cursor.getDate() + 1)
while (cursor < target) {
if (pattern[cursor.getDay()] && isAligned(cursor)) count++
cursor.setDate(cursor.getDate() + 1)
}
// Target itself is guaranteed valid (occursOnDate passed), so its index is count+1
recurrenceIndex = count + 1
} else if (base.repeat === 'months') {
const baseStart = new Date(base.startDate + 'T00:00:00')
const target = new Date(dateStr + 'T00:00:00')
const interval = base.repeatInterval || 1
const diffMonths =
(target.getFullYear() - baseStart.getFullYear()) * 12 +
(target.getMonth() - baseStart.getMonth())
// diffMonths should be multiple of interval; sequential index = diffMonths/interval
recurrenceIndex = diffMonths / interval
occurrenceFound = true
}
} catch {
recurrenceIndex = 0
}
dayEvents.push({
...base,
id: base.id + '_v_' + dateStr,
startDate: dateStr,
endDate: dateStr,
_recurrenceIndex: recurrenceIndex,
_baseId: base.id,
})
}
}
const dow = cur.getDay()

View File

@@ -3,7 +3,7 @@ import { useCalendarStore } from '@/stores/CalendarStore'
import { ref, computed, watch, onMounted, onUnmounted, nextTick } from 'vue'
import WeekdaySelector from './WeekdaySelector.vue'
import Numeric from './Numeric.vue'
import { addDaysStr } from '@/utils/date'
import { addDaysStr, getMondayOfISOWeek } from '@/utils/date'
const props = defineProps({
selection: { type: Object, default: () => ({ startDate: null, dayCount: 0 }) },
@@ -173,11 +173,9 @@ function openEditDialog(payload) {
// Count valid repeat occurrences (pattern + interval alignment) AFTER the base span
const interval = event.repeatInterval || 1
const WEEK_MS = 7 * 86400000
const baseBlockStart = new Date(baseStart)
baseBlockStart.setDate(baseStart.getDate() - baseStart.getDay())
const baseBlockStart = getMondayOfISOWeek(baseStart)
function isAligned(d) {
const blk = new Date(d)
blk.setDate(d.getDate() - d.getDay())
const blk = getMondayOfISOWeek(d)
const diff = Math.floor((blk - baseBlockStart) / WEEK_MS)
return diff % interval === 0
}