refactor: code clean up

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-07-06 22:42:31 -04:00
parent df531908f3
commit 3c0ea698b1
8 changed files with 62 additions and 66 deletions
+19 -20
View File
@@ -62,18 +62,17 @@ const {
editingCollection, editingCollection,
collectionEditorMode, collectionEditorMode,
collectionEditorType, collectionEditorType,
isTaskView, isTasksSection,
} = storeToRefs(chronoUiStore); } = storeToRefs(chronoUiStore);
const { loadVisibleRange: loadVisibleRangeOperations } = chronoOperationsStore; const { loadVisibleRange: loadVisibleRangeOperations } = chronoOperationsStore;
const { const {
initialize, initialize,
setViewMode, selectSection,
setCurrentDate, selectDate,
selectCalendar, selectCollection,
openEditCalendar, openEditCalendar,
selectTaskList,
openEditTaskList, openEditTaskList,
createEventFromDate, createEventFromDate,
startEditingSelectedEntity, startEditingSelectedEntity,
@@ -120,10 +119,10 @@ async function onFilesSelected(event: Event) {
if (files.length) await openImport(files) if (files.length) await openImport(files)
} }
function syncViewModeFromRoute() { function selectSectionFromRoute() {
const routePath = route.path; const routePath = route.path;
const mode = routePath.endsWith('/tasks') ? 'tasks' : 'calendar'; const section = routePath.endsWith('/tasks') ? 'tasks' : 'calendar';
setViewMode(mode); selectSection(section);
} }
function handleCalendarViewChange(view: CalendarViewType) { function handleCalendarViewChange(view: CalendarViewType) {
@@ -150,16 +149,16 @@ watch(
onMounted(async () => { onMounted(async () => {
try { try {
syncViewModeFromRoute(); selectSectionFromRoute();
await initialize(isTaskView.value ? 'tasks' : 'calendar'); await initialize(isTasksSection.value ? 'tasks' : 'calendar');
} catch (error) { } catch (error) {
console.error('[Chrono] - Failed to load data from ChronoManager:', error); console.error('[Chrono] - Failed to load data from ChronoManager:', error);
} }
}); });
watch(() => route.fullPath, async () => { watch(() => route.fullPath, async () => {
syncViewModeFromRoute(); selectSectionFromRoute();
if (isTaskView.value) { if (isTasksSection.value) {
await ensureTasksLoaded(); await ensureTasksLoaded();
} }
}); });
@@ -187,7 +186,7 @@ watch(() => route.fullPath, async () => {
<!-- View Switcher for Calendar --> <!-- View Switcher for Calendar -->
<v-btn-toggle <v-btn-toggle
v-if="!isTaskView" v-if="!isTasksSection"
:model-value="calendarView" :model-value="calendarView"
color="primary" color="primary"
variant="outlined" variant="outlined"
@@ -214,11 +213,11 @@ watch(() => route.fullPath, async () => {
> >
<div class="pa-4"> <div class="pa-4">
<CollectionList <CollectionList
v-if="!isTaskView" v-if="!isTasksSection"
:collections="collections" :collections="collections"
:selected-collection="selectedCollection" :selected-collection="selectedCollection"
type="calendar" type="calendar"
@select="selectCalendar" @select="selectCollection"
@edit="openEditCalendar" @edit="openEditCalendar"
@toggle-visibility="toggleCalendarVisibility" @toggle-visibility="toggleCalendarVisibility"
/> />
@@ -227,12 +226,12 @@ watch(() => route.fullPath, async () => {
:collections="collections" :collections="collections"
:selected-collection="selectedCollection" :selected-collection="selectedCollection"
type="tasklist" type="tasklist"
@select="selectTaskList" @select="selectCollection"
@edit="openEditTaskList" @edit="openEditTaskList"
/> />
<v-btn <v-btn
v-if="!isTaskView" v-if="!isTasksSection"
variant="tonal" variant="tonal"
color="primary" color="primary"
block block
@@ -262,7 +261,7 @@ watch(() => route.fullPath, async () => {
<input ref="fileInputRef" type="file" accept=".ics,text/calendar" multiple class="d-none" @change="onFilesSelected" /> <input ref="fileInputRef" type="file" accept=".ics,text/calendar" multiple class="d-none" @change="onFilesSelected" />
<!-- Mini Calendar Widget --> <!-- Mini Calendar Widget -->
<v-card v-if="!isTaskView" class="mt-4" variant="outlined"> <v-card v-if="!isTasksSection" class="mt-4" variant="outlined">
<v-card-text class="pa-2"> <v-card-text class="pa-2">
<MiniCalendar v-model="currentDate" /> <MiniCalendar v-model="currentDate" />
</v-card-text> </v-card-text>
@@ -299,7 +298,7 @@ watch(() => route.fullPath, async () => {
<v-progress-linear v-if="loading" indeterminate color="primary" /> <v-progress-linear v-if="loading" indeterminate color="primary" />
<CalendarView <CalendarView
v-if="!isTaskView" v-if="!isTasksSection"
:view="calendarView" :view="calendarView"
:current-date="currentDate" :current-date="currentDate"
:calendars="calendars" :calendars="calendars"
@@ -307,7 +306,7 @@ watch(() => route.fullPath, async () => {
:initial-agenda-view-span="agendaViewSpan" :initial-agenda-view-span="agendaViewSpan"
@event-click="editEvent" @event-click="editEvent"
@date-click="createEventFromDate" @date-click="createEventFromDate"
@update:current-date="setCurrentDate" @update:current-date="selectDate"
@update:days-span="setDaysViewSpan" @update:days-span="setDaysViewSpan"
@update:agenda-span="setAgendaViewSpan" @update:agenda-span="setAgendaViewSpan"
/> />
+3 -2
View File
@@ -11,6 +11,7 @@ import { useEntitiesStore } from '@ChronoManager/stores/entitiesStore'
import { useServicesStore } from '@ChronoManager/stores/servicesStore' import { useServicesStore } from '@ChronoManager/stores/servicesStore'
import { useImportStore } from '@ChronoManager/stores/importStore' import { useImportStore } from '@ChronoManager/stores/importStore'
import { EpochSpan } from '@/types/date' import { EpochSpan } from '@/types/date'
import type { ChronoSection } from '@/types'
type ChronoEntityProperties = EventObject | TaskObject type ChronoEntityProperties = EventObject | TaskObject
@@ -162,7 +163,7 @@ export const useChronoOperationsStore = defineStore('chronoOperationsStore', ()
tasksLoaded.value = true tasksLoaded.value = true
} }
async function initialize(viewMode: 'calendar' | 'tasks' = 'calendar') { async function initialize(section: ChronoSection = 'calendar') {
loading.value = true loading.value = true
try { try {
if (!collectionsLoaded.value) { if (!collectionsLoaded.value) {
@@ -171,7 +172,7 @@ export const useChronoOperationsStore = defineStore('chronoOperationsStore', ()
collectionsLoaded.value = true collectionsLoaded.value = true
} }
if (viewMode === 'tasks') { if (section === 'tasks') {
await ensureTasksLoaded() await ensureTasksLoaded()
} }
+15 -19
View File
@@ -5,12 +5,13 @@ import { EntityObject } from '@ChronoManager/models/entity'
import { EventObject } from '@ChronoManager/models/event' import { EventObject } from '@ChronoManager/models/event'
import { TaskObject } from '@ChronoManager/models/task' import { TaskObject } from '@ChronoManager/models/task'
import type { ServiceObject } from '@ChronoManager/models/service' import type { ServiceObject } from '@ChronoManager/models/service'
import type { ChronoSection } from '@/types'
import { useChronoOperationsStore } from '@/stores/chronoOperationsStore' import { useChronoOperationsStore } from '@/stores/chronoOperationsStore'
export const useChronoUiStore = defineStore('chronoUiStore', () => { export const useChronoUiStore = defineStore('chronoUiStore', () => {
const operationsStore = useChronoOperationsStore() const operationsStore = useChronoOperationsStore()
const viewMode = ref<'calendar' | 'tasks'>('calendar') const section = ref<ChronoSection>('calendar')
const currentDate = ref(new Date()) const currentDate = ref(new Date())
const sidebarVisible = ref(true) const sidebarVisible = ref(true)
const selectedCollection = shallowRef<CollectionObject | null>(null) const selectedCollection = shallowRef<CollectionObject | null>(null)
@@ -24,22 +25,18 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => {
const collectionEditorMode = ref<'create' | 'edit'>('create') const collectionEditorMode = ref<'create' | 'edit'>('create')
const collectionEditorType = ref<'calendar' | 'tasklist'>('calendar') const collectionEditorType = ref<'calendar' | 'tasklist'>('calendar')
const isTaskView = computed(() => viewMode.value === 'tasks') const isTasksSection = computed(() => section.value === 'tasks')
function setViewMode(mode: 'calendar' | 'tasks') { function selectSection(target: ChronoSection) {
viewMode.value = mode section.value = target
} }
function setCurrentDate(date: Date) { function selectDate(date: Date) {
currentDate.value = new Date(date) currentDate.value = new Date(date)
} }
function selectCalendar(calendar: CollectionObject) { function selectCollection(collection: CollectionObject) {
selectedCollection.value = calendar selectedCollection.value = collection
}
function selectTaskList(list: CollectionObject) {
selectedCollection.value = list
} }
function openCollectionEditor(type: 'calendar' | 'tasklist') { function openCollectionEditor(type: 'calendar' | 'tasklist') {
@@ -193,8 +190,8 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => {
await operationsStore.finishImport(refresh) await operationsStore.finishImport(refresh)
} }
async function initialize(viewMode: 'calendar' | 'tasks' = 'calendar') { async function initialize(initialSection: ChronoSection = 'calendar') {
await operationsStore.initialize(viewMode) await operationsStore.initialize(initialSection)
if (selectedCollection.value && !operationsStore.collections.some( if (selectedCollection.value && !operationsStore.collections.some(
collection => collection.identifier === selectedCollection.value?.identifier, collection => collection.identifier === selectedCollection.value?.identifier,
)) { )) {
@@ -203,7 +200,7 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => {
} }
return { return {
viewMode, section,
currentDate, currentDate,
sidebarVisible, sidebarVisible,
selectedCollection, selectedCollection,
@@ -216,11 +213,10 @@ export const useChronoUiStore = defineStore('chronoUiStore', () => {
editingCollection, editingCollection,
collectionEditorMode, collectionEditorMode,
collectionEditorType, collectionEditorType,
isTaskView, isTasksSection,
setViewMode, selectSection,
setCurrentDate, selectDate,
selectCalendar, selectCollection,
selectTaskList,
openCreateCalendar, openCreateCalendar,
openCreateTaskList, openCreateTaskList,
openEditCalendar, openEditCalendar,
+1
View File
@@ -5,6 +5,7 @@
*/ */
// Local UI-specific types // Local UI-specific types
export type ChronoSection = 'calendar' | 'tasks';
export type CalendarView = 'days' | 'month' | 'agenda'; export type CalendarView = 'days' | 'month' | 'agenda';
export interface ViewState { export interface ViewState {
+4 -5
View File
@@ -2,7 +2,6 @@ import type { EntityObject } from '@ChronoManager/models/entity'
import type { EventObject } from '@ChronoManager/models/event' import type { EventObject } from '@ChronoManager/models/event'
import type { EventMutationObject } from '@ChronoManager/models/event-mutation' import type { EventMutationObject } from '@ChronoManager/models/event-mutation'
import type { CalendarInstance } from '../types/instance' import type { CalendarInstance } from '../types/instance'
import type { VisibleDateRange } from '../types'
import { parseCalendarDate, shiftLocalDays, startOfLocalDay } from './date' import { parseCalendarDate, shiftLocalDays, startOfLocalDay } from './date'
import { EpochSpan } from '@/types/date' import { EpochSpan } from '@/types/date'
@@ -96,7 +95,7 @@ function materializeInstance(
durationDays: number | null, durationDays: number | null,
recurring: boolean, recurring: boolean,
mutation: EventMutationObject | undefined, mutation: EventMutationObject | undefined,
range?: VisibleDateRange, range?: EpochSpan,
): CalendarInstance | null { ): CalendarInstance | null {
if (mutation?.mutationExclusion === true) return null if (mutation?.mutationExclusion === true) return null
@@ -208,7 +207,7 @@ function expandWeekly(
start: Date, start: Date,
durationMs: number, durationMs: number,
durationDays: number | null, durationDays: number | null,
range: VisibleDateRange, range: EpochSpan,
mutations: Map<number, EventMutationObject>, mutations: Map<number, EventMutationObject>,
): CalendarInstance[] { ): CalendarInstance[] {
const pattern = (entity.properties as EventObject).pattern! const pattern = (entity.properties as EventObject).pattern!
@@ -227,13 +226,13 @@ function expandWeekly(
while (true) { while (true) {
const intervalWeekStart = shiftLocalDays(weekStart, week * interval * 7) const intervalWeekStart = shiftLocalDays(weekStart, week * interval * 7)
if (intervalWeekStart.getTime() >= range.endMs) break if (intervalWeekStart.getTime() >= range.end) break
for (const weekday of weekdays) { for (const weekday of weekdays) {
const candidate = shiftLocalDays(intervalWeekStart, weekday - 1) const candidate = shiftLocalDays(intervalWeekStart, weekday - 1)
const candidateMs = candidate.getTime() const candidateMs = candidate.getTime()
if (candidateMs < start.getTime()) continue if (candidateMs < start.getTime()) continue
if (candidateMs >= range.endMs) return instances if (candidateMs >= range.end) return instances
if (concludesMs !== null && candidateMs > concludesMs) return instances if (concludesMs !== null && candidateMs > concludesMs) return instances
occurrenceCount += 1 occurrenceCount += 1
+8 -8
View File
@@ -9,8 +9,8 @@ import {
describe('calendar visible ranges', () => { describe('calendar visible ranges', () => {
it('uses a half-open range for a day span', () => { it('uses a half-open range for a day span', () => {
const range = daysVisibleRange(new Date(2026, 5, 15, 13, 45), 7) const range = daysVisibleRange(new Date(2026, 5, 15, 13, 45), 7)
const start = new Date(range.startMs) const start = new Date(range.start)
const end = new Date(range.endMs) const end = new Date(range.end)
expect([start.getFullYear(), start.getMonth(), start.getDate(), start.getHours()]) expect([start.getFullYear(), start.getMonth(), start.getDate(), start.getHours()])
.toEqual([2026, 5, 15, 0]) .toEqual([2026, 5, 15, 0])
@@ -20,8 +20,8 @@ describe('calendar visible ranges', () => {
it('uses calendar-day arithmetic across a daylight-saving boundary', () => { it('uses calendar-day arithmetic across a daylight-saving boundary', () => {
const range = daysVisibleRange(new Date(2026, 2, 8, 12), 1) const range = daysVisibleRange(new Date(2026, 2, 8, 12), 1)
const start = new Date(range.startMs) const start = new Date(range.start)
const end = new Date(range.endMs) const end = new Date(range.end)
expect(start.getHours()).toBe(0) expect(start.getHours()).toBe(0)
expect(end.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', () => { it('includes every leading and trailing day rendered by a month grid', () => {
const range = monthGridVisibleRange(new Date(2026, 5, 15)) const range = monthGridVisibleRange(new Date(2026, 5, 15))
const start = new Date(range.startMs) const start = new Date(range.start)
const end = new Date(range.endMs) const end = new Date(range.end)
expect([start.getFullYear(), start.getMonth(), start.getDate()]).toEqual([2026, 4, 31]) expect([start.getFullYear(), start.getMonth(), start.getDate()]).toEqual([2026, 4, 31])
expect([end.getFullYear(), end.getMonth(), end.getDate()]).toEqual([2026, 6, 5]) 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', () => { it('calculates a leap-year February grid', () => {
const range = monthGridVisibleRange(new Date(2024, 1, 29)) const range = monthGridVisibleRange(new Date(2024, 1, 29))
const start = new Date(range.startMs) const start = new Date(range.start)
const end = new Date(range.endMs) const end = new Date(range.end)
expect([start.getFullYear(), start.getMonth(), start.getDate()]).toEqual([2024, 0, 28]) expect([start.getFullYear(), start.getMonth(), start.getDate()]).toEqual([2024, 0, 28])
expect([end.getFullYear(), end.getMonth(), end.getDate()]).toEqual([2024, 2, 3]) expect([end.getFullYear(), end.getMonth(), end.getDate()]).toEqual([2024, 2, 3])
+4 -4
View File
@@ -30,7 +30,7 @@ describe('entity instance expansion', () => {
) )
expect(instance.durationMs).toBe(60 * 60 * 1000) 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(new Date(instance.dayStartMs).getHours()).toBe(0)
expect(instance.instanceId).toBeNull() expect(instance.instanceId).toBeNull()
expect(instance.multiDay).toBe(false) 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), 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([end.getDate(), end.getHours()]).toEqual([21, 0])
expect(new Date(instance.dayStartMs).getDate()).toBe(20) expect(new Date(instance.dayStartMs).getDate()).toBe(20)
expect(instance.multiDay).toBe(false) 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), 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([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', () => { it('gives a zero-duration event a queryable minimum duration', () => {
+8 -8
View File
@@ -39,7 +39,7 @@ describe('daily recurrence', () => {
daysVisibleRange(new Date(2026, 5, 4), 6), 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(instances.every(instance => instance.durationMs === 60 * 60 * 1000)).toBe(true)
expect(new Set(instances.map(instance => instance.key)).size).toBe(3) 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), 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', () => { it('preserves local wall-clock time across daylight-saving changes', () => {
@@ -85,7 +85,7 @@ describe('daily recurrence', () => {
daysVisibleRange(new Date(2026, 2, 7), 3), 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', () => { it('preserves exclusive calendar-day duration for recurring timeless events', () => {
@@ -107,9 +107,9 @@ describe('daily recurrence', () => {
) )
expect(instances).toHaveLength(3) 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 => { expect(instances.map(instance => {
const end = new Date(instance.endMs) const end = new Date(instance.end)
return [end.getDate(), end.getHours()] return [end.getDate(), end.getHours()]
})).toEqual([[8, 0], [9, 0], [10, 0]]) })).toEqual([[8, 0], [9, 0], [10, 0]])
}) })
@@ -128,7 +128,7 @@ describe('weekly recurrence', () => {
daysVisibleRange(new Date(2026, 5, 1), 10), 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), 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', () => { 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) const moved = instances.find(instance => instance.instanceId === sourceId)
expect(instances).toHaveLength(2) 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!.durationMs).toBe(2 * 60 * 60 * 1000)
expect(moved!.label).toBe('Moved standup') expect(moved!.label).toBe('Moved standup')
expect(moved!.color).toBe('#abcdef') expect(moved!.color).toBe('#abcdef')