[SAAS-022] feat: Implement Goals module frontend
- Added API services for definitions and assignments - Added 24 React Query hooks in useGoals.ts - Updated hooks/index.ts to export useGoals Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
a4253a8ce9
commit
69a6a2c4ea
@ -14,3 +14,4 @@ export * from './useAnalytics';
|
|||||||
export * from './useMfa';
|
export * from './useMfa';
|
||||||
export * from './useWhatsApp';
|
export * from './useWhatsApp';
|
||||||
export * from './usePortfolio';
|
export * from './usePortfolio';
|
||||||
|
export * from './useGoals';
|
||||||
|
|||||||
242
src/hooks/useGoals.ts
Normal file
242
src/hooks/useGoals.ts
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||||
|
import {
|
||||||
|
definitionsApi,
|
||||||
|
assignmentsApi,
|
||||||
|
type DefinitionFilters,
|
||||||
|
type CreateDefinitionDto,
|
||||||
|
type UpdateDefinitionDto,
|
||||||
|
type GoalStatus,
|
||||||
|
type AssignmentFilters,
|
||||||
|
type CreateAssignmentDto,
|
||||||
|
type UpdateAssignmentDto,
|
||||||
|
type AssignmentStatus,
|
||||||
|
type UpdateProgressDto,
|
||||||
|
} from '@/services/goals';
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// Goal Definitions Hooks
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
export function useGoalDefinitions(filters?: DefinitionFilters) {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'definitions', filters],
|
||||||
|
queryFn: () => definitionsApi.list(filters),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGoalDefinition(id: string) {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'definitions', id],
|
||||||
|
queryFn: () => definitionsApi.get(id),
|
||||||
|
enabled: !!id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCreateGoalDefinition() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (data: CreateDefinitionDto) => definitionsApi.create(data),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions'] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUpdateGoalDefinition() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, data }: { id: string; data: UpdateDefinitionDto }) =>
|
||||||
|
definitionsApi.update(id, data),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions', id] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUpdateGoalStatus() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, status }: { id: string; status: GoalStatus }) =>
|
||||||
|
definitionsApi.updateStatus(id, { status }),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions', id] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useActivateGoal() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => definitionsApi.activate(id),
|
||||||
|
onSuccess: (_, id) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions', id] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDuplicateGoalDefinition() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => definitionsApi.duplicate(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions'] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDeleteGoalDefinition() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => definitionsApi.delete(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions'] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// Goal Assignments Hooks
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
export function useGoalAssignments(filters?: AssignmentFilters) {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'assignments', filters],
|
||||||
|
queryFn: () => assignmentsApi.list(filters),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGoalAssignmentsByGoal(goalId: string) {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'definitions', goalId, 'assignments'],
|
||||||
|
queryFn: () => assignmentsApi.listByGoal(goalId),
|
||||||
|
enabled: !!goalId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGoalAssignment(id: string) {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'assignments', id],
|
||||||
|
queryFn: () => assignmentsApi.get(id),
|
||||||
|
enabled: !!id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useCreateGoalAssignment() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (data: CreateAssignmentDto) => assignmentsApi.create(data),
|
||||||
|
onSuccess: (result) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'assignments'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'definitions', result.definitionId, 'assignments'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'my'] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUpdateGoalAssignment() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, data }: { id: string; data: UpdateAssignmentDto }) =>
|
||||||
|
assignmentsApi.update(id, data),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'assignments'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'assignments', id] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUpdateAssignmentStatus() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, status }: { id: string; status: AssignmentStatus }) =>
|
||||||
|
assignmentsApi.updateStatus(id, { status }),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'assignments'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'assignments', id] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'my'] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUpdateGoalProgress() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, data }: { id: string; data: UpdateProgressDto }) =>
|
||||||
|
assignmentsApi.updateProgress(id, data),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'assignments'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'assignments', id] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'my'] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGoalProgressHistory(assignmentId: string) {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'assignments', assignmentId, 'history'],
|
||||||
|
queryFn: () => assignmentsApi.getHistory(assignmentId),
|
||||||
|
enabled: !!assignmentId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useDeleteGoalAssignment() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: (id: string) => assignmentsApi.delete(id),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'assignments'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'my'] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// My Goals Hooks
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
export function useMyGoals() {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'my'],
|
||||||
|
queryFn: () => assignmentsApi.getMyGoals(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useMyGoalsSummary() {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'my', 'summary'],
|
||||||
|
queryFn: () => assignmentsApi.getMyGoalsSummary(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useUpdateMyGoalProgress() {
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
return useMutation({
|
||||||
|
mutationFn: ({ id, data }: { id: string; data: UpdateProgressDto }) =>
|
||||||
|
assignmentsApi.updateMyProgress(id, data),
|
||||||
|
onSuccess: (_, { id }) => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'my'] });
|
||||||
|
queryClient.invalidateQueries({ queryKey: ['goals', 'assignments', id] });
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================================
|
||||||
|
// Reports Hooks
|
||||||
|
// ============================================
|
||||||
|
|
||||||
|
export function useGoalCompletionReport(startDate?: string, endDate?: string) {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'reports', 'completion', startDate, endDate],
|
||||||
|
queryFn: () => assignmentsApi.getCompletionReport(startDate, endDate),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function useGoalUserReport() {
|
||||||
|
return useQuery({
|
||||||
|
queryKey: ['goals', 'reports', 'by-user'],
|
||||||
|
queryFn: () => assignmentsApi.getUserReport(),
|
||||||
|
});
|
||||||
|
}
|
||||||
205
src/services/goals/assignments.api.ts
Normal file
205
src/services/goals/assignments.api.ts
Normal file
@ -0,0 +1,205 @@
|
|||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// Types
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
export type AssigneeType = 'user' | 'team' | 'tenant';
|
||||||
|
export type AssignmentStatus = 'active' | 'achieved' | 'failed' | 'cancelled';
|
||||||
|
export type ProgressSource = 'manual' | 'automatic' | 'import' | 'api';
|
||||||
|
|
||||||
|
export interface Assignment {
|
||||||
|
id: string;
|
||||||
|
tenantId: string;
|
||||||
|
definitionId: string;
|
||||||
|
assigneeType: AssigneeType;
|
||||||
|
userId: string | null;
|
||||||
|
teamId: string | null;
|
||||||
|
customTarget: number | null;
|
||||||
|
currentValue: number;
|
||||||
|
progressPercentage: number;
|
||||||
|
lastUpdatedAt: string | null;
|
||||||
|
status: AssignmentStatus;
|
||||||
|
achievedAt: string | null;
|
||||||
|
notes: string | null;
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
definition?: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
targetValue: number;
|
||||||
|
unit: string | null;
|
||||||
|
startsAt: string;
|
||||||
|
endsAt: string;
|
||||||
|
};
|
||||||
|
user?: {
|
||||||
|
id: string;
|
||||||
|
email: string;
|
||||||
|
firstName: string | null;
|
||||||
|
lastName: string | null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateAssignmentDto {
|
||||||
|
definitionId: string;
|
||||||
|
assigneeType?: AssigneeType;
|
||||||
|
userId?: string;
|
||||||
|
teamId?: string;
|
||||||
|
customTarget?: number;
|
||||||
|
notes?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateAssignmentDto = Partial<Omit<CreateAssignmentDto, 'definitionId'>>;
|
||||||
|
|
||||||
|
export interface AssignmentStatusDto {
|
||||||
|
status: AssignmentStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpdateProgressDto {
|
||||||
|
value: number;
|
||||||
|
source?: ProgressSource;
|
||||||
|
sourceReference?: string;
|
||||||
|
notes?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AssignmentFilters {
|
||||||
|
definitionId?: string;
|
||||||
|
userId?: string;
|
||||||
|
status?: AssignmentStatus;
|
||||||
|
assigneeType?: AssigneeType;
|
||||||
|
minProgress?: number;
|
||||||
|
maxProgress?: number;
|
||||||
|
sortBy?: string;
|
||||||
|
sortOrder?: 'ASC' | 'DESC';
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaginatedAssignments {
|
||||||
|
items: Assignment[];
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProgressLog {
|
||||||
|
id: string;
|
||||||
|
assignmentId: string;
|
||||||
|
previousValue: number | null;
|
||||||
|
newValue: number;
|
||||||
|
changeAmount: number | null;
|
||||||
|
source: ProgressSource;
|
||||||
|
sourceReference: string | null;
|
||||||
|
notes: string | null;
|
||||||
|
loggedAt: string;
|
||||||
|
loggedBy: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MyGoalsSummary {
|
||||||
|
totalAssignments: number;
|
||||||
|
activeAssignments: number;
|
||||||
|
achievedAssignments: number;
|
||||||
|
failedAssignments: number;
|
||||||
|
averageProgress: number;
|
||||||
|
atRiskCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CompletionReport {
|
||||||
|
totalGoals: number;
|
||||||
|
achievedGoals: number;
|
||||||
|
failedGoals: number;
|
||||||
|
activeGoals: number;
|
||||||
|
completionRate: number;
|
||||||
|
averageProgress: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UserReport {
|
||||||
|
userId: string;
|
||||||
|
userName: string | null;
|
||||||
|
totalAssignments: number;
|
||||||
|
achieved: number;
|
||||||
|
failed: number;
|
||||||
|
active: number;
|
||||||
|
averageProgress: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// API Service
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
export const assignmentsApi = {
|
||||||
|
// Assignments CRUD
|
||||||
|
list: async (params?: AssignmentFilters): Promise<PaginatedAssignments> => {
|
||||||
|
const response = await api.get<PaginatedAssignments>('/goals/assignments', { params });
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
listByGoal: async (goalId: string): Promise<Assignment[]> => {
|
||||||
|
const response = await api.get<Assignment[]>(`/goals/${goalId}/assignments`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
get: async (id: string): Promise<Assignment> => {
|
||||||
|
const response = await api.get<Assignment>(`/goals/assignments/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
create: async (data: CreateAssignmentDto): Promise<Assignment> => {
|
||||||
|
const response = await api.post<Assignment>('/goals/assignments', data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
update: async (id: string, data: UpdateAssignmentDto): Promise<Assignment> => {
|
||||||
|
const response = await api.patch<Assignment>(`/goals/assignments/${id}`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateStatus: async (id: string, data: AssignmentStatusDto): Promise<Assignment> => {
|
||||||
|
const response = await api.patch<Assignment>(`/goals/assignments/${id}/status`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateProgress: async (id: string, data: UpdateProgressDto): Promise<Assignment> => {
|
||||||
|
const response = await api.post<Assignment>(`/goals/assignments/${id}/progress`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
getHistory: async (id: string): Promise<ProgressLog[]> => {
|
||||||
|
const response = await api.get<ProgressLog[]>(`/goals/assignments/${id}/history`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
delete: async (id: string): Promise<void> => {
|
||||||
|
await api.delete(`/goals/assignments/${id}`);
|
||||||
|
},
|
||||||
|
|
||||||
|
// My Goals
|
||||||
|
getMyGoals: async (): Promise<Assignment[]> => {
|
||||||
|
const response = await api.get<Assignment[]>('/goals/my');
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
getMyGoalsSummary: async (): Promise<MyGoalsSummary> => {
|
||||||
|
const response = await api.get<MyGoalsSummary>('/goals/my/summary');
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMyProgress: async (id: string, data: UpdateProgressDto): Promise<Assignment> => {
|
||||||
|
const response = await api.post<Assignment>(`/goals/my/${id}/update`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
// Reports
|
||||||
|
getCompletionReport: async (startDate?: string, endDate?: string): Promise<CompletionReport> => {
|
||||||
|
const response = await api.get<CompletionReport>('/goals/reports/completion', {
|
||||||
|
params: { startDate, endDate },
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUserReport: async (): Promise<UserReport[]> => {
|
||||||
|
const response = await api.get<UserReport[]>('/goals/reports/by-user');
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
137
src/services/goals/definitions.api.ts
Normal file
137
src/services/goals/definitions.api.ts
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import api from '../api';
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// Types
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
export type GoalType = 'target' | 'limit' | 'maintain';
|
||||||
|
export type MetricType = 'number' | 'currency' | 'percentage' | 'boolean' | 'count';
|
||||||
|
export type PeriodType = 'daily' | 'weekly' | 'monthly' | 'quarterly' | 'yearly' | 'custom';
|
||||||
|
export type DataSource = 'manual' | 'sales' | 'billing' | 'commissions' | 'custom';
|
||||||
|
export type GoalStatus = 'draft' | 'active' | 'paused' | 'completed' | 'cancelled';
|
||||||
|
|
||||||
|
export interface SourceConfig {
|
||||||
|
module?: string;
|
||||||
|
entity?: string;
|
||||||
|
filter?: Record<string, unknown>;
|
||||||
|
aggregation?: 'sum' | 'count' | 'avg';
|
||||||
|
field?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Milestone {
|
||||||
|
percentage: number;
|
||||||
|
notify: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GoalDefinition {
|
||||||
|
id: string;
|
||||||
|
tenantId: string;
|
||||||
|
name: string;
|
||||||
|
description: string | null;
|
||||||
|
category: string | null;
|
||||||
|
type: GoalType;
|
||||||
|
metric: MetricType;
|
||||||
|
targetValue: number;
|
||||||
|
unit: string | null;
|
||||||
|
period: PeriodType;
|
||||||
|
startsAt: string;
|
||||||
|
endsAt: string;
|
||||||
|
source: DataSource;
|
||||||
|
sourceConfig: SourceConfig;
|
||||||
|
milestones: Milestone[];
|
||||||
|
status: GoalStatus;
|
||||||
|
tags: string[];
|
||||||
|
createdAt: string;
|
||||||
|
updatedAt: string;
|
||||||
|
createdBy: string | null;
|
||||||
|
assignmentCount?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CreateDefinitionDto {
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
category?: string;
|
||||||
|
type?: GoalType;
|
||||||
|
metric?: MetricType;
|
||||||
|
targetValue: number;
|
||||||
|
unit?: string;
|
||||||
|
period?: PeriodType;
|
||||||
|
startsAt: string;
|
||||||
|
endsAt: string;
|
||||||
|
source?: DataSource;
|
||||||
|
sourceConfig?: SourceConfig;
|
||||||
|
milestones?: Milestone[];
|
||||||
|
status?: GoalStatus;
|
||||||
|
tags?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export type UpdateDefinitionDto = Partial<CreateDefinitionDto>;
|
||||||
|
|
||||||
|
export interface DefinitionStatusDto {
|
||||||
|
status: GoalStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DefinitionFilters {
|
||||||
|
status?: GoalStatus;
|
||||||
|
period?: PeriodType;
|
||||||
|
category?: string;
|
||||||
|
search?: string;
|
||||||
|
activeOn?: string;
|
||||||
|
sortBy?: string;
|
||||||
|
sortOrder?: 'ASC' | 'DESC';
|
||||||
|
page?: number;
|
||||||
|
limit?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PaginatedDefinitions {
|
||||||
|
items: GoalDefinition[];
|
||||||
|
total: number;
|
||||||
|
page: number;
|
||||||
|
limit: number;
|
||||||
|
totalPages: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
// API Service
|
||||||
|
// ─────────────────────────────────────────────
|
||||||
|
|
||||||
|
export const definitionsApi = {
|
||||||
|
list: async (params?: DefinitionFilters): Promise<PaginatedDefinitions> => {
|
||||||
|
const response = await api.get<PaginatedDefinitions>('/goals', { params });
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
get: async (id: string): Promise<GoalDefinition> => {
|
||||||
|
const response = await api.get<GoalDefinition>(`/goals/${id}`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
create: async (data: CreateDefinitionDto): Promise<GoalDefinition> => {
|
||||||
|
const response = await api.post<GoalDefinition>('/goals', data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
update: async (id: string, data: UpdateDefinitionDto): Promise<GoalDefinition> => {
|
||||||
|
const response = await api.patch<GoalDefinition>(`/goals/${id}`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
updateStatus: async (id: string, data: DefinitionStatusDto): Promise<GoalDefinition> => {
|
||||||
|
const response = await api.patch<GoalDefinition>(`/goals/${id}/status`, data);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
activate: async (id: string): Promise<GoalDefinition> => {
|
||||||
|
const response = await api.post<GoalDefinition>(`/goals/${id}/activate`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
duplicate: async (id: string): Promise<GoalDefinition> => {
|
||||||
|
const response = await api.post<GoalDefinition>(`/goals/${id}/duplicate`);
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
delete: async (id: string): Promise<void> => {
|
||||||
|
await api.delete(`/goals/${id}`);
|
||||||
|
},
|
||||||
|
};
|
||||||
2
src/services/goals/index.ts
Normal file
2
src/services/goals/index.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export * from './definitions.api';
|
||||||
|
export * from './assignments.api';
|
||||||
Loading…
Reference in New Issue
Block a user