Files
webmail/stores/task-store.ts
T
Linus Rath c633185cda Merge branch 'main' into feat/stalwart-1.0
# Conflicts:
#	CONTRIBUTING.md
#	LICENSE
#	README.md
#	app/api/calendar-agenda/route.ts
#	app/api/wopi/files/[fileId]/contents/route.ts
#	app/api/wopi/launch/route.ts
#	components/calendar/calendar-app.tsx
#	components/calendar/calendar-day-view.tsx
#	components/calendar/calendar-month-view.tsx
#	components/calendar/calendar-week-view.tsx
#	components/calendar/event-modal.tsx
#	components/contacts/contact-detail.tsx
#	components/email/email-composer.tsx
#	components/email/email-list.tsx
#	components/files/file-browser.tsx
#	components/files/files-app.tsx
#	components/files/folder-tree-sidebar.tsx
#	components/filters/filter-rule-modal.tsx
#	components/mail/mail-app.tsx
#	hooks/use-mailbox-drop.ts
#	integration/run-tests.sh
#	lib/__tests__/calendar-agenda-route.test.ts
#	lib/__tests__/jmap-draft-lifecycle.test.ts
#	lib/__tests__/web-push.test.ts
#	lib/account-state-manager.ts
#	lib/jmap/client-interface.ts
#	lib/jmap/client.ts
#	lib/jmap/types.ts
#	lib/message-list-order.ts
#	lib/sieve/generator.ts
#	lib/sieve/parser.ts
#	lib/telemetry/payload.ts
#	lib/thread-utils.ts
#	lib/unified-mailbox.ts
#	lib/web-push.ts
#	lib/wopi/token.ts
#	locales/ar/common.json
#	locales/ca/common.json
#	locales/cs/common.json
#	locales/da/common.json
#	locales/de/common.json
#	locales/en/common.json
#	locales/es/common.json
#	locales/fa/common.json
#	locales/fr/common.json
#	locales/he/common.json
#	locales/hu/common.json
#	locales/it/common.json
#	locales/ja/common.json
#	locales/ko/common.json
#	locales/lv/common.json
#	locales/mn/common.json
#	locales/nb/common.json
#	locales/nl/common.json
#	locales/pl/common.json
#	locales/pt/common.json
#	locales/ro/common.json
#	locales/ru/common.json
#	locales/sk/common.json
#	locales/tr/common.json
#	locales/uk/common.json
#	locales/zh-TW/common.json
#	locales/zh/common.json
#	scripts/lite/lib.mjs
#	stores/__tests__/calendar-store-synthetic-ids.test.ts
#	stores/__tests__/email-store-shared-folder-keywords.test.ts
#	stores/__tests__/email-store-unified-actions.test.ts
#	stores/__tests__/file-store.test.ts
#	stores/email-store.ts
#	stores/file-store.ts
#	stores/message-list-tabs-store.ts
2026-10-12 08:35:08 +02:00

108 lines
4.0 KiB
TypeScript

import { create } from 'zustand';
import type { CalendarTask } from '@/lib/jmap/types';
import type { IJMAPClient } from '@/lib/jmap/client-interface';
import { debug } from '@/lib/debug';
export type TaskViewFilter = 'all' | 'pending' | 'completed' | 'overdue';
/**
* The `error` a failed task load leaves. The tasks loaded before stay; the
* task list shows a notice for it.
*/
export const TASKS_LOAD_ERROR = 'Failed to fetch tasks';
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<void>;
createTask: (client: IJMAPClient, task: Partial<CalendarTask>) => Promise<CalendarTask>;
updateTask: (client: IJMAPClient, id: string, updates: Partial<CalendarTask>) => Promise<void>;
deleteTask: (client: IJMAPClient, id: string) => Promise<void>;
toggleTaskComplete: (client: IJMAPClient, task: CalendarTask) => Promise<void>;
clearTasks: () => void;
}
export const useTaskStore = create<TaskStore>((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: TASKS_LOAD_ERROR });
}
},
createTask: async (client, task) => {
debug.log('tasks', 'TaskStore/createTask', task);
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;
},
updateTask: async (client, id, updates) => {
const newId = await client.updateCalendarTask(id, updates);
if (newId && newId !== id) {
// Moved into a calendar of another account: the server recreated it
// under a new id, so reload rather than patch the old entry. (#1204)
set({ selectedTaskId: get().selectedTaskId === id ? newId : get().selectedTaskId });
await get().fetchTasks(client);
return;
}
set({
tasks: get().tasks.map(t => t.id === id ? { ...t, ...updates, updated: new Date().toISOString() } : t),
});
},
deleteTask: async (client, id) => {
await client.deleteCalendarTask(id);
set({
tasks: get().tasks.filter(t => t.id !== id),
selectedTaskId: get().selectedTaskId === id ? null : get().selectedTaskId,
});
},
toggleTaskComplete: async (client, task) => {
const newProgress = task.progress === 'completed' ? 'needs-action' : 'completed';
const updates: Partial<CalendarTask> = {
progress: newProgress,
};
await client.updateCalendarTask(task.id, updates);
set({
tasks: get().tasks.map(t => t.id === task.id ? { ...t, ...updates, updated: new Date().toISOString() } : t),
});
},
clearTasks: () => set({ tasks: [], selectedTaskId: null, error: null }),
}));