163bf0891a
LST-66 (2.3) front. Companion to the backend module migration. - Move pages (absences, team-absences), 8 components, the absences service + DTO and the useAbsenceHelpers composable into frontend/modules/absence/ (auto-detected layer; composable now auto-imported). - Rewrite consumers: AdminAbsencePolicyTab and the time-tracking calendar (getPublicHolidays) point to ~/modules/absence/... - Middlewares (employee/admin) and shared services (clients, users, user-data DTO) stay at the root. i18n stays global. - Routes /absences and /team-absences preserved. nuxt build passes; routes confirmed.
138 lines
4.8 KiB
TypeScript
138 lines
4.8 KiB
TypeScript
import type {
|
|
AbsenceBalance,
|
|
AbsencePolicy,
|
|
AbsencePolicyWrite,
|
|
AbsencePreviewPayload,
|
|
AbsencePreviewResult,
|
|
AbsenceRequest,
|
|
AbsenceRequestWrite,
|
|
AbsenceStatus,
|
|
AbsenceType,
|
|
} from './dto/absence'
|
|
import type { HydraCollection } from '~/utils/api'
|
|
import { extractHydraMembers } from '~/utils/api'
|
|
|
|
export type AbsenceRequestFilters = {
|
|
status?: AbsenceStatus
|
|
type?: AbsenceType
|
|
year?: number
|
|
user?: number
|
|
}
|
|
|
|
export function useAbsenceService() {
|
|
const api = useApi()
|
|
|
|
// --- Requests ---
|
|
|
|
async function getRequests(filters: AbsenceRequestFilters = {}): Promise<AbsenceRequest[]> {
|
|
const query: Record<string, unknown> = {}
|
|
if (filters.status) query.status = filters.status
|
|
if (filters.type) query.type = filters.type
|
|
if (filters.year) query.year = filters.year
|
|
if (filters.user) query.user = `/api/users/${filters.user}`
|
|
const data = await api.get<HydraCollection<AbsenceRequest>>('/absence_requests', query)
|
|
return extractHydraMembers(data)
|
|
}
|
|
|
|
async function getRequest(id: number): Promise<AbsenceRequest> {
|
|
return api.get<AbsenceRequest>(`/absence_requests/${id}`)
|
|
}
|
|
|
|
async function create(payload: AbsenceRequestWrite): Promise<AbsenceRequest> {
|
|
return api.post<AbsenceRequest>('/absence_requests', payload as Record<string, unknown>, {
|
|
toastSuccessKey: 'absences.toast.created',
|
|
})
|
|
}
|
|
|
|
async function preview(payload: AbsencePreviewPayload): Promise<AbsencePreviewResult> {
|
|
return api.post<AbsencePreviewResult>('/absence_requests/preview', payload as Record<string, unknown>, {
|
|
toast: false,
|
|
})
|
|
}
|
|
|
|
async function approve(id: number): Promise<AbsenceRequest> {
|
|
return api.patch<AbsenceRequest>(`/absence_requests/${id}/approve`, {}, {
|
|
toastSuccessKey: 'absences.toast.approved',
|
|
})
|
|
}
|
|
|
|
async function reject(id: number, rejectionReason: string): Promise<AbsenceRequest> {
|
|
return api.patch<AbsenceRequest>(`/absence_requests/${id}/reject`, { rejectionReason }, {
|
|
toastSuccessKey: 'absences.toast.rejected',
|
|
})
|
|
}
|
|
|
|
async function cancel(id: number): Promise<AbsenceRequest> {
|
|
return api.patch<AbsenceRequest>(`/absence_requests/${id}/cancel`, {}, {
|
|
toastSuccessKey: 'absences.toast.cancelled',
|
|
})
|
|
}
|
|
|
|
async function uploadJustification(id: number, file: File): Promise<AbsenceRequest> {
|
|
const form = new FormData()
|
|
form.append('file', file)
|
|
return api.post<AbsenceRequest>(`/absence_requests/${id}/justificatif`, form as unknown as Record<string, unknown>, {
|
|
toastSuccessKey: 'absences.toast.justificationUploaded',
|
|
})
|
|
}
|
|
|
|
// --- Balances ---
|
|
|
|
async function getBalances(filters: { user?: number; period?: string; type?: AbsenceType } = {}): Promise<AbsenceBalance[]> {
|
|
const query: Record<string, unknown> = {}
|
|
if (filters.user) query.user = `/api/users/${filters.user}`
|
|
if (filters.period) query.period = filters.period
|
|
if (filters.type) query.type = filters.type
|
|
const data = await api.get<HydraCollection<AbsenceBalance>>('/absence_balances', query)
|
|
return extractHydraMembers(data)
|
|
}
|
|
|
|
async function adjustBalance(id: number, payload: { acquired?: number; acquiring?: number; taken?: number }): Promise<AbsenceBalance> {
|
|
return api.patch<AbsenceBalance>(`/absence_balances/${id}`, payload as Record<string, unknown>, {
|
|
toastSuccessKey: 'absences.toast.balanceAdjusted',
|
|
})
|
|
}
|
|
|
|
// --- Policies ---
|
|
|
|
async function getPolicies(): Promise<AbsencePolicy[]> {
|
|
const data = await api.get<HydraCollection<AbsencePolicy>>('/absence_policies')
|
|
return extractHydraMembers(data)
|
|
}
|
|
|
|
async function updatePolicy(id: number, payload: AbsencePolicyWrite): Promise<AbsencePolicy> {
|
|
return api.patch<AbsencePolicy>(`/absence_policies/${id}`, payload as Record<string, unknown>, {
|
|
toastSuccessKey: 'absences.toast.policyUpdated',
|
|
})
|
|
}
|
|
|
|
// --- Admin calendar ---
|
|
|
|
async function getCalendar(from: string, to: string): Promise<AbsenceRequest[]> {
|
|
return api.get<AbsenceRequest[]>('/admin/absences/calendar', { from, to })
|
|
}
|
|
|
|
// --- Public holidays (computed server-side) ---
|
|
|
|
async function getPublicHolidays(from: string, to: string): Promise<Record<string, string>> {
|
|
return api.get<Record<string, string>>('/public_holidays', { from, to }, { toast: false })
|
|
}
|
|
|
|
return {
|
|
getRequests,
|
|
getRequest,
|
|
create,
|
|
preview,
|
|
approve,
|
|
reject,
|
|
cancel,
|
|
uploadJustification,
|
|
getBalances,
|
|
adjustBalance,
|
|
getPolicies,
|
|
updatePolicy,
|
|
getCalendar,
|
|
getPublicHolidays,
|
|
}
|
|
}
|