Files
ftb-project-management/apps/web/stores/useTaskWorklogStore.ts
2026-07-03 19:36:18 +08:00

72 lines
2.3 KiB
TypeScript

'use client';
import { create } from 'zustand';
import type { TaskWorklog } from '@/lib/task-worklog';
import { scheduleSaveWithOptimisticRollback } from '@/lib/optimistic-persistence';
import { loadServerData, saveServerData, SERVER_DATA_CACHE_MS } from '@/lib/server-data';
let lastWorklogsFetchAt = 0;
async function loadStored(): Promise<TaskWorklog[] | null> {
try {
return await loadServerData<TaskWorklog[]>('task-worklogs');
} catch {}
return null;
}
interface TaskWorklogState {
worklogs: TaskWorklog[];
loaded: boolean;
fetchWorklogs: (options?: { force?: boolean }) => Promise<void>;
addWorklog: (data: Omit<TaskWorklog, 'id' | 'createdAt'>) => void;
deleteWorklog: (id: string) => void;
getActualHours: (taskId: string) => number;
}
export const useTaskWorklogStore = create<TaskWorklogState>((set, get) => ({
worklogs: [],
loaded: false,
fetchWorklogs: async (options) => {
if (!options?.force && get().loaded && Date.now() - lastWorklogsFetchAt < SERVER_DATA_CACHE_MS) return;
const cached = await loadStored();
if (!options?.force && get().loaded && Date.now() - lastWorklogsFetchAt < SERVER_DATA_CACHE_MS) return;
lastWorklogsFetchAt = Date.now();
set({ worklogs: cached ?? [], loaded: true });
},
addWorklog: (data) => {
const previous = get().worklogs;
const item: TaskWorklog = {
...data,
id: `wl-${Date.now()}`,
createdAt: new Date().toISOString(),
};
const updated = [...previous, item];
set({ worklogs: updated, loaded: true });
scheduleSaveWithOptimisticRollback({
save: () => saveServerData('task-worklogs', updated),
expected: updated,
getCurrent: () => get().worklogs,
rollback: () => set({ worklogs: previous, loaded: true }),
});
},
deleteWorklog: (id) => {
const previous = get().worklogs;
const updated = previous.filter((w) => w.id !== id);
set({ worklogs: updated, loaded: true });
scheduleSaveWithOptimisticRollback({
save: () => saveServerData('task-worklogs', updated),
expected: updated,
getCurrent: () => get().worklogs,
rollback: () => set({ worklogs: previous, loaded: true }),
});
},
getActualHours: (taskId) => {
return get().worklogs
.filter((w) => w.taskId === taskId)
.reduce((sum, w) => sum + w.hours, 0);
},
}));