This commit is contained in:
yotakii
2026-03-03 12:41:04 +03:00
parent eecdf547cf
commit 69d3d21487

View File

@@ -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,
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<EmployeesResponse> => {
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<Employee> => {
const response = await api.get(`/hr/employees/${id}`)
return normalizeEmployeeFromApi(response.data.data)
},
// Create new employee
create: async (data: CreateEmployeeData): Promise<Employee> => {
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<Employee> => {
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<void> => {
await api.delete(`/hr/employees/${id}`)
}
}
// Departments API
export const departmentsAPI = {
getAll: async (): Promise<any[]> => {
const response = await api.get('/hr/departments')
@@ -169,7 +273,6 @@ export const departmentsAPI = {
}
}
// Positions API
export const positionsAPI = {
getAll: async (): Promise<any[]> => {
const response = await api.get('/hr/positions')