import { create } from 'zustand'; import type { CalendarTask } from '@/lib/jmap/types'; import type { IJMAPClient } from '@/lib/jmap/client-interface'; import { debug } from '@/lib/debug'; import { enqueueOperation, isNetworkError } from '@/lib/offline-write-queue'; import { useAccountStore } from '@/stores/account-store'; export type TaskViewFilter = 'all' | 'pending' | 'completed' | 'overdue'; interface TaskStore { tasks: CalendarTask[]; selectedTaskId: string | null; filter: TaskViewFilter; showCompleted: boolean; isLoading: boolean; error: string | null; setTasks: (tasks: CalendarTask[]) => void; setSelectedTaskId: (id: string | null) => void; setFilter: (filter: TaskViewFilter) => void; setShowCompleted: (show: boolean) => void; fetchTasks: (client: IJMAPClient, calendarIds?: string[]) => Promise; createTask: (client: IJMAPClient, task: Partial) => Promise; updateTask: (client: IJMAPClient, id: string, updates: Partial) => Promise; deleteTask: (client: IJMAPClient, id: string) => Promise; toggleTaskComplete: (client: IJMAPClient, task: CalendarTask) => Promise; clearTasks: () => void; } export const useTaskStore = create((set, get) => ({ tasks: [], selectedTaskId: null, filter: 'all', showCompleted: false, isLoading: false, error: null, setTasks: (tasks) => set({ tasks }), setSelectedTaskId: (id) => set({ selectedTaskId: id }), setFilter: (filter) => set({ filter }), setShowCompleted: (show) => set({ showCompleted: show }), fetchTasks: async (client, calendarIds) => { debug.log('tasks', 'TaskStore/fetchTasks start', { calendarIds: calendarIds || 'all' }); set({ isLoading: true, error: null }); try { const tasks = await client.getCalendarTasks(calendarIds); debug.log('tasks', 'TaskStore/fetchTasks received', tasks.length, 'tasks'); tasks.forEach((t, i) => { debug.log('tasks', `TaskStore/fetchTasks [${i}]`, { id: t.id, uid: t.uid, '@type': t['@type'], title: t.title, due: t.due, progress: t.progress, showWithoutTime: t.showWithoutTime, calendarIds: t.calendarIds, }); }); set({ tasks, isLoading: false }); } catch (error) { debug.error('TaskStore/fetchTasks failed', error); set({ isLoading: false, error: 'Failed to fetch tasks' }); } }, createTask: async (client, task) => { debug.log('tasks', 'TaskStore/createTask', task); try { const created = await client.createCalendarTask(task); debug.log('tasks', 'TaskStore/createTask result', { id: created.id, uid: created.uid, title: created.title }); set({ tasks: [...get().tasks, created] }); return created; } catch (error) { debug.error('TaskStore/createTask failed', error); if (isNetworkError(error)) { const accountId = useAccountStore.getState().activeAccountId; if (accountId) { enqueueOperation({ type: 'createTask', accountId, payload: task }); } } set({ error: 'Failed to create task' }); throw error; } }, updateTask: async (client, id, updates) => { try { await client.updateCalendarTask(id, updates); set({ tasks: get().tasks.map(t => t.id === id ? { ...t, ...updates, updated: new Date().toISOString() } : t), }); } catch (error) { debug.error('TaskStore/updateTask failed', error); if (isNetworkError(error)) { const accountId = useAccountStore.getState().activeAccountId; if (accountId) { enqueueOperation({ type: 'updateTask', accountId, payload: { id, updates } }); } } set({ error: 'Failed to update task' }); } }, deleteTask: async (client, id) => { try { await client.deleteCalendarTask(id); set({ tasks: get().tasks.filter(t => t.id !== id), selectedTaskId: get().selectedTaskId === id ? null : get().selectedTaskId, }); } catch (error) { debug.error('TaskStore/deleteTask failed', error); if (isNetworkError(error)) { const accountId = useAccountStore.getState().activeAccountId; if (accountId) { enqueueOperation({ type: 'deleteTask', accountId, payload: { id } }); } } set({ error: 'Failed to delete task' }); } }, toggleTaskComplete: async (client, task) => { try { const newProgress = task.progress === 'completed' ? 'needs-action' : 'completed'; const updates: Partial = { progress: newProgress, progressUpdated: new Date().toISOString(), }; await client.updateCalendarTask(task.id, updates); set({ tasks: get().tasks.map(t => t.id === task.id ? { ...t, ...updates, updated: new Date().toISOString() } : t), }); } catch (error) { debug.error('TaskStore/toggleTaskComplete failed', error); set({ error: 'Failed to update task' }); } }, clearTasks: () => set({ tasks: [], selectedTaskId: null, error: null }), }));