diff --git a/apps/edr-freight-web/backoffice/src/pages/dashboard/user-management/UserManagementPage.tsx b/apps/edr-freight-web/backoffice/src/pages/dashboard/user-management/UserManagementPage.tsx index c1683aa11..3d490fcf4 100644 --- a/apps/edr-freight-web/backoffice/src/pages/dashboard/user-management/UserManagementPage.tsx +++ b/apps/edr-freight-web/backoffice/src/pages/dashboard/user-management/UserManagementPage.tsx @@ -12,6 +12,11 @@ import { DropdownMenuItem, DropdownMenuSeparator, DropdownMenuTrigger, + Select, + SelectContent, + SelectItem, + SelectTrigger, + SelectValue, } from "@edr/ui-common"; import { Building2, @@ -53,9 +58,16 @@ interface PositionRecord { key: string; name: LocaleText; parentPositionId?: string | null; + positionTypeId?: string | null; rank?: number; } +interface PositionTypeRecord { + id: string; + key: string; + name: LocaleText; +} + interface EmployeeUserRecord { id: string; name?: LocaleText; @@ -104,6 +116,7 @@ interface PositionFormState { nameAm: string; key: string; parentPositionId: string; + positionTypeId: string; } interface UnitFormState { @@ -147,6 +160,7 @@ const emptyPositionForm: PositionFormState = { nameAm: "", key: "", parentPositionId: "", + positionTypeId: "", }; const inputClassName = @@ -434,6 +448,7 @@ const UserManagementPage = () => { const [organizations, setOrganizations] = useState([]); const [units, setUnits] = useState([]); const [positions, setPositions] = useState([]); + const [positionTypes, setPositionTypes] = useState([]); const [orgEmployees, setOrgEmployees] = useState([]); const [positionMembers, setPositionMembers] = useState([]); const [selectedOrgConfiguration, setSelectedOrgConfiguration] = @@ -447,9 +462,11 @@ const UserManagementPage = () => { const [loading, setLoading] = useState(true); const [membersLoading, setMembersLoading] = useState(false); const [orgEmployeesLoading, setOrgEmployeesLoading] = useState(false); + const [positionTypesLoading, setPositionTypesLoading] = useState(false); const [actionError, setActionError] = useState(null); const [actionSuccess, setActionSuccess] = useState(null); const [loadError, setLoadError] = useState(null); + const [positionTypesError, setPositionTypesError] = useState(null); const [submitting, setSubmitting] = useState(false); const [unitSearch, setUnitSearch] = useState(""); const [positionSearch, setPositionSearch] = useState(""); @@ -664,6 +681,25 @@ const UserManagementPage = () => { } }, []); + const loadPositionTypes = useCallback(async (unitId: string) => { + setPositionTypesLoading(true); + setPositionTypesError(null); + + try { + const response = await api.get>( + `/position-types/list-with-commons/${unitId}?take=1000&skip=0&orderBy=createdAt:Desc`, + ); + setPositionTypes(getItems(response.data)); + } catch (error) { + const message = getErrorMessage(error, "Failed to load position types."); + setPositionTypes([]); + setPositionTypesError(message); + throw error; + } finally { + setPositionTypesLoading(false); + } + }, []); + const loadPositionMembers = useCallback(async (positionId: string | null) => { if (!positionId) { setPositionMembers([]); @@ -748,6 +784,8 @@ const UserManagementPage = () => { if (!selectedOrgId) { setUnits([]); setPositions([]); + setPositionTypes([]); + setPositionTypesError(null); setSelectedUnitId(null); setSelectedPositionId(null); setExpandedDepartmentIds(new Set()); @@ -772,6 +810,8 @@ const UserManagementPage = () => { useEffect(() => { if (!selectedUnitId) { setPositions([]); + setPositionTypes([]); + setPositionTypesError(null); setSelectedPositionId(null); setExpandedDepartmentIds(new Set()); setPositionMembers([]); @@ -865,16 +905,27 @@ const UserManagementPage = () => { }); }; - const openCreateSubDepartmentDialog = (parent: PositionRecord) => { - setSelectedPositionId(parent.id); - setExpandedDepartmentIds((current) => new Set(current).add(parent.id)); - setCreatePositionMode("create-child"); - setPositionForm({ - ...emptyPositionForm, - parentPositionId: parent.id, - }); + const openCreateSubDepartmentDialog = async (parent: PositionRecord) => { + if (!selectedUnit) { + setActionError("Select a unit before creating a department."); + return; + } + resetMessages(); - setIsCreatePositionOpen(true); + + try { + await loadPositionTypes(selectedUnit.id); + setSelectedPositionId(parent.id); + setExpandedDepartmentIds((current) => new Set(current).add(parent.id)); + setCreatePositionMode("create-child"); + setPositionForm({ + ...emptyPositionForm, + parentPositionId: parent.id, + }); + setIsCreatePositionOpen(true); + } catch (error) { + setActionError(getErrorMessage(error, "Failed to load position types.")); + } }; const openInviteForDepartment = (position: PositionRecord) => { @@ -905,26 +956,52 @@ const UserManagementPage = () => { setIsEditUnitOpen(true); }; - const openCreatePositionDialog = (mode: "create-root" | "create-child") => { - setCreatePositionMode(mode); - setPositionForm({ - ...emptyPositionForm, - parentPositionId: mode === "create-child" && selectedPosition ? selectedPosition.id : "", - }); + const openCreatePositionDialog = async ( + mode: "create-root" | "create-child", + unitId = selectedUnit?.id, + ) => { + if (!unitId) { + setActionError("Select a unit before creating a department."); + return; + } + resetMessages(); - setIsCreatePositionOpen(true); + + try { + await loadPositionTypes(unitId); + setCreatePositionMode(mode); + setPositionForm({ + ...emptyPositionForm, + parentPositionId: mode === "create-child" && selectedPosition ? selectedPosition.id : "", + }); + setIsCreatePositionOpen(true); + } catch (error) { + setActionError(getErrorMessage(error, "Failed to load position types.")); + } }; - const openEditPositionDialog = (position: PositionRecord) => { - setPositionForm({ - id: position.id, - nameEn: position.name.en ?? "", - nameAm: position.name.am ?? "", - key: position.key, - parentPositionId: position.parentPositionId ?? "", - }); + const openEditPositionDialog = async (position: PositionRecord) => { + if (!selectedUnit) { + setActionError("Select a unit before editing a department."); + return; + } + resetMessages(); - setIsEditPositionOpen(true); + + try { + await loadPositionTypes(selectedUnit.id); + setPositionForm({ + id: position.id, + nameEn: position.name.en ?? "", + nameAm: position.name.am ?? "", + key: position.key, + parentPositionId: position.parentPositionId ?? "", + positionTypeId: position.positionTypeId ?? "", + }); + setIsEditPositionOpen(true); + } catch (error) { + setActionError(getErrorMessage(error, "Failed to load position types.")); + } }; const handleCreateUnit = async (event: React.FormEvent) => { @@ -1007,6 +1084,11 @@ const UserManagementPage = () => { return; } + if (!positionForm.positionTypeId) { + setActionError("Select a position type before saving the department."); + return; + } + setSubmitting(true); resetMessages(); @@ -1018,6 +1100,7 @@ const UserManagementPage = () => { unitId: selectedUnit.id, organizationId: selectedOrganization.id, parentPositionId: positionForm.parentPositionId || null, + positionTypeId: positionForm.positionTypeId, rank: 0, }; @@ -1419,8 +1502,10 @@ const UserManagementPage = () => { { event.preventDefault(); - void handleSelectUnit(item.id); - openCreatePositionDialog("create-root"); + void (async () => { + await handleSelectUnit(item.id); + await openCreatePositionDialog("create-root", item.id); + })(); }} > Add Department @@ -1495,7 +1580,7 @@ const UserManagementPage = () => { onAddSubDepartment={openCreateSubDepartmentDialog} onEdit={(position) => { setSelectedPositionId(position.id); - openEditPositionDialog(position); + void openEditPositionDialog(position); }} onDelete={(position) => { setSelectedPositionId(position.id); @@ -1804,6 +1889,31 @@ const UserManagementPage = () => { + + + {positionTypesError ? ( +

{positionTypesError}

+ ) : null} +
+ setPositionForm((current) => ({ ...current, positionTypeId: value })) + } + disabled={positionTypesLoading || submitting} + > + + + + + {positionTypes.map((positionType) => ( + + {getLocaleLabel(positionType.name, positionType.key)} + + ))} + + + {positionTypesError ? ( +

{positionTypesError}

+ ) : null} +