150 lines
4.4 KiB
TypeScript
150 lines
4.4 KiB
TypeScript
import { create } from 'zustand';
|
|
import type { Task, TaskCreate, TaskUpdate, Project, Label, User } from '@/types';
|
|
import { api } from '@/lib/api';
|
|
|
|
interface TasksState {
|
|
tasks: Task[];
|
|
completedTasks: Task[];
|
|
projects: Project[];
|
|
labels: Label[];
|
|
users: User[];
|
|
isLoading: boolean;
|
|
|
|
// Selected items
|
|
selectedTask: Task | null;
|
|
activeProjectId: string | null;
|
|
activeView: 'inbox' | 'today' | 'upcoming' | 'project' | 'label';
|
|
|
|
// Actions
|
|
fetchTasks: (params?: Parameters<typeof api.getTasks>[0]) => Promise<void>;
|
|
fetchCompletedTasks: (params?: Parameters<typeof api.getTasks>[0]) => Promise<void>;
|
|
fetchProjects: () => Promise<void>;
|
|
fetchLabels: () => Promise<void>;
|
|
fetchUsers: () => Promise<void>;
|
|
|
|
createTask: (data: TaskCreate) => Promise<Task>;
|
|
updateTask: (id: string, data: TaskUpdate) => Promise<void>;
|
|
deleteTask: (id: string) => Promise<void>;
|
|
toggleComplete: (id: string) => Promise<void>;
|
|
createProject: (data: { name: string; color?: string; icon?: string }) => Promise<Project>;
|
|
|
|
setSelectedTask: (task: Task | null) => void;
|
|
setActiveProject: (projectId: string | null) => void;
|
|
setActiveView: (view: TasksState['activeView']) => void;
|
|
}
|
|
|
|
export const useTasksStore = create<TasksState>((set, get) => ({
|
|
tasks: [],
|
|
completedTasks: [],
|
|
projects: [],
|
|
labels: [],
|
|
users: [],
|
|
isLoading: false,
|
|
selectedTask: null,
|
|
activeProjectId: null,
|
|
activeView: 'inbox',
|
|
|
|
fetchTasks: async (params) => {
|
|
set({ isLoading: true });
|
|
try {
|
|
const tasks = await api.getTasks(params);
|
|
set({ tasks, isLoading: false });
|
|
} catch (error) {
|
|
console.error('Failed to fetch tasks:', error);
|
|
set({ isLoading: false });
|
|
}
|
|
},
|
|
|
|
fetchCompletedTasks: async (params) => {
|
|
try {
|
|
const completedTasks = await api.getTasks({ ...params, completed: true });
|
|
set({ completedTasks });
|
|
} catch (error) {
|
|
console.error('Failed to fetch completed tasks:', error);
|
|
}
|
|
},
|
|
|
|
fetchProjects: async () => {
|
|
try {
|
|
const projects = await api.getProjects();
|
|
set({ projects });
|
|
} catch (error) {
|
|
console.error('Failed to fetch projects:', error);
|
|
}
|
|
},
|
|
|
|
fetchLabels: async () => {
|
|
try {
|
|
const labels = await api.getLabels();
|
|
set({ labels });
|
|
} catch (error) {
|
|
console.error('Failed to fetch labels:', error);
|
|
}
|
|
},
|
|
|
|
fetchUsers: async () => {
|
|
try {
|
|
const users = await api.getUsers();
|
|
set({ users });
|
|
} catch (error) {
|
|
console.error('Failed to fetch users:', error);
|
|
}
|
|
},
|
|
|
|
createTask: async (data) => {
|
|
const task = await api.createTask(data);
|
|
set((state) => ({ tasks: [task, ...state.tasks] }));
|
|
return task;
|
|
},
|
|
|
|
updateTask: async (id, data) => {
|
|
const updated = await api.updateTask(id, data);
|
|
set((state) => ({
|
|
tasks: state.tasks.map((t) => (t.id === id ? { ...t, ...updated } : t)),
|
|
selectedTask: state.selectedTask?.id === id
|
|
? { ...state.selectedTask, ...updated }
|
|
: state.selectedTask,
|
|
}));
|
|
},
|
|
|
|
deleteTask: async (id) => {
|
|
await api.deleteTask(id);
|
|
set((state) => ({
|
|
tasks: state.tasks.filter((t) => t.id !== id),
|
|
selectedTask: state.selectedTask?.id === id ? null : state.selectedTask,
|
|
}));
|
|
},
|
|
|
|
createProject: async (data) => {
|
|
const project = await api.createProject(data);
|
|
set((state) => ({ projects: [...state.projects, project] }));
|
|
return project;
|
|
},
|
|
|
|
toggleComplete: async (id) => {
|
|
const task = get().tasks.find((t) => t.id === id) || get().completedTasks.find((t) => t.id === id);
|
|
if (!task) return;
|
|
|
|
const updated = await api.updateTask(id, { isCompleted: !task.isCompleted });
|
|
const updatedTask = { ...task, isCompleted: !task.isCompleted, completedAt: updated.completedAt };
|
|
|
|
if (updatedTask.isCompleted) {
|
|
// Move from tasks to completedTasks
|
|
set((state) => ({
|
|
tasks: state.tasks.filter((t) => t.id !== id),
|
|
completedTasks: [updatedTask, ...state.completedTasks],
|
|
}));
|
|
} else {
|
|
// Move from completedTasks to tasks
|
|
set((state) => ({
|
|
tasks: [updatedTask, ...state.tasks],
|
|
completedTasks: state.completedTasks.filter((t) => t.id !== id),
|
|
}));
|
|
}
|
|
},
|
|
|
|
setSelectedTask: (task) => set({ selectedTask: task }),
|
|
setActiveProject: (projectId) => set({ activeProjectId: projectId }),
|
|
setActiveView: (view) => set({ activeView: view }),
|
|
}));
|