diff --git a/frontend/src/lib/api/employees.ts b/frontend/src/lib/api/employees.ts index a7d5f61..8c8817d 100644 --- a/frontend/src/lib/api/employees.ts +++ b/frontend/src/lib/api/employees.ts @@ -9,28 +9,139 @@ const toNumber = (v: any): number => { return Number.isFinite(n) ? n : 0 } +const cleanStr = (v: any) => { + if (v === null || v === undefined) return undefined + const s = String(v).trim() + return s === '' ? undefined : s +} + +const cleanEmail = (v: any) => { + const s = cleanStr(v) + if (!s) return undefined + return s.replace(/\s+/g, '').replace(/\++$/g, '') +} + +const parseDateToISO = (v: any) => { + const s = cleanStr(v) + if (!s) return undefined + + // DD/MM/YYYY + const m = s.match(/^(\d{2})\/(\d{2})\/(\d{4})$/) + if (m) { + const dd = m[1] + const mm = m[2] + const yyyy = m[3] + const d = new Date(`${yyyy}-${mm}-${dd}T00:00:00.000Z`) + return isNaN(d.getTime()) ? undefined : d.toISOString() + } + + const d = new Date(s) + return isNaN(d.getTime()) ? undefined : d.toISOString() +} + const normalizeEmployeeFromApi = (e: any) => { const basic = toNumber(e?.basicSalary ?? e?.baseSalary ?? e?.salary) return { ...e, - baseSalary: basic, + baseSalary: basic, + salary: basic, } } + const normalizeEmployeeToApi = (data: any) => { - const d = { ...(data || {}) } + const d: any = { ...(data || {}) } + + if (d.department?.id && !d.departmentId) d.departmentId = d.department.id + if (d.position?.id && !d.positionId) d.positionId = d.position.id + if (d.reportingTo?.id && !d.reportingToId) d.reportingToId = d.reportingTo.id if (d.baseSalary !== undefined) { d.basicSalary = toNumber(d.baseSalary) - delete d.baseSalary - } - - if (d.salary !== undefined) { + } else if (d.salary !== undefined) { d.basicSalary = toNumber(d.salary) - delete d.salary } - return d + d.firstName = cleanStr(d.firstName) + d.lastName = cleanStr(d.lastName) + d.firstNameAr = cleanStr(d.firstNameAr) + d.lastNameAr = cleanStr(d.lastNameAr) + + d.email = cleanEmail(d.email) + d.phone = cleanStr(d.phone) + d.mobile = cleanStr(d.mobile) + + d.gender = cleanStr(d.gender) + d.nationality = cleanStr(d.nationality) + d.nationalId = cleanStr(d.nationalId) + d.passportNumber = cleanStr(d.passportNumber) + + d.employmentType = cleanStr(d.employmentType) + d.contractType = cleanStr(d.contractType) + + d.departmentId = cleanStr(d.departmentId) + d.positionId = cleanStr(d.positionId) + d.reportingToId = cleanStr(d.reportingToId) + + d.currency = cleanStr(d.currency) ?? 'SAR' + d.status = cleanStr(d.status) + + d.address = cleanStr(d.address) + d.city = cleanStr(d.city) + d.country = cleanStr(d.country) + + d.terminationReason = cleanStr(d.terminationReason) + d.emergencyContactName = cleanStr(d.emergencyContactName) + d.emergencyContactPhone = cleanStr(d.emergencyContactPhone) + d.emergencyContactRelation = cleanStr(d.emergencyContactRelation) + + d.hireDate = parseDateToISO(d.hireDate) + d.dateOfBirth = parseDateToISO(d.dateOfBirth) + d.endDate = parseDateToISO(d.endDate) + d.probationEndDate = parseDateToISO(d.probationEndDate) + d.terminationDate = parseDateToISO(d.terminationDate) + + const allowed = [ + 'firstName', + 'lastName', + 'firstNameAr', + 'lastNameAr', + 'email', + 'phone', + 'mobile', + 'dateOfBirth', + 'gender', + 'nationality', + 'nationalId', + 'passportNumber', + 'employmentType', + 'contractType', + 'hireDate', + 'endDate', + 'probationEndDate', + 'departmentId', + 'positionId', + 'reportingToId', + 'basicSalary', + 'currency', + 'status', + 'terminationDate', + 'terminationReason', + 'emergencyContactName', + 'emergencyContactPhone', + 'emergencyContactRelation', + 'address', + 'city', + 'country', + 'documents', + ] + + const payload: any = {} + for (const k of allowed) { + if (d[k] !== undefined) payload[k] = d[k] + } + + return payload } export interface Employee { @@ -60,7 +171,6 @@ export interface Employee { reportingTo?: any baseSalary: number - basicSalary?: any currency?: string @@ -111,7 +221,6 @@ export interface EmployeesResponse { } export const employeesAPI = { - // Get all employees with filters and pagination getAll: async (filters: EmployeeFilters = {}): Promise => { const params = new URLSearchParams() if (filters.search) params.append('search', filters.search) @@ -135,33 +244,28 @@ export const employeesAPI = { } }, - // Get single employee by ID getById: async (id: string): Promise => { const response = await api.get(`/hr/employees/${id}`) return normalizeEmployeeFromApi(response.data.data) }, - // Create new employee create: async (data: CreateEmployeeData): Promise => { const payload = normalizeEmployeeToApi(data) const response = await api.post('/hr/employees', payload) return normalizeEmployeeFromApi(response.data.data) }, - // Update existing employee update: async (id: string, data: UpdateEmployeeData): Promise => { const payload = normalizeEmployeeToApi(data) const response = await api.put(`/hr/employees/${id}`, payload) return normalizeEmployeeFromApi(response.data.data) }, - // Delete employee delete: async (id: string): Promise => { await api.delete(`/hr/employees/${id}`) } } -// Departments API export const departmentsAPI = { getAll: async (): Promise => { const response = await api.get('/hr/departments') @@ -169,7 +273,6 @@ export const departmentsAPI = { } } -// Positions API export const positionsAPI = { getAll: async (): Promise => { const response = await api.get('/hr/positions')