feat: wire designation management to real API

Remove FALLBACK_DESIGNATIONS and static DEPARTMENTS array. Fetch
departments from API for dropdown, send department_id (UUID) on save,
normalize department_name/department_id from backend response.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ashwin Kumar 2026-03-27 19:21:00 +01:00
parent 2a3a336114
commit c911a0c450

View file

@ -8,6 +8,7 @@ const API = '/api/gateway';
type DesignationRecord = CrudRecord & {
code?: string;
department?: string;
departmentId?: string;
level?: string;
description?: string;
totalEmployees?: number;
@ -16,14 +17,7 @@ type DesignationRecord = CrudRecord & {
canApprove?: boolean;
};
const FALLBACK_DESIGNATIONS: DesignationRecord[] = [
{ id: 'z1', name: 'Senior Software Engineer', code: 'SSE-001', department: 'Engineering', level: 'Senior', totalEmployees: 12, status: 'ACTIVE', updatedAt: '2026-03-01', createdDate: '2026-01-15' },
{ id: 'z2', name: 'Marketing Manager', code: 'MM-002', department: 'Marketing', level: 'Manager', totalEmployees: 8, status: 'ACTIVE', updatedAt: '2026-03-01', createdDate: '2026-01-20' },
{ id: 'z3', name: 'Sales Executive', code: 'SE-003', department: 'Sales', level: 'Executive', totalEmployees: 15, status: 'ACTIVE', updatedAt: '2026-03-01', createdDate: '2026-02-01' },
{ id: 'z4', name: 'HR Specialist', code: 'HRS-004', department: 'Human Resources', level: 'Specialist', totalEmployees: 5, status: 'ACTIVE', updatedAt: '2026-03-01', createdDate: '2026-02-05' },
{ id: 'z5', name: 'Product Manager', code: 'PM-005', department: 'Product', level: 'Manager', totalEmployees: 6, status: 'ACTIVE', updatedAt: '2026-03-01', createdDate: '2026-02-10' },
{ id: 'z6', name: 'Finance Analyst', code: 'FA-006', department: 'Finance', level: 'Analyst', totalEmployees: 9, status: 'INACTIVE', updatedAt: '2026-03-01', createdDate: '2026-02-15' },
];
type DepartmentOption = { id: string; name: string };
const permissionGroups = [
{ title: 'Employee Management', items: ['View Employees', 'Create Employees', 'Edit Employees', 'Delete Employees'] },
@ -32,7 +26,6 @@ const permissionGroups = [
];
const LEVELS = ['Intern', 'Junior', 'Mid-Level', 'Senior', 'Lead', 'Manager', 'Director', 'VP', 'C-Level', 'Executive', 'Specialist', 'Analyst'];
const DEPARTMENTS = ['Engineering', 'Marketing', 'Sales', 'Human Resources', 'Finance', 'Operations', 'Product', 'Customer Success'];
type DesignationListResponse = {
designations?: any[];
@ -51,16 +44,17 @@ function normalizeDesignation(item: any, idx: number): DesignationRecord {
return {
id: String(item.id ?? `des-${idx + 1}`),
name: String(item.name ?? ''),
code: String(item.code ?? ''),
department: String(item.department ?? item.department_name ?? ''),
level: String(item.level ?? ''),
description: String(item.description ?? ''),
totalEmployees: Number(item.totalEmployees ?? item.total_employees ?? 0),
canManageTeam: Boolean(item.canManageTeam ?? item.can_manage_team ?? false),
canApprove: Boolean(item.canApprove ?? item.can_approve ?? false),
code: item.code ? String(item.code) : undefined,
department: item.department_name ? String(item.department_name) : undefined,
departmentId: item.department_id ? String(item.department_id) : undefined,
level: item.level ? String(item.level) : undefined,
description: item.description ? String(item.description) : undefined,
totalEmployees: Number(item.total_employees ?? 0),
canManageTeam: Boolean(item.can_manage_team ?? false),
canApprove: Boolean(item.can_approve ?? false),
status: isActive ? 'ACTIVE' : 'INACTIVE',
updatedAt: String(item.updatedAt ?? item.updated_at ?? ''),
createdDate: String(item.createdDate ?? item.created_at ?? ''),
updatedAt: String(item.updated_at ?? ''),
createdDate: String(item.created_at ?? ''),
};
}
@ -128,7 +122,7 @@ export default function DesignationManagementPage() {
const [name, setName] = createSignal('');
const [code, setCode] = createSignal('');
const [department, setDepartment] = createSignal('');
const [departmentId, setDepartmentId] = createSignal('');
const [level, setLevel] = createSignal('');
const [description, setDescription] = createSignal('');
const [status, setStatus] = createSignal<'ACTIVE' | 'INACTIVE'>('ACTIVE');
@ -137,52 +131,61 @@ export default function DesignationManagementPage() {
const [isLoading, setIsLoading] = createSignal(false);
const [isSaving, setIsSaving] = createSignal(false);
const [error, setError] = createSignal('');
const [departments, setDepartments] = createSignal<DepartmentOption[]>([]);
const load = async () => {
setIsLoading(true);
setError('');
try {
try {
const params = new URLSearchParams({
page: '1',
per_page: '100',
q: search().trim(),
});
if (statusFilter() !== 'all') {
params.set('status', statusFilter());
}
if (deptFilter() !== 'all') {
params.set('department', deptFilter());
}
const res = await fetch(`${API}/api/admin/designations?${params.toString()}`);
if (!res.ok) {
throw new Error(`Request failed (${res.status})`);
}
const payload = (await res.json().catch(() => null)) as DesignationListResponse | null;
const list = Array.isArray(payload)
? payload
: Array.isArray(payload?.designations)
? payload.designations
: Array.isArray(payload?.data)
? payload.data
: Array.isArray(payload?.items)
? payload.items
: [];
if (list.length === 0) {
setRows(FALLBACK_DESIGNATIONS);
} else {
setRows(list.map(normalizeDesignation));
}
} catch {
setRows(FALLBACK_DESIGNATIONS);
setError('Could not reach designations API, showing fallback data.');
const params = new URLSearchParams({
page: '1',
per_page: '100',
q: search().trim(),
});
if (statusFilter() !== 'all') {
params.set('status', statusFilter());
}
if (deptFilter() !== 'all') {
params.set('department_id', deptFilter());
}
const res = await fetch(`${API}/api/admin/designations?${params.toString()}`);
if (!res.ok) throw new Error(`Request failed (${res.status})`);
const payload = (await res.json().catch(() => null)) as DesignationListResponse | null;
const list = Array.isArray(payload)
? payload
: Array.isArray(payload?.designations)
? payload.designations
: Array.isArray(payload?.data)
? payload.data
: Array.isArray(payload?.items)
? payload.items
: [];
setRows(list.map(normalizeDesignation));
} catch (err: any) {
setError(err?.message || 'Could not reach designations API.');
setRows([]);
} finally {
setIsLoading(false);
}
};
onMount(() => void load());
const loadDepartments = async () => {
try {
const res = await fetch(`${API}/api/admin/departments?per_page=100`);
if (!res.ok) return;
const payload = await res.json().catch(() => null);
const list: any[] = Array.isArray(payload)
? payload
: Array.isArray(payload?.departments)
? payload.departments
: [];
setDepartments(list.map((d: any) => ({ id: String(d.id), name: String(d.name) })));
} catch {
// departments dropdown will just be empty
}
};
onMount(() => { void load(); void loadDepartments(); });
const filteredRows = createMemo(() => {
let r = rows();
@ -209,7 +212,7 @@ export default function DesignationManagementPage() {
});
const resetForm = () => {
setEditingId(null); setName(''); setCode(''); setDepartment('');
setEditingId(null); setName(''); setCode(''); setDepartmentId('');
setLevel(''); setDescription(''); setStatus('ACTIVE');
setCanManageTeam(false); setCanApprove(false); setFormTab('general'); setError('');
};
@ -218,9 +221,9 @@ export default function DesignationManagementPage() {
const openEdit = (row: DesignationRecord) => {
setEditingId(row.id);
setName(row.name || ''); setCode(String(row.code || ''));
setDepartment(String(row.department || '')); setLevel(String(row.level || ''));
setDescription(String(row.description || ''));
setName(row.name || ''); setCode(row.code || '');
setDepartmentId(row.departmentId || ''); setLevel(row.level || '');
setDescription(row.description || '');
setStatus(row.status === 'INACTIVE' ? 'INACTIVE' : 'ACTIVE');
setCanManageTeam(Boolean(row.canManageTeam)); setCanApprove(Boolean(row.canApprove));
setFormTab('general'); setView('form'); setOpenMenuId(null);
@ -235,16 +238,18 @@ export default function DesignationManagementPage() {
setIsSaving(true);
setError('');
const payload = {
const payload: Record<string, unknown> = {
name: name().trim(),
code: code().trim(),
department: department().trim(),
level: level().trim(),
level: level().trim() || null,
description: description().trim() || null,
status: status(),
can_manage_team: canManageTeam(),
can_approve: canApprove(),
};
if (departmentId().trim()) {
payload.department_id = departmentId().trim();
}
try {
const endpoint = editingId()
@ -594,9 +599,9 @@ export default function DesignationManagementPage() {
<FormInput label="Designation Code" required value={code()} onInput={setCode} placeholder="e.g. SSE-001" />
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:20px">
<FormSelect label="Department" required value={department()} onChange={setDepartment}>
<FormSelect label="Department" value={departmentId()} onChange={setDepartmentId}>
<option value="">Select department</option>
<For each={DEPARTMENTS}>{(d) => <option value={d}>{d}</option>}</For>
<For each={departments()}>{(d) => <option value={d.id}>{d.name}</option>}</For>
</FormSelect>
<FormSelect label="Designation Level" required value={level()} onChange={setLevel}>
<option value="">Select level</option>