import { writable, derived } from 'svelte/store'; import { tasks as tasksAPI } from '$lib/api/endpoints.js'; import { queueChange } from '$lib/utils/sync-queue.js'; /** * @typedef {import('$lib/api/types.js').Task} Task * @typedef {import('$lib/api/types.js').TaskFilters} TaskFilters */ /** * Create tasks store */ function createTasksStore() { const { subscribe, set, update } = writable(/** @type {Task[]} */ ([])); return { subscribe, /** * Load all tasks from API * @param {TaskFilters} [filters] */ async load(filters = {}) { try { const tasks = await tasksAPI.list(filters); set(tasks); } catch (error) { console.error('Failed to load tasks:', error); throw error; } }, /** * Add new task (optimistic update) * @param {Partial} task */ async add(task) { try { const created = await tasksAPI.create(task); update(tasks => [...tasks, created]); return created; } catch (error) { // Queue for offline sync queueChange({ type: 'create', task_uuid: task.uuid, data: task }); // Still update UI optimistically update(tasks => [...tasks, task]); throw error; } }, /** * Update task (optimistic update) * @param {string} uuid * @param {Partial} updates */ async updateTask(uuid, updates) { // Optimistic update update(tasks => { const index = tasks.findIndex(t => t.uuid === uuid); if (index >= 0) { tasks[index] = { ...tasks[index], ...updates, modified: Date.now() / 1000 }; } return tasks; }); try { const updated = await tasksAPI.update(uuid, updates); // Sync with server response update(tasks => { const index = tasks.findIndex(t => t.uuid === uuid); if (index >= 0) { tasks[index] = updated; } return tasks; }); } catch (error) { // Queue for offline sync queueChange({ type: 'update', task_uuid: uuid, data: updates }); throw error; } }, /** * Delete task * @param {string} uuid */ async deleteTask(uuid) { // Optimistic removal update(tasks => tasks.filter(t => t.uuid !== uuid)); try { await tasksAPI.delete(uuid); } catch (error) { queueChange({ type: 'delete', task_uuid: uuid, data: {} }); throw error; } }, /** * Complete task * @param {string} uuid */ async complete(uuid) { try { const completed = await tasksAPI.complete(uuid); update(tasks => { const index = tasks.findIndex(t => t.uuid === uuid); if (index >= 0) { tasks[index] = completed; } return tasks; }); } catch (error) { queueChange({ type: 'update', task_uuid: uuid, data: { status: 'C', end: Date.now() / 1000 } }); throw error; } } }; } export const tasksStore = createTasksStore(); // Derived stores for filtered views export const pendingTasks = derived( tasksStore, $tasks => $tasks.filter(t => t.status === 'P') ); export const completedTasks = derived( tasksStore, $tasks => $tasks.filter(t => t.status === 'C') ); export const tasksByProject = derived( tasksStore, $tasks => { const grouped = {}; $tasks.forEach(task => { const project = task.project || 'No Project'; if (!grouped[project]) grouped[project] = []; grouped[project].push(task); }); return grouped; } );