133 lines
3.7 KiB
TypeScript
133 lines
3.7 KiB
TypeScript
|
|
/**
|
||
|
|
* Tasks API hooks — CRUD, assign, status update.
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||
|
|
import { apiGet, apiPost, apiPatch, apiDelete } from './client';
|
||
|
|
|
||
|
|
export interface Task {
|
||
|
|
id: string;
|
||
|
|
title: string;
|
||
|
|
description: string | null;
|
||
|
|
status: 'open' | 'in_progress' | 'done';
|
||
|
|
priority: 'low' | 'medium' | 'high' | 'urgent';
|
||
|
|
due_date: string | null;
|
||
|
|
assigned_to: string | null;
|
||
|
|
contact_id: string | null;
|
||
|
|
created_by: string | null;
|
||
|
|
created_at: string;
|
||
|
|
updated_at: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TaskListResponse {
|
||
|
|
items: Task[];
|
||
|
|
total: number;
|
||
|
|
page: number;
|
||
|
|
page_size: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TaskCreateInput {
|
||
|
|
title: string;
|
||
|
|
description?: string | null;
|
||
|
|
status?: string;
|
||
|
|
priority?: string;
|
||
|
|
due_date?: string | null;
|
||
|
|
assigned_to?: string | null;
|
||
|
|
contact_id?: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TaskUpdateInput {
|
||
|
|
title?: string;
|
||
|
|
description?: string | null;
|
||
|
|
status?: string;
|
||
|
|
priority?: string;
|
||
|
|
due_date?: string | null;
|
||
|
|
assigned_to?: string | null;
|
||
|
|
contact_id?: string | null;
|
||
|
|
}
|
||
|
|
|
||
|
|
export interface TaskFilter {
|
||
|
|
status?: string;
|
||
|
|
priority?: string;
|
||
|
|
assigned_to?: string;
|
||
|
|
contact_id?: string;
|
||
|
|
search?: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useTasks(page = 1, pageSize = 25, filter?: TaskFilter) {
|
||
|
|
const params = new URLSearchParams({ page: String(page), page_size: String(pageSize) });
|
||
|
|
if (filter?.status) params.set('status', filter.status);
|
||
|
|
if (filter?.priority) params.set('priority', filter.priority);
|
||
|
|
if (filter?.assigned_to) params.set('assigned_to', filter.assigned_to);
|
||
|
|
if (filter?.contact_id) params.set('contact_id', filter.contact_id);
|
||
|
|
if (filter?.search) params.set('search', filter.search);
|
||
|
|
return useQuery({
|
||
|
|
queryKey: ['tasks', page, pageSize, filter],
|
||
|
|
queryFn: () => apiGet<TaskListResponse>(`/tasks?${params.toString()}`),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useTask(id?: string) {
|
||
|
|
return useQuery({
|
||
|
|
queryKey: ['tasks', id],
|
||
|
|
queryFn: () => apiGet<Task>(`/tasks/${id}`),
|
||
|
|
enabled: !!id,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useCreateTask() {
|
||
|
|
const queryClient = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: (data: TaskCreateInput) => apiPost<Task>('/tasks', data),
|
||
|
|
onSuccess: () => {
|
||
|
|
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useUpdateTask() {
|
||
|
|
const queryClient = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: ({ id, data }: { id: string; data: TaskUpdateInput }) =>
|
||
|
|
apiPatch<Task>(`/tasks/${id}`, data),
|
||
|
|
onSuccess: (_data, variables) => {
|
||
|
|
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||
|
|
queryClient.invalidateQueries({ queryKey: ['tasks', variables.id] });
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useDeleteTask() {
|
||
|
|
const queryClient = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: (id: string) => apiDelete(`/tasks/${id}`),
|
||
|
|
onSuccess: () => {
|
||
|
|
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useAssignTask() {
|
||
|
|
const queryClient = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: ({ id, assignedTo }: { id: string; assignedTo: string }) =>
|
||
|
|
apiPost<Task>(`/tasks/${id}/assign`, { assigned_to: assignedTo }),
|
||
|
|
onSuccess: (_data, variables) => {
|
||
|
|
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||
|
|
queryClient.invalidateQueries({ queryKey: ['tasks', variables.id] });
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
export function useUpdateTaskStatus() {
|
||
|
|
const queryClient = useQueryClient();
|
||
|
|
return useMutation({
|
||
|
|
mutationFn: ({ id, status }: { id: string; status: string }) =>
|
||
|
|
apiPost<Task>(`/tasks/${id}/status`, { status }),
|
||
|
|
onSuccess: (_data, variables) => {
|
||
|
|
queryClient.invalidateQueries({ queryKey: ['tasks'] });
|
||
|
|
queryClient.invalidateQueries({ queryKey: ['tasks', variables.id] });
|
||
|
|
},
|
||
|
|
});
|
||
|
|
}
|