diff --git a/src/pages/ChronoPage.vue b/src/pages/ChronoPage.vue index 2cb0604..bf468f5 100644 --- a/src/pages/ChronoPage.vue +++ b/src/pages/ChronoPage.vue @@ -62,18 +62,17 @@ const { editingCollection, collectionEditorMode, collectionEditorType, - isTaskView, + isTasksSection, } = storeToRefs(chronoUiStore); const { loadVisibleRange: loadVisibleRangeOperations } = chronoOperationsStore; const { initialize, - setViewMode, - setCurrentDate, - selectCalendar, + selectSection, + selectDate, + selectCollection, openEditCalendar, - selectTaskList, openEditTaskList, createEventFromDate, startEditingSelectedEntity, @@ -120,10 +119,10 @@ async function onFilesSelected(event: Event) { if (files.length) await openImport(files) } -function syncViewModeFromRoute() { +function selectSectionFromRoute() { const routePath = route.path; - const mode = routePath.endsWith('/tasks') ? 'tasks' : 'calendar'; - setViewMode(mode); + const section = routePath.endsWith('/tasks') ? 'tasks' : 'calendar'; + selectSection(section); } function handleCalendarViewChange(view: CalendarViewType) { @@ -150,16 +149,16 @@ watch( onMounted(async () => { try { - syncViewModeFromRoute(); - await initialize(isTaskView.value ? 'tasks' : 'calendar'); + selectSectionFromRoute(); + await initialize(isTasksSection.value ? 'tasks' : 'calendar'); } catch (error) { console.error('[Chrono] - Failed to load data from ChronoManager:', error); } }); watch(() => route.fullPath, async () => { - syncViewModeFromRoute(); - if (isTaskView.value) { + selectSectionFromRoute(); + if (isTasksSection.value) { await ensureTasksLoaded(); } }); @@ -187,7 +186,7 @@ watch(() => route.fullPath, async () => { route.fullPath, async () => { >
@@ -227,12 +226,12 @@ watch(() => route.fullPath, async () => { :collections="collections" :selected-collection="selectedCollection" type="tasklist" - @select="selectTaskList" + @select="selectCollection" @edit="openEditTaskList" /> route.fullPath, async () => { - + @@ -299,7 +298,7 @@ watch(() => route.fullPath, async () => { route.fullPath, async () => { :initial-agenda-view-span="agendaViewSpan" @event-click="editEvent" @date-click="createEventFromDate" - @update:current-date="setCurrentDate" + @update:current-date="selectDate" @update:days-span="setDaysViewSpan" @update:agenda-span="setAgendaViewSpan" /> diff --git a/src/stores/chronoOperationsStore.ts b/src/stores/chronoOperationsStore.ts index dfca603..55a80b7 100644 --- a/src/stores/chronoOperationsStore.ts +++ b/src/stores/chronoOperationsStore.ts @@ -11,6 +11,7 @@ import { useEntitiesStore } from '@ChronoManager/stores/entitiesStore' import { useServicesStore } from '@ChronoManager/stores/servicesStore' import { useImportStore } from '@ChronoManager/stores/importStore' import { EpochSpan } from '@/types/date' +import type { ChronoSection } from '@/types' type ChronoEntityProperties = EventObject | TaskObject @@ -162,7 +163,7 @@ export const useChronoOperationsStore = defineStore('chronoOperationsStore', () tasksLoaded.value = true } - async function initialize(viewMode: 'calendar' | 'tasks' = 'calendar') { + async function initialize(section: ChronoSection = 'calendar') { loading.value = true try { if (!collectionsLoaded.value) { @@ -171,7 +172,7 @@ export const useChronoOperationsStore = defineStore('chronoOperationsStore', () collectionsLoaded.value = true } - if (viewMode === 'tasks') { + if (section === 'tasks') { await ensureTasksLoaded() } diff --git a/src/stores/chronoUiStore.ts b/src/stores/chronoUiStore.ts index b25390f..7e9438b 100644 --- a/src/stores/chronoUiStore.ts +++ b/src/stores/chronoUiStore.ts @@ -5,12 +5,13 @@ import { EntityObject } from '@ChronoManager/models/entity' import { EventObject } from '@ChronoManager/models/event' import { TaskObject } from '@ChronoManager/models/task' import type { ServiceObject } from '@ChronoManager/models/service' +import type { ChronoSection } from '@/types' import { useChronoOperationsStore } from '@/stores/chronoOperationsStore' export const useChronoUiStore = defineStore('chronoUiStore', () => { const operationsStore = useChronoOperationsStore() - const viewMode = ref<'calendar' | 'tasks'>('calendar') + const section = ref('calendar') const currentDate = ref(new Date()) const sidebarVisible = ref(true) const selectedCollection = shallowRef(null) @@ -24,22 +25,18 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => { const collectionEditorMode = ref<'create' | 'edit'>('create') const collectionEditorType = ref<'calendar' | 'tasklist'>('calendar') - const isTaskView = computed(() => viewMode.value === 'tasks') + const isTasksSection = computed(() => section.value === 'tasks') - function setViewMode(mode: 'calendar' | 'tasks') { - viewMode.value = mode + function selectSection(target: ChronoSection) { + section.value = target } - function setCurrentDate(date: Date) { + function selectDate(date: Date) { currentDate.value = new Date(date) } - function selectCalendar(calendar: CollectionObject) { - selectedCollection.value = calendar - } - - function selectTaskList(list: CollectionObject) { - selectedCollection.value = list + function selectCollection(collection: CollectionObject) { + selectedCollection.value = collection } function openCollectionEditor(type: 'calendar' | 'tasklist') { @@ -193,8 +190,8 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => { await operationsStore.finishImport(refresh) } - async function initialize(viewMode: 'calendar' | 'tasks' = 'calendar') { - await operationsStore.initialize(viewMode) + async function initialize(initialSection: ChronoSection = 'calendar') { + await operationsStore.initialize(initialSection) if (selectedCollection.value && !operationsStore.collections.some( collection => collection.identifier === selectedCollection.value?.identifier, )) { @@ -203,7 +200,7 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => { } return { - viewMode, + section, currentDate, sidebarVisible, selectedCollection, @@ -216,11 +213,10 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => { editingCollection, collectionEditorMode, collectionEditorType, - isTaskView, - setViewMode, - setCurrentDate, - selectCalendar, - selectTaskList, + isTasksSection, + selectSection, + selectDate, + selectCollection, openCreateCalendar, openCreateTaskList, openEditCalendar, diff --git a/src/types/index.ts b/src/types/index.ts index 102da54..d094109 100644 --- a/src/types/index.ts +++ b/src/types/index.ts @@ -5,6 +5,7 @@ */ // Local UI-specific types +export type ChronoSection = 'calendar' | 'tasks'; export type CalendarView = 'days' | 'month' | 'agenda'; export interface ViewState { diff --git a/src/utils/recurrence.ts b/src/utils/recurrence.ts index e6ff998..e15958c 100644 --- a/src/utils/recurrence.ts +++ b/src/utils/recurrence.ts @@ -2,7 +2,6 @@ import type { EntityObject } from '@ChronoManager/models/entity' import type { EventObject } from '@ChronoManager/models/event' import type { EventMutationObject } from '@ChronoManager/models/event-mutation' import type { CalendarInstance } from '../types/instance' -import type { VisibleDateRange } from '../types' import { parseCalendarDate, shiftLocalDays, startOfLocalDay } from './date' import { EpochSpan } from '@/types/date' @@ -96,7 +95,7 @@ function materializeInstance( durationDays: number | null, recurring: boolean, mutation: EventMutationObject | undefined, - range?: VisibleDateRange, + range?: EpochSpan, ): CalendarInstance | null { if (mutation?.mutationExclusion === true) return null @@ -208,7 +207,7 @@ function expandWeekly( start: Date, durationMs: number, durationDays: number | null, - range: VisibleDateRange, + range: EpochSpan, mutations: Map, ): CalendarInstance[] { const pattern = (entity.properties as EventObject).pattern! @@ -227,13 +226,13 @@ function expandWeekly( while (true) { const intervalWeekStart = shiftLocalDays(weekStart, week * interval * 7) - if (intervalWeekStart.getTime() >= range.endMs) break + if (intervalWeekStart.getTime() >= range.end) break for (const weekday of weekdays) { const candidate = shiftLocalDays(intervalWeekStart, weekday - 1) const candidateMs = candidate.getTime() if (candidateMs < start.getTime()) continue - if (candidateMs >= range.endMs) return instances + if (candidateMs >= range.end) return instances if (concludesMs !== null && candidateMs > concludesMs) return instances occurrenceCount += 1 diff --git a/tests/js/unit/dateRanges.test.ts b/tests/js/unit/dateRanges.test.ts index d7272e3..e2876df 100644 --- a/tests/js/unit/dateRanges.test.ts +++ b/tests/js/unit/dateRanges.test.ts @@ -9,8 +9,8 @@ import { describe('calendar visible ranges', () => { it('uses a half-open range for a day span', () => { const range = daysVisibleRange(new Date(2026, 5, 15, 13, 45), 7) - const start = new Date(range.startMs) - const end = new Date(range.endMs) + const start = new Date(range.start) + const end = new Date(range.end) expect([start.getFullYear(), start.getMonth(), start.getDate(), start.getHours()]) .toEqual([2026, 5, 15, 0]) @@ -20,8 +20,8 @@ describe('calendar visible ranges', () => { it('uses calendar-day arithmetic across a daylight-saving boundary', () => { const range = daysVisibleRange(new Date(2026, 2, 8, 12), 1) - const start = new Date(range.startMs) - const end = new Date(range.endMs) + const start = new Date(range.start) + const end = new Date(range.end) expect(start.getHours()).toBe(0) expect(end.getHours()).toBe(0) @@ -30,8 +30,8 @@ describe('calendar visible ranges', () => { it('includes every leading and trailing day rendered by a month grid', () => { const range = monthGridVisibleRange(new Date(2026, 5, 15)) - const start = new Date(range.startMs) - const end = new Date(range.endMs) + const start = new Date(range.start) + const end = new Date(range.end) expect([start.getFullYear(), start.getMonth(), start.getDate()]).toEqual([2026, 4, 31]) expect([end.getFullYear(), end.getMonth(), end.getDate()]).toEqual([2026, 6, 5]) @@ -39,8 +39,8 @@ describe('calendar visible ranges', () => { it('calculates a leap-year February grid', () => { const range = monthGridVisibleRange(new Date(2024, 1, 29)) - const start = new Date(range.startMs) - const end = new Date(range.endMs) + const start = new Date(range.start) + const end = new Date(range.end) expect([start.getFullYear(), start.getMonth(), start.getDate()]).toEqual([2024, 0, 28]) expect([end.getFullYear(), end.getMonth(), end.getDate()]).toEqual([2024, 2, 3]) diff --git a/tests/js/unit/entityInstances.test.ts b/tests/js/unit/entityInstances.test.ts index ed002b7..22ead39 100644 --- a/tests/js/unit/entityInstances.test.ts +++ b/tests/js/unit/entityInstances.test.ts @@ -30,7 +30,7 @@ describe('entity instance expansion', () => { ) expect(instance.durationMs).toBe(60 * 60 * 1000) - expect(new Date(instance.startMs).getHours()).toBe(9) + expect(new Date(instance.start).getHours()).toBe(9) expect(new Date(instance.dayStartMs).getHours()).toBe(0) expect(instance.instanceId).toBeNull() expect(instance.multiDay).toBe(false) @@ -54,7 +54,7 @@ describe('entity instance expansion', () => { eventEntity('all-day', localIso(2026, 5, 20), localIso(2026, 5, 21), true), ) - const end = new Date(instance.endMs) + const end = new Date(instance.end) expect([end.getDate(), end.getHours()]).toEqual([21, 0]) expect(new Date(instance.dayStartMs).getDate()).toBe(20) expect(instance.multiDay).toBe(false) @@ -65,9 +65,9 @@ describe('entity instance expansion', () => { eventEntity('utc-all-day', '2025-03-27T00:00:00+00:00', '2025-03-28T00:00:00+00:00', true), ) - const start = new Date(instance.startMs) + const start = new Date(instance.start) expect([start.getMonth(), start.getDate(), start.getHours()]).toEqual([2, 27, 0]) - expect(new Date(instance.endMs).getDate()).toBe(28) + expect(new Date(instance.end).getDate()).toBe(28) }) it('gives a zero-duration event a queryable minimum duration', () => { diff --git a/tests/js/unit/recurrence.test.ts b/tests/js/unit/recurrence.test.ts index 67c1b16..9aa3864 100644 --- a/tests/js/unit/recurrence.test.ts +++ b/tests/js/unit/recurrence.test.ts @@ -39,7 +39,7 @@ describe('daily recurrence', () => { daysVisibleRange(new Date(2026, 5, 4), 6), ) - expect(instances.map(instance => new Date(instance.startMs).getDate())).toEqual([5, 7, 9]) + expect(instances.map(instance => new Date(instance.start).getDate())).toEqual([5, 7, 9]) expect(instances.every(instance => instance.durationMs === 60 * 60 * 1000)).toBe(true) expect(new Set(instances.map(instance => instance.key)).size).toBe(3) }) @@ -71,7 +71,7 @@ describe('daily recurrence', () => { daysVisibleRange(new Date(2026, 5, 1), 5), ) - expect(instances.map(instance => new Date(instance.startMs).getDate())).toEqual([1, 2, 3]) + expect(instances.map(instance => new Date(instance.start).getDate())).toEqual([1, 2, 3]) }) it('preserves local wall-clock time across daylight-saving changes', () => { @@ -85,7 +85,7 @@ describe('daily recurrence', () => { daysVisibleRange(new Date(2026, 2, 7), 3), ) - expect(instances.map(instance => new Date(instance.startMs).getHours())).toEqual([9, 9, 9]) + expect(instances.map(instance => new Date(instance.start).getHours())).toEqual([9, 9, 9]) }) it('preserves exclusive calendar-day duration for recurring timeless events', () => { @@ -107,9 +107,9 @@ describe('daily recurrence', () => { ) expect(instances).toHaveLength(3) - expect(instances.map(instance => new Date(instance.startMs).getHours())).toEqual([0, 0, 0]) + expect(instances.map(instance => new Date(instance.start).getHours())).toEqual([0, 0, 0]) expect(instances.map(instance => { - const end = new Date(instance.endMs) + const end = new Date(instance.end) return [end.getDate(), end.getHours()] })).toEqual([[8, 0], [9, 0], [10, 0]]) }) @@ -128,7 +128,7 @@ describe('weekly recurrence', () => { daysVisibleRange(new Date(2026, 5, 1), 10), ) - expect(instances.map(instance => new Date(instance.startMs).getDate())).toEqual([1, 3, 8, 10]) + expect(instances.map(instance => new Date(instance.start).getDate())).toEqual([1, 3, 8, 10]) }) }) @@ -150,7 +150,7 @@ describe('recurrence mutations', () => { daysVisibleRange(new Date(2026, 5, 1), 3), ) - expect(instances.map(instance => new Date(instance.startMs).getDate())).toEqual([1, 3]) + expect(instances.map(instance => new Date(instance.start).getDate())).toEqual([1, 3]) }) it('moves and restyles a modified occurrence without duplicating it', () => { @@ -178,7 +178,7 @@ describe('recurrence mutations', () => { const moved = instances.find(instance => instance.instanceId === sourceId) expect(instances).toHaveLength(2) - expect(new Date(moved!.startMs).getHours()).toBe(14) + expect(new Date(moved!.start).getHours()).toBe(14) expect(moved!.durationMs).toBe(2 * 60 * 60 * 1000) expect(moved!.label).toBe('Moved standup') expect(moved!.color).toBe('#abcdef')