Initial commit - Todo app frontend

This commit is contained in:
2026-01-28 16:46:44 +00:00
commit 95b816a2e6
15978 changed files with 2514406 additions and 0 deletions

108
src/stores/tasks.ts Normal file
View File

@@ -0,0 +1,108 @@
import { create } from 'zustand';
import type { Task, TaskCreate, TaskUpdate, Project, Label } from '@/types';
import { api } from '@/lib/api';
interface TasksState {
tasks: Task[];
projects: Project[];
labels: Label[];
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>;
fetchProjects: () => Promise<void>;
fetchLabels: () => Promise<void>;
createTask: (data: TaskCreate) => Promise<Task>;
updateTask: (id: string, data: TaskUpdate) => Promise<void>;
deleteTask: (id: string) => Promise<void>;
toggleComplete: (id: string) => Promise<void>;
setSelectedTask: (task: Task | null) => void;
setActiveProject: (projectId: string | null) => void;
setActiveView: (view: TasksState['activeView']) => void;
}
export const useTasksStore = create<TasksState>((set, get) => ({
tasks: [],
projects: [],
labels: [],
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 });
}
},
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);
}
},
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,
}));
},
toggleComplete: async (id) => {
const task = get().tasks.find((t) => t.id === id);
if (!task) return;
const updated = await api.updateTask(id, { isCompleted: !task.isCompleted });
set((state) => ({
tasks: state.tasks.map((t) =>
t.id === id ? { ...t, isCompleted: !task.isCompleted, completedAt: updated.completedAt } : t
),
}));
},
setSelectedTask: (task) => set({ selectedTask: task }),
setActiveProject: (projectId) => set({ activeProjectId: projectId }),
setActiveView: (view) => set({ activeView: view }),
}));