import { defineStore } from 'pinia' import type { TimeEntry } from '~/services/dto/time-entry' import type { Task } from '~/services/dto/task' import { useTimeEntryService } from '~/services/time-entries' export const useTimerStore = defineStore('timer', () => { const activeEntry = ref(null) const pendingCompleteEntry = ref(null) const now = ref(Date.now()) let intervalId: ReturnType | null = null const isRunning = computed(() => activeEntry.value !== null) const elapsed = computed(() => { if (!activeEntry.value) return 0 const start = new Date(activeEntry.value.startedAt).getTime() return Math.floor((now.value - start) / 1000) }) const elapsedFormatted = computed(() => { const total = elapsed.value const h = Math.floor(total / 3600) const m = Math.floor((total % 3600) / 60) const s = total % 60 return [h, m, s].map((v) => String(v).padStart(2, '0')).join(':') }) function startTicking() { stopTicking() now.value = Date.now() intervalId = setInterval(() => { now.value = Date.now() }, 1000) } function stopTicking() { if (intervalId) { clearInterval(intervalId) intervalId = null } } async function fetchActive() { const { getActive } = useTimeEntryService() activeEntry.value = await getActive() if (activeEntry.value) { startTicking() } else { stopTicking() } } async function start() { const authStore = useAuthStore() if (!authStore.user) return if (isRunning.value) { await stop() } const { create } = useTimeEntryService() activeEntry.value = await create({ startedAt: new Date().toISOString(), user: `/api/users/${authStore.user.id}`, }) startTicking() } function toIri(entity: T | string, prefix: string): string { if (typeof entity === 'string') return entity return entity['@id'] ?? `${prefix}/${entity.id}` } async function startFromTask(task: Task) { const authStore = useAuthStore() if (!authStore.user) return if (isRunning.value) { await stop() } const { create } = useTimeEntryService() activeEntry.value = await create({ startedAt: new Date().toISOString(), user: `/api/users/${authStore.user.id}`, title: task.title, project: task.project ? toIri(task.project, '/api/projects') : null, task: toIri(task, '/api/tasks'), tags: task.tags?.map(t => toIri(t, '/api/task_tags')) ?? [], }) startTicking() } async function stop() { if (!activeEntry.value) return const wasEmpty = !activeEntry.value.task const { update } = useTimeEntryService() const stoppedEntry = await update(activeEntry.value.id, { stoppedAt: new Date().toISOString(), }) activeEntry.value = null stopTicking() if (wasEmpty) { pendingCompleteEntry.value = stoppedEntry } } function clearPendingEntry() { pendingCompleteEntry.value = null } return { activeEntry, pendingCompleteEntry, isRunning, elapsed, elapsedFormatted, fetchActive, start, startFromTask, stop, clearPendingEntry, } })