erp-core-frontend-v2/src/features/projects/api/projects.api.ts
rckrdmrd 07987788f8 feat(frontend): Add CRM and Projects modules frontend
- 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>
2026-01-18 10:36:23 -06:00

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 });
},
};