- CRM module: Types, API client, hooks (useLeads, useOpportunities, usePipeline, useStages, useActivities), and pages (LeadsPage, OpportunitiesPage) - Projects module: Types, API client, hooks (useProjects, useTasks, useTaskBoard, useTaskStages, useTimesheets), and pages (ProjectsPage, TasksPage) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
246 lines
8.9 KiB
TypeScript
246 lines
8.9 KiB
TypeScript
import { api } from '@services/api/axios-instance';
|
|
import type {
|
|
Project,
|
|
ProjectCreateInput,
|
|
ProjectUpdateInput,
|
|
ProjectFilters,
|
|
ProjectsResponse,
|
|
ProjectStats,
|
|
Task,
|
|
TaskCreateInput,
|
|
TaskUpdateInput,
|
|
TaskFilters,
|
|
TasksResponse,
|
|
TaskBoard,
|
|
TaskStage,
|
|
TaskStageCreateInput,
|
|
TaskStageUpdateInput,
|
|
TaskStagesResponse,
|
|
Timesheet,
|
|
TimesheetCreateInput,
|
|
TimesheetUpdateInput,
|
|
TimesheetFilters,
|
|
TimesheetsResponse,
|
|
} from '../types';
|
|
|
|
const PROJECTS_BASE = '/api/projects';
|
|
|
|
// ============================================================================
|
|
// Projects API
|
|
// ============================================================================
|
|
|
|
export const projectsApi = {
|
|
getAll: async (filters: ProjectFilters = {}): Promise<ProjectsResponse> => {
|
|
const params = new URLSearchParams();
|
|
if (filters.companyId) params.append('company_id', filters.companyId);
|
|
if (filters.managerId) params.append('manager_id', filters.managerId);
|
|
if (filters.partnerId) params.append('partner_id', filters.partnerId);
|
|
if (filters.status) params.append('status', filters.status);
|
|
if (filters.search) params.append('search', filters.search);
|
|
if (filters.page) params.append('page', String(filters.page));
|
|
if (filters.limit) params.append('limit', String(filters.limit));
|
|
|
|
const response = await api.get<ProjectsResponse>(`${PROJECTS_BASE}?${params}`);
|
|
return response.data;
|
|
},
|
|
|
|
getById: async (id: string): Promise<Project> => {
|
|
const response = await api.get<Project>(`${PROJECTS_BASE}/${id}`);
|
|
return response.data;
|
|
},
|
|
|
|
create: async (data: ProjectCreateInput): Promise<Project> => {
|
|
const response = await api.post<Project>(PROJECTS_BASE, data);
|
|
return response.data;
|
|
},
|
|
|
|
update: async (id: string, data: ProjectUpdateInput): Promise<Project> => {
|
|
const response = await api.patch<Project>(`${PROJECTS_BASE}/${id}`, data);
|
|
return response.data;
|
|
},
|
|
|
|
delete: async (id: string): Promise<void> => {
|
|
await api.delete(`${PROJECTS_BASE}/${id}`);
|
|
},
|
|
|
|
getStats: async (id: string): Promise<ProjectStats> => {
|
|
const response = await api.get<ProjectStats>(`${PROJECTS_BASE}/${id}/stats`);
|
|
return response.data;
|
|
},
|
|
|
|
activate: async (id: string): Promise<Project> => {
|
|
const response = await api.post<Project>(`${PROJECTS_BASE}/${id}/activate`);
|
|
return response.data;
|
|
},
|
|
|
|
complete: async (id: string): Promise<Project> => {
|
|
const response = await api.post<Project>(`${PROJECTS_BASE}/${id}/complete`);
|
|
return response.data;
|
|
},
|
|
|
|
cancel: async (id: string): Promise<Project> => {
|
|
const response = await api.post<Project>(`${PROJECTS_BASE}/${id}/cancel`);
|
|
return response.data;
|
|
},
|
|
|
|
hold: async (id: string): Promise<Project> => {
|
|
const response = await api.post<Project>(`${PROJECTS_BASE}/${id}/hold`);
|
|
return response.data;
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// Tasks API
|
|
// ============================================================================
|
|
|
|
export const tasksApi = {
|
|
getAll: async (filters: TaskFilters = {}): Promise<TasksResponse> => {
|
|
const params = new URLSearchParams();
|
|
if (filters.projectId) params.append('project_id', filters.projectId);
|
|
if (filters.assignedTo) params.append('assigned_to', filters.assignedTo);
|
|
if (filters.status) params.append('status', filters.status);
|
|
if (filters.priority) params.append('priority', filters.priority);
|
|
if (filters.parentId) params.append('parent_id', filters.parentId);
|
|
if (filters.stageId) params.append('stage_id', filters.stageId);
|
|
if (filters.search) params.append('search', filters.search);
|
|
if (filters.page) params.append('page', String(filters.page));
|
|
if (filters.limit) params.append('limit', String(filters.limit));
|
|
|
|
const response = await api.get<TasksResponse>(`${PROJECTS_BASE}/tasks?${params}`);
|
|
return response.data;
|
|
},
|
|
|
|
getById: async (id: string): Promise<Task> => {
|
|
const response = await api.get<Task>(`${PROJECTS_BASE}/tasks/${id}`);
|
|
return response.data;
|
|
},
|
|
|
|
create: async (data: TaskCreateInput): Promise<Task> => {
|
|
const response = await api.post<Task>(`${PROJECTS_BASE}/tasks`, data);
|
|
return response.data;
|
|
},
|
|
|
|
update: async (id: string, data: TaskUpdateInput): Promise<Task> => {
|
|
const response = await api.patch<Task>(`${PROJECTS_BASE}/tasks/${id}`, data);
|
|
return response.data;
|
|
},
|
|
|
|
delete: async (id: string): Promise<void> => {
|
|
await api.delete(`${PROJECTS_BASE}/tasks/${id}`);
|
|
},
|
|
|
|
getBoard: async (projectId: string): Promise<TaskBoard> => {
|
|
const response = await api.get<TaskBoard>(`${PROJECTS_BASE}/${projectId}/board`);
|
|
return response.data;
|
|
},
|
|
|
|
moveToStage: async (taskId: string, stageId: string, sequence?: number): Promise<Task> => {
|
|
const response = await api.post<Task>(`${PROJECTS_BASE}/tasks/${taskId}/move`, {
|
|
stageId,
|
|
sequence,
|
|
});
|
|
return response.data;
|
|
},
|
|
|
|
start: async (id: string): Promise<Task> => {
|
|
const response = await api.post<Task>(`${PROJECTS_BASE}/tasks/${id}/start`);
|
|
return response.data;
|
|
},
|
|
|
|
complete: async (id: string): Promise<Task> => {
|
|
const response = await api.post<Task>(`${PROJECTS_BASE}/tasks/${id}/complete`);
|
|
return response.data;
|
|
},
|
|
|
|
cancel: async (id: string): Promise<Task> => {
|
|
const response = await api.post<Task>(`${PROJECTS_BASE}/tasks/${id}/cancel`);
|
|
return response.data;
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// Task Stages API
|
|
// ============================================================================
|
|
|
|
export const taskStagesApi = {
|
|
getAll: async (projectId?: string): Promise<TaskStagesResponse> => {
|
|
const params = projectId ? `?project_id=${projectId}` : '';
|
|
const response = await api.get<TaskStagesResponse>(`${PROJECTS_BASE}/stages${params}`);
|
|
return response.data;
|
|
},
|
|
|
|
getById: async (id: string): Promise<TaskStage> => {
|
|
const response = await api.get<TaskStage>(`${PROJECTS_BASE}/stages/${id}`);
|
|
return response.data;
|
|
},
|
|
|
|
create: async (data: TaskStageCreateInput): Promise<TaskStage> => {
|
|
const response = await api.post<TaskStage>(`${PROJECTS_BASE}/stages`, data);
|
|
return response.data;
|
|
},
|
|
|
|
update: async (id: string, data: TaskStageUpdateInput): Promise<TaskStage> => {
|
|
const response = await api.patch<TaskStage>(`${PROJECTS_BASE}/stages/${id}`, data);
|
|
return response.data;
|
|
},
|
|
|
|
delete: async (id: string): Promise<void> => {
|
|
await api.delete(`${PROJECTS_BASE}/stages/${id}`);
|
|
},
|
|
|
|
reorder: async (stageIds: string[]): Promise<void> => {
|
|
await api.post(`${PROJECTS_BASE}/stages/reorder`, { stageIds });
|
|
},
|
|
};
|
|
|
|
// ============================================================================
|
|
// Timesheets API
|
|
// ============================================================================
|
|
|
|
export const timesheetsApi = {
|
|
getAll: async (filters: TimesheetFilters = {}): Promise<TimesheetsResponse> => {
|
|
const params = new URLSearchParams();
|
|
if (filters.companyId) params.append('company_id', filters.companyId);
|
|
if (filters.projectId) params.append('project_id', filters.projectId);
|
|
if (filters.taskId) params.append('task_id', filters.taskId);
|
|
if (filters.employeeId) params.append('employee_id', filters.employeeId);
|
|
if (filters.dateFrom) params.append('date_from', filters.dateFrom);
|
|
if (filters.dateTo) params.append('date_to', filters.dateTo);
|
|
if (filters.isBillable !== undefined) params.append('is_billable', String(filters.isBillable));
|
|
if (filters.isBilled !== undefined) params.append('is_billed', String(filters.isBilled));
|
|
if (filters.search) params.append('search', filters.search);
|
|
if (filters.page) params.append('page', String(filters.page));
|
|
if (filters.limit) params.append('limit', String(filters.limit));
|
|
|
|
const response = await api.get<TimesheetsResponse>(`${PROJECTS_BASE}/timesheets?${params}`);
|
|
return response.data;
|
|
},
|
|
|
|
getById: async (id: string): Promise<Timesheet> => {
|
|
const response = await api.get<Timesheet>(`${PROJECTS_BASE}/timesheets/${id}`);
|
|
return response.data;
|
|
},
|
|
|
|
create: async (data: TimesheetCreateInput): Promise<Timesheet> => {
|
|
const response = await api.post<Timesheet>(`${PROJECTS_BASE}/timesheets`, data);
|
|
return response.data;
|
|
},
|
|
|
|
update: async (id: string, data: TimesheetUpdateInput): Promise<Timesheet> => {
|
|
const response = await api.patch<Timesheet>(`${PROJECTS_BASE}/timesheets/${id}`, data);
|
|
return response.data;
|
|
},
|
|
|
|
delete: async (id: string): Promise<void> => {
|
|
await api.delete(`${PROJECTS_BASE}/timesheets/${id}`);
|
|
},
|
|
|
|
getByProject: async (projectId: string, filters: Omit<TimesheetFilters, 'projectId'> = {}): Promise<TimesheetsResponse> => {
|
|
return timesheetsApi.getAll({ ...filters, projectId });
|
|
},
|
|
|
|
getByEmployee: async (employeeId: string, filters: Omit<TimesheetFilters, 'employeeId'> = {}): Promise<TimesheetsResponse> => {
|
|
return timesheetsApi.getAll({ ...filters, employeeId });
|
|
},
|
|
};
|