// ============================================================ // Employees Module โ Expanded // ============================================================ let empState = { page: 1, search: '', status: '' }; async function renderEmployees(params = {}) { if (!Auth.isHR() && !Auth.isAdmin()) { return renderMyProfile(); } if (params.id) return renderEmployeeDetail(params.id); if (params.tab === 'leave') return renderLeaveAdmin(); if (params.tab === 'settings') return renderHRSettings(); const content = document.getElementById('page-content'); content.innerHTML = `
Team members, HR records & documents
| Employee | Emp No. | Department | Job Title | Type | Salary | User | Status |
|---|---|---|---|---|---|---|---|
${avatarHTML(e.first_name + ' ' + e.last_name, 'lg')} ${e.first_name} ${e.last_name} ${e.work_email || e.personal_email || 'โ'} |
${e.employee_number} | ${e.department || 'โ'} | ${e.job_title || 'โ'} | ${Fmt.capitalize(e.employment_type || '')} | ${e.current_salary ? 'R ' + parseFloat(e.current_salary).toFixed(2) : 'โ'} | ${e.linked_username ? `${e.linked_username}` : 'None'} | ${Fmt.statusBadge(e.status)} |
${e.first_name} ${e.last_name}
${e.id_number || 'โ'}
${Fmt.date(e.date_of_birth) || 'โ'}
${Fmt.capitalize(e.gender || 'โ')}
${e.nationality || 'โ'}
${Fmt.capitalize(e.marital_status || 'โ')}
${e.personal_email || 'โ'}
${e.phone || 'โ'}
${e.emergency_contact_name || 'โ'}
${e.emergency_contact_phone || 'โ'}
${[e.address_line1, e.address_line2, e.city, e.province, e.postal_code].filter(Boolean).join(', ') || 'โ'}
${e.job_title || 'โ'}
${e.department || 'โ'}
${Fmt.capitalize(e.employment_type || 'โ')}
${Fmt.statusBadge(e.status)}
${Fmt.date(e.start_date)}
${Fmt.date(e.probation_end_date) || 'โ'}
${e.work_email || 'โ'}
${e.tax_number || 'โ'}
${e.uif_number || 'โ'}
${e.days_per_month || '21.67'}
${e.hours_per_day || '8'}
No system user linked. Link a user so they can view their profile and apply for leave.
'}| Effective Date | Type | Basic Salary | Hourly Rate* |
|---|---|---|---|
| ${Fmt.date(s.effective_date)} | ${Fmt.capitalize(s.salary_type)} | ${Fmt.currency(s.basic_salary)} | R ${hr.toFixed(2)}/hr |
* Rate = Salary รท (${e.days_per_month || 21.67} days ร ${e.hours_per_day || 8} hrs/day)
` : `| Type | Amount | Taxable |
|---|---|---|
| ${a.type} | ${Fmt.currency(a.amount)} | ${a.is_taxable ? 'Yes' : 'No'} |
| Type | Amount |
|---|---|
| ${d.type} | ${d.is_percentage ? d.amount + '%' : Fmt.currency(d.amount)} |
${e.bank_name || 'โ'}
${Fmt.capitalize(e.account_type || 'โ')}
${e.bank_account_no || 'โ'}
${e.bank_branch_code || 'โ'}
${e.salaries?.[0] ? Fmt.capitalize(e.salaries[0].salary_type) + ' ยท Eff. ' + Fmt.date(e.salaries[0].effective_date) : 'No record'}
${Auth.can('employees', 'edit') ? `` : ''}| Type | Start | End | Days | Reason | Status | |
|---|---|---|---|---|---|---|
| ${Fmt.capitalize(l.leave_type)} | ${Fmt.date(l.start_date)} | ${Fmt.date(l.end_date)} | ${l.days} | ${l.reason || 'โ'} | ${Fmt.statusBadge(l.status)} | ${l.status === 'pending' && (Auth.isAdmin() || Auth.isHR()) ? `
|
| Type | Label | Expiry | Uploaded | File | |
|---|---|---|---|---|---|
| ${d.doc_type || 'other'} | ${d.label} | ${Fmt.date(d.expiry_date) || 'โ'} | ${Fmt.date(d.created_at)} | ${d.file_path ? `๐ View` : 'โ'} | ${Auth.can('employees', 'delete') ? `` : ''} |
Reason: ${w.reason}
${w.outcome ? `Outcome: ${w.outcome}
` : ''} ${w.follow_up_date ? `๐ Follow-up: ${Fmt.date(w.follow_up_date)}
` : ''}Link a login so this employee can view their profile and apply for leave.
Approve and manage leave requests
${res.message}
`; return; } const leaves = res.data.leaves; if (!leaves.length) { wrap.innerHTML = `| Employee | Dept. | Type | Start | End | Days | Reason | Status | |
|---|---|---|---|---|---|---|---|---|
| ${l.employee_name} ${l.employee_number} |
${l.department || 'โ'} | ${Fmt.capitalize(l.leave_type)} | ${Fmt.date(l.start_date)} | ${Fmt.date(l.end_date)} | ${l.days} | ${l.reason || 'โ'} | ${Fmt.statusBadge(l.status)} | ${l.status === 'pending' ? `
|
| Employee | Dept. | ${types.map(t => `${Fmt.capitalize(t)} | `).join('')}||
|---|---|---|---|---|
| ${types.map(() => ' | Alloc | Used | Avail | ').join('')}|
| ${e.name} ${e.number} | ${e.dept || 'โ'} | ${types.map(t => { const b = e.types[t] || {}; const alloc = parseFloat(b.allocated || 0) + parseFloat(b.carried_over || 0); const used = parseFloat(b.used || 0); const avail = Math.max(0, alloc - used); return `${alloc.toFixed(1)} | ${used.toFixed(1)} | ${avail.toFixed(1)} | `; }).join('')}
System configuration
| Name | Username | Role | Status | Last Login | ||
|---|---|---|---|---|---|---|
|
${(u.full_name || '?').split(' ').map(n => n[0]).join('').slice(0, 2).toUpperCase()}
${u.full_name || 'โ'}
|
${u.username} | ${u.email || 'โ'} | ${ROLES[u.role_id] || 'Unknown'} | ${u.is_active ? 'โ Active' : 'โ Inactive'} | ${u.last_login ? Fmt.date(u.last_login) : 'Never'} |
Contact HR to link your employee profile.
${e.first_name} ${e.last_name}
${e.employee_number}
${e.job_title || 'โ'}
${e.department || 'โ'}
${e.work_email || 'โ'}
${e.phone || 'โ'}
${Fmt.date(e.start_date)}
${Fmt.capitalize(e.employment_type)}
| Type | Start | End | Days | Status |
|---|---|---|---|---|
| ${Fmt.capitalize(l.leave_type)} | ${Fmt.date(l.start_date)} | ${Fmt.date(l.end_date)} | ${l.days} | ${Fmt.statusBadge(l.status)} |