From cd4ce6f69ef86f9ef3da598a147802a249d50da8 Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Mon, 25 Aug 2025 22:40:03 -0600 Subject: [PATCH] Refactor to use no of days instead of enddate on events. Other minor cleanup, larger date limits. --- src/components/EventDialog.vue | 11 +++++-- src/plugins/virtualWeeks.js | 46 +++++++++++++++++++---------- src/stores/CalendarStore.js | 54 +++++++++++++--------------------- src/utils/date.js | 9 ++---- 4 files changed, 63 insertions(+), 57 deletions(-) diff --git a/src/components/EventDialog.vue b/src/components/EventDialog.vue index 8e5777b..1f2e569 100644 --- a/src/components/EventDialog.vue +++ b/src/components/EventDialog.vue @@ -244,10 +244,16 @@ function openCreateDialog(selectionData = null) { recurrenceWeekdays.value[startingDay] = true initialWeekday.value = startingDay + let days = 1 + if (start && end && start <= end) { + const s = fromLocalString(start, DEFAULT_TZ) + const e = fromLocalString(end, DEFAULT_TZ) + days = Math.max(1, (e - s) / 86400000 + 1) + } editingEventId.value = calendarStore.createEvent({ title: '', startDate: start, - endDate: end, + days, colorId: colorId.value, recur: recurrenceEnabled.value && repeat.value !== 'none' @@ -306,7 +312,8 @@ function openEditDialog(payload) { if (event.recur.freq === 'weeks' && occurrenceIndex >= 0) { const pattern = event.recur.weekdays || [] const baseStart = fromLocalString(event.startDate, DEFAULT_TZ) - const baseEnd = fromLocalString(event.endDate, DEFAULT_TZ) + const baseEnd = new Date(fromLocalString(event.startDate, DEFAULT_TZ)) + baseEnd.setDate(baseEnd.getDate() + (event.days || 1) - 1) if (occurrenceIndex === 0) { occurrenceDate = baseStart weekday = baseStart.getDay() diff --git a/src/plugins/virtualWeeks.js b/src/plugins/virtualWeeks.js index 83c6131..6d73466 100644 --- a/src/plugins/virtualWeeks.js +++ b/src/plugins/virtualWeeks.js @@ -1,5 +1,5 @@ import { ref } from 'vue' -import { addDays, differenceInWeeks, differenceInCalendarDays } from 'date-fns' +import { addDays, differenceInWeeks } from 'date-fns' import { toLocalString, fromLocalString, @@ -72,19 +72,27 @@ export function createVirtualWeekManager({ const collectEventsForDate = (dateStr, curDateObj) => { const storedEvents = [] for (const ev of calendarStore.events.values()) { - if (!ev.recur && dateStr >= ev.startDate && dateStr <= ev.endDate) { - storedEvents.push(ev) + if (!ev.recur) { + const evEnd = toLocalString( + addDays(fromLocalString(ev.startDate, DEFAULT_TZ), (ev.days || 1) - 1), + DEFAULT_TZ, + ) + if (dateStr >= ev.startDate && dateStr <= evEnd) { + storedEvents.push({ ...ev, endDate: evEnd }) + } } } const dayEvents = [...storedEvents] for (const base of repeatingBases) { - if (dateStr >= base.startDate && dateStr <= base.endDate) { - dayEvents.push({ ...base, _recurrenceIndex: 0, _baseId: base.id }) + const baseEnd = toLocalString( + addDays(fromLocalString(base.startDate, DEFAULT_TZ), (base.days || 1) - 1), + DEFAULT_TZ, + ) + if (dateStr >= base.startDate && dateStr <= baseEnd) { + dayEvents.push({ ...base, endDate: baseEnd, _recurrenceIndex: 0, _baseId: base.id }) continue } - const baseStart = fromLocalString(base.startDate, DEFAULT_TZ) - const baseEnd = fromLocalString(base.endDate, DEFAULT_TZ) - const spanDays = Math.max(0, differenceInCalendarDays(baseEnd, baseStart)) + const spanDays = (base.days || 1) - 1 const currentDate = curDateObj let occurrenceFound = false for (let offset = 0; offset <= spanDays && !occurrenceFound; offset++) { @@ -303,19 +311,27 @@ export function createVirtualWeekManager({ // Rebuild events list for this day const storedEvents = [] for (const ev of calendarStore.events.values()) { - if (!ev.recur && dateStr >= ev.startDate && dateStr <= ev.endDate) { - storedEvents.push(ev) + if (!ev.recur) { + const evEnd = toLocalString( + addDays(fromLocalString(ev.startDate, DEFAULT_TZ), (ev.days || 1) - 1), + DEFAULT_TZ, + ) + if (dateStr >= ev.startDate && dateStr <= evEnd) { + storedEvents.push({ ...ev, endDate: evEnd }) + } } } const dayEvents = [...storedEvents] for (const base of repeatingBases) { - if (dateStr >= base.startDate && dateStr <= base.endDate) { - dayEvents.push({ ...base, _recurrenceIndex: 0, _baseId: base.id }) + const baseEndStr = toLocalString( + addDays(fromLocalString(base.startDate, DEFAULT_TZ), (base.days || 1) - 1), + DEFAULT_TZ, + ) + if (dateStr >= base.startDate && dateStr <= baseEndStr) { + dayEvents.push({ ...base, endDate: baseEndStr, _recurrenceIndex: 0, _baseId: base.id }) continue } - const baseStart = fromLocalString(base.startDate, DEFAULT_TZ) - const baseEnd = fromLocalString(base.endDate, DEFAULT_TZ) - const spanDays = Math.max(0, differenceInCalendarDays(baseEnd, baseStart)) + const spanDays = (base.days || 1) - 1 const currentDate = fromLocalString(dateStr, DEFAULT_TZ) let occurrenceFound = false for (let offset = 0; offset <= spanDays && !occurrenceFound; offset++) { diff --git a/src/stores/CalendarStore.js b/src/stores/CalendarStore.js index 763a978..5b5adab 100644 --- a/src/stores/CalendarStore.js +++ b/src/stores/CalendarStore.js @@ -127,14 +127,18 @@ export const useCalendarStore = defineStore('calendar', { }, createEvent(eventData) { - const singleDay = eventData.startDate === eventData.endDate + let days = 1 + if (typeof eventData.days === 'number') { + days = Math.max(1, Math.floor(eventData.days)) + } + const singleDay = days === 1 const event = { id: this.generateId(), title: eventData.title, startDate: eventData.startDate, - endDate: eventData.endDate, + days, colorId: - eventData.colorId ?? this.selectEventColorId(eventData.startDate, eventData.endDate), + eventData.colorId ?? this.selectEventColorId(eventData.startDate, eventData.startDate), startTime: singleDay ? eventData.startTime || '09:00' : null, durationMinutes: singleDay ? eventData.durationMinutes || 60 : null, recur: @@ -149,7 +153,7 @@ export const useCalendarStore = defineStore('calendar', { } : null, } - this.events.set(event.id, { ...event, isSpanning: event.startDate < event.endDate }) + this.events.set(event.id, { ...event, isSpanning: event.days > 1 }) this.notifyEventsChanged() return event.id }, @@ -164,7 +168,7 @@ export const useCalendarStore = defineStore('calendar', { const endDate = fromLocalString(endDateStr, DEFAULT_TZ) for (const ev of this.events.values()) { const evStart = fromLocalString(ev.startDate) - const evEnd = fromLocalString(ev.endDate) + const evEnd = addDays(evStart, (ev.days || 1) - 1) if (evEnd < startDate || evStart > endDate) continue if (ev.colorId >= 0 && ev.colorId < 8) colorCounts[ev.colorId]++ } @@ -202,17 +206,10 @@ export const useCalendarStore = defineStore('calendar', { this.deleteEvent(baseId) return } - const oldStart = fromLocalString(base.startDate, DEFAULT_TZ) - const oldEnd = fromLocalString(base.endDate, DEFAULT_TZ) - const durationDays = Math.max(0, differenceInCalendarDays(oldEnd, oldStart)) - const newEndStr = toLocalString( - addDays(fromLocalString(nextStartStr, DEFAULT_TZ), durationDays), - DEFAULT_TZ, - ) base.startDate = nextStartStr - base.endDate = newEndStr + // keep same days length if (numericCount !== Infinity) base.recur.count = String(Math.max(1, numericCount - 1)) - this.events.set(baseId, { ...base, isSpanning: base.startDate < base.endDate }) + this.events.set(baseId, { ...base, isSpanning: base.days > 1 }) this.notifyEventsChanged() }, @@ -234,14 +231,6 @@ export const useCalendarStore = defineStore('calendar', { base.recur.count = occurrenceIndex const nextStartStr = getOccurrenceDate(snapshot, occurrenceIndex + 1, DEFAULT_TZ) if (!nextStartStr) return - const durationDays = Math.max( - 0, - differenceInCalendarDays( - fromLocalString(snapshot.endDate), - fromLocalString(snapshot.startDate), - ), - ) - const newEndStr = toLocalString(addDays(fromLocalString(nextStartStr), durationDays)) const originalNumeric = snapshot.recur.count === 'unlimited' ? Infinity : parseInt(snapshot.recur.count, 10) let remainingCount = 'unlimited' @@ -253,7 +242,7 @@ export const useCalendarStore = defineStore('calendar', { this.createEvent({ title: snapshot.title, startDate: nextStartStr, - endDate: newEndStr, + days: snapshot.days, colorId: snapshot.colorId, recur: snapshot.recur ? { @@ -283,8 +272,7 @@ export const useCalendarStore = defineStore('calendar', { const snapshot = this.events.get(eventId) if (!snapshot) return const prevStart = fromLocalString(snapshot.startDate, DEFAULT_TZ) - const prevEnd = fromLocalString(snapshot.endDate, DEFAULT_TZ) - const prevDurationDays = Math.max(0, differenceInCalendarDays(prevEnd, prevStart)) + const prevDurationDays = (snapshot.days || 1) - 1 const newStart = fromLocalString(newStartStr, DEFAULT_TZ) const newEnd = fromLocalString(newEndStr, DEFAULT_TZ) const proposedDurationDays = Math.max(0, differenceInCalendarDays(newEnd, newStart)) @@ -292,10 +280,7 @@ export const useCalendarStore = defineStore('calendar', { if (mode === 'resize-left' || mode === 'resize-right') finalDurationDays = proposedDurationDays snapshot.startDate = newStartStr - snapshot.endDate = toLocalString( - addDays(fromLocalString(newStartStr, DEFAULT_TZ), finalDurationDays), - DEFAULT_TZ, - ) + snapshot.days = finalDurationDays + 1 if ( rotatePattern && (mode === 'move' || mode === 'resize-left') && @@ -310,7 +295,7 @@ export const useCalendarStore = defineStore('calendar', { snapshot.recur.weekdays = this._rotateWeekdayPattern(snapshot.recur.weekdays, shift) } } - this.events.set(eventId, { ...snapshot, isSpanning: snapshot.startDate < snapshot.endDate }) + this.events.set(eventId, { ...snapshot, isSpanning: snapshot.days > 1 }) this.notifyEventsChanged() }, @@ -398,7 +383,7 @@ export const useCalendarStore = defineStore('calendar', { const newId = this.createEvent({ title: base.title, startDate: newStartStr, - endDate: newEndStr, + days: base.days, colorId: base.colorId, recur: { freq: base.recur.freq, @@ -430,7 +415,7 @@ export const useCalendarStore = defineStore('calendar', { return newId }, - splitRepeatSeries(baseId, occurrenceIndex, newStartStr, newEndStr) { + splitRepeatSeries(baseId, occurrenceIndex, newStartStr, _newEndStr) { const base = this.events.get(baseId) if (!base || !base.recur) return null const originalCountRaw = base.recur.count @@ -446,7 +431,7 @@ export const useCalendarStore = defineStore('calendar', { return this.createEvent({ title: base.title, startDate: newStartStr, - endDate: newEndStr, + days: base.days, colorId: base.colorId, recur: base.recur ? { @@ -484,11 +469,12 @@ export const useCalendarStore = defineStore('calendar', { }) }, deserialize(value) { - return JSON.parse(value, (_k, v) => { + const revived = JSON.parse(value, (_k, v) => { if (v && v.__map) return new Map(v.data) if (v && v.__set) return new Set(v.data) return v }) + return revived }, }, }, diff --git a/src/utils/date.js b/src/utils/date.js index c5d7c17..3449e57 100644 --- a/src/utils/date.js +++ b/src/utils/date.js @@ -23,9 +23,8 @@ const monthAbbr = [ 'nov', 'dec', ] -// Calendar year bounds (used instead of config.min_year / config.max_year) -const MIN_YEAR = 1901 -const MAX_YEAR = 2100 +const MIN_YEAR = 100 // less than 100 is interpreted as 19xx +const MAX_YEAR = 9999 // Core helpers ------------------------------------------------------------ /** @@ -230,9 +229,7 @@ function getOccurrenceDate(event, occurrenceIndex, timeZone = DEFAULT_TZ) { } function getVirtualOccurrenceEndDate(event, occurrenceStartDate, timeZone = DEFAULT_TZ) { - const baseStart = fromLocalString(event.startDate, timeZone) - const baseEnd = fromLocalString(event.endDate, timeZone) - const spanDays = Math.max(0, dateFns.differenceInCalendarDays(baseEnd, baseStart)) + const spanDays = Math.max(0, (event.days || 1) - 1) const occurrenceStart = fromLocalString(occurrenceStartDate, timeZone) return toLocalString(dateFns.addDays(occurrenceStart, spanDays), timeZone) }