Files

249 lines
5.6 KiB
TypeScript

/**
* 📝 Tasks Store (Zustand)
* Gerenciador de estado das tarefas
*/
import { create } from 'zustand';
import apiClient, { handleApiError } from '../api';
import {
TasksState,
Task,
CreateTaskPayload,
UpdateTaskPayload,
TaskFilters,
TasksListResponse,
TaskStatsResponse,
} from '../types';
interface TasksStore extends TasksState {
// Ações
fetchTasks: (filters?: TaskFilters) => Promise<void>;
fetchStats: () => Promise<void>;
createTask: (payload: CreateTaskPayload) => Promise<Task | null>;
updateTask: (id: string, payload: UpdateTaskPayload) => Promise<Task | null>;
deleteTask: (id: string) => Promise<boolean>;
setFilters: (filters: TaskFilters) => void;
setError: (error: string | null) => void;
setLoading: (loading: boolean) => void;
clear: () => void;
}
/**
* Criar store de tarefas
*/
export const useTasksStore = create<TasksStore>((set, get) => ({
// Estado inicial
tasks: [],
stats: null,
isLoading: false,
error: null,
filters: {
completed: undefined,
sortBy: 'created_at',
order: 'desc',
},
// ============================================================================
// AÇÕES
// ============================================================================
/**
* Buscar tarefas com filtros
*/
fetchTasks: async (filters?: TaskFilters) => {
try {
set({ isLoading: true, error: null });
if (filters) {
set({ filters });
}
const currentFilters = filters || get().filters;
const params = new URLSearchParams();
if (currentFilters.completed !== undefined) {
params.append('completed', String(currentFilters.completed));
}
if (currentFilters.category) {
params.append('category', currentFilters.category);
}
if (currentFilters.priority) {
params.append('priority', currentFilters.priority);
}
if (currentFilters.sortBy) {
params.append('sortBy', currentFilters.sortBy);
}
if (currentFilters.order) {
params.append('order', currentFilters.order);
}
const url = `/tasks${params.toString() ? '?' + params.toString() : ''}`;
const response = await apiClient.get<TasksListResponse>(url);
set({
tasks: response.data.data,
isLoading: false,
});
} catch (error) {
const message = handleApiError(error);
set({ error: message, isLoading: false, tasks: [] });
}
},
/**
* Buscar estatísticas
*/
fetchStats: async () => {
try {
const response = await apiClient.get<TaskStatsResponse>('/tasks/stats');
set({ stats: response.data.data });
} catch (error) {
console.error('Erro ao buscar estatísticas:', error);
}
},
/**
* Criar tarefa
*/
createTask: async (payload: CreateTaskPayload) => {
try {
set({ isLoading: true, error: null });
const response = await apiClient.post<{ data: Task }>('/tasks', payload);
const newTask = response.data.data;
// Adicionar à lista
set({ tasks: [newTask, ...get().tasks] });
// Atualizar stats se houver
if (get().stats) {
await get().fetchStats();
}
return newTask;
} catch (error) {
const message = handleApiError(error);
set({ error: message });
throw new Error(message);
} finally {
set({ isLoading: false });
}
},
/**
* Atualizar tarefa
*/
updateTask: async (id: string, payload: UpdateTaskPayload) => {
try {
set({ isLoading: true, error: null });
const response = await apiClient.patch<{ data: Task }>(
`/tasks/${id}`,
payload,
);
const updatedTask = response.data.data;
// Atualizar na lista
set({
tasks: get().tasks.map((t) => (t.id === id ? updatedTask : t)),
});
// Atualizar stats se houver
if (get().stats) {
await get().fetchStats();
}
return updatedTask;
} catch (error) {
const message = handleApiError(error);
set({ error: message });
throw new Error(message);
} finally {
set({ isLoading: false });
}
},
/**
* Deletar tarefa
*/
deleteTask: async (id: string) => {
try {
set({ isLoading: true, error: null });
await apiClient.delete(`/tasks/${id}`);
// Remover da lista
set({ tasks: get().tasks.filter((t) => t.id !== id) });
// Atualizar stats se houver
if (get().stats) {
await get().fetchStats();
}
return true;
} catch (error) {
const message = handleApiError(error);
set({ error: message });
return false;
} finally {
set({ isLoading: false });
}
},
/**
* Setar filtros
*/
setFilters: (filters: TaskFilters) => {
set({ filters });
},
/**
* Setar erro
*/
setError: (error: string | null) => {
set({ error });
},
/**
* Setar loading
*/
setLoading: (isLoading: boolean) => {
set({ isLoading });
},
/**
* Limpar estado
*/
clear: () => {
set({
tasks: [],
stats: null,
isLoading: false,
error: null,
filters: {
completed: undefined,
sortBy: 'created_at',
order: 'desc',
},
});
},
}));
// Hook customizado
export const useTasks = () => {
const store = useTasksStore();
return {
tasks: store.tasks,
stats: store.stats,
isLoading: store.isLoading,
error: store.error,
filters: store.filters,
fetchTasks: store.fetchTasks,
fetchStats: store.fetchStats,
createTask: store.createTask,
updateTask: store.updateTask,
deleteTask: store.deleteTask,
setFilters: store.setFilters,
};
};