import { computed, ref, shallowRef } from 'vue' import { defineStore } from 'pinia' import { CollectionObject } from '@ChronoManager/models/collection' 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 { useCollectionsStore } from '@ChronoManager/stores/collectionsStore' import { useEntitiesStore } from '@ChronoManager/stores/entitiesStore' import { useServicesStore } from '@ChronoManager/stores/servicesStore' import { useImportStore } from '@ChronoManager/stores/importStore' import type { VisibleDateRange } from '@/types' type ChronoEntityProperties = EventObject | TaskObject export const useChronoOperationsStore = defineStore('chronoOperationsStore', () => { const servicesStore = useServicesStore() const collectionsStore = useCollectionsStore() const entitiesStore = useEntitiesStore() const importStore = useImportStore() const loading = ref(false) const visibleRange = shallowRef(null) const collections = computed(() => collectionsStore.collections) const entities = computed(() => entitiesStore.entities) const calendars = computed(() => collections.value.filter( collection => collection.properties.content?.includes('event'), )) const taskLists = computed(() => collections.value.filter( collection => collection.properties.content?.includes('task'), )) const events = computed(() => entities.value.filter( entity => entity.properties instanceof EventObject, )) const tasks = computed(() => entities.value.filter( entity => entity.properties instanceof TaskObject, )) const filteredEvents = computed(() => { const visibleCalendarIds = calendars.value .filter(calendar => calendar.properties.visibility !== false) .map(calendar => calendar.identifier) return events.value.filter(event => visibleCalendarIds.includes(event.collection)) }) const filteredTasks = computed(() => tasks.value) function setVisibleRange(range: VisibleDateRange) { if ( visibleRange.value?.startMs === range.startMs && visibleRange.value.endMs === range.endMs ) { return } visibleRange.value = { ...range } } function prepareEntityProperties(entity: EntityObject): ChronoEntityProperties { const properties = entity.properties as ChronoEntityProperties const now = new Date().toISOString() properties.modified = now as never if (!entity.identifier) { properties.created = now as never } return properties } async function saveEntity(entity: EntityObject, collection: CollectionObject): Promise { const properties = prepareEntityProperties(entity).toJson() return entity.identifier ? entitiesStore.update(entity.identifier, properties) : entitiesStore.create(collection.identifier, properties) } async function deleteEntity(entity: EntityObject) { await entitiesStore.delete([entity.identifier]) } async function toggleCalendarVisibility(collection: CollectionObject) { const updated = collection.clone() updated.properties.visibility = collection.properties.visibility === false await collectionsStore.update(updated.identifier, updated.properties) } async function toggleTaskComplete(taskId: string | number) { const taskEntity = tasks.value.find(task => task.identifier === taskId) if (!taskEntity) return const taskData = taskEntity.properties as TaskObject const isCompleted = taskData.status === 'completed' taskData.status = isCompleted ? 'needs-action' : 'completed' taskData.completedOn = isCompleted ? null : new Date().toISOString() as never taskData.progress = isCompleted ? null : 100 taskData.modified = new Date().toISOString() as never await entitiesStore.update(taskEntity.identifier, taskData.toJson()) } async function saveCollection( collection: CollectionObject, service: ServiceObject, mode: 'create' | 'edit', ) { if (mode === 'create') { await collectionsStore.create(service.provider, service.identifier || '', collection.properties) return } await collectionsStore.update(collection.identifier, collection.properties) } async function deleteCollection(collection: CollectionObject) { await collectionsStore.delete(collection.identifier) } async function prepareImport(files: File[], selectedCollection: CollectionObject | null) { importStore.removeAllFiles() importStore.reset() for (const file of files) { const id = importStore.addFile({ name: file.name, contents: await file.text(), size: file.size, type: file.type, }) if (selectedCollection && collections.value.some( collection => collection.identifier === selectedCollection.identifier, )) { importStore.setCollectionForFile(id, selectedCollection.identifier) } } importStore.stage = 'selecting' } async function finishImport(refresh = false) { if (refresh) { const targets = new Set() for (const id of importStore.order) { const target = importStore.sessions[id]?.targetIdentifier if (target) targets.add(target) } for (const target of targets) await entitiesStore.list([target]) } importStore.removeAllFiles() importStore.reset() } async function initialize() { loading.value = true try { await servicesStore.list() await collectionsStore.list() const sources = collections.value.map(collection => collection.identifier) if (sources.length > 0) await entitiesStore.list(sources) } finally { loading.value = false } } return { loading, visibleRange, collections, entities, calendars, taskLists, events, tasks, filteredEvents, filteredTasks, setVisibleRange, saveEntity, deleteEntity, toggleCalendarVisibility, toggleTaskComplete, saveCollection, deleteCollection, prepareImport, finishImport, initialize, } })