Files
worldshine-redesign/client/src/components/employees/ExternalEmployeesImport.js
Lixian Zhou 1500254db7
All checks were successful
Build And Deploy Main / build-and-deploy (push) Successful in 36s
fix
2026-03-16 16:22:38 -04:00

305 lines
11 KiB
JavaScript

import React, { useEffect, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { Button, Modal, Spinner } from "react-bootstrap";
import { AuthService, EmployeeService, EventsService } from "../../services";
import { EMPLOYEE_PERMISSION_GROUPS } from "../../shared";
const SYSTEM_ACCESS_PERMISSION = "System Access";
const ExternalEmployeesImport = () => {
const navigate = useNavigate();
const currentSite = EventsService.site || 3;
const [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false);
const [employees, setEmployees] = useState([]);
const [siteFilter, setSiteFilter] = useState(currentSite);
const [keyword, setKeyword] = useState("");
const [showPermissionModal, setShowPermissionModal] = useState(false);
const [selectedEmployee, setSelectedEmployee] = useState(undefined);
const [selectedPermissions, setSelectedPermissions] = useState([SYSTEM_ACCESS_PERMISSION]);
const [selectedAllowSite, setSelectedAllowSite] = useState(currentSite);
const [existingPermissionMap, setExistingPermissionMap] = useState({});
useEffect(() => {
if (!AuthService.canAddOrEditEmployees()) {
window.alert("You haven't login yet OR this user does not have access to this page. Please change an admin account to login.");
AuthService.logout();
navigate("/login");
return;
}
loadExternalEmployees();
loadExistingPermissions();
}, []);
const loadExistingPermissions = () => {
EmployeeService.getExternalUserPermissionsList(currentSite)
.then((response) => {
const records = Array.isArray(response?.data) ? response.data : [];
const nextMap = {};
records.forEach((item) => {
const key = item?.external_user_id;
if (!key) return;
nextMap[key] = item;
});
setExistingPermissionMap(nextMap);
})
.catch(() => {
setExistingPermissionMap({});
});
};
const loadExternalEmployees = () => {
setLoading(true);
EmployeeService.getExternalEmployeesList()
.then((response) => {
setEmployees(Array.isArray(response?.data) ? response.data : []);
})
.catch((error) => {
window.alert(error?.response?.data?.message || "Failed to load employees from HR system.");
})
.finally(() => {
setLoading(false);
});
};
const filteredEmployees = useMemo(() => {
return (employees || [])
.filter((item) => siteFilter === 'all' || Number(item?.site) === Number(siteFilter))
.filter((item) => {
if (!keyword) return true;
const key = keyword.toLowerCase();
return (
(item?.username || "").toLowerCase().includes(key) ||
(item?.name || "").toLowerCase().includes(key) ||
(item?.title || "").toLowerCase().includes(key)
);
});
}, [employees, siteFilter, keyword]);
const openPermissionModal = (employee) => {
const allowSite = Number(currentSite);
setSelectedEmployee(employee);
setSelectedAllowSite(allowSite);
setSelectedPermissions([SYSTEM_ACCESS_PERMISSION]);
setShowPermissionModal(true);
EmployeeService.getExternalUserPermission(employee?.employee_id, allowSite)
.then((response) => {
const existingPermissions = Array.isArray(response?.data?.permissions) ? response.data.permissions : [];
const nextPermissions = Array.from(new Set([SYSTEM_ACCESS_PERMISSION, ...existingPermissions]));
setSelectedPermissions(nextPermissions);
})
.catch(() => {
setSelectedPermissions([SYSTEM_ACCESS_PERMISSION]);
});
};
const closePermissionModal = () => {
if (saving) return;
setShowPermissionModal(false);
setSelectedEmployee(undefined);
setSelectedPermissions([SYSTEM_ACCESS_PERMISSION]);
setSelectedAllowSite(currentSite);
};
const togglePermission = (permissionKey) => {
if (permissionKey === SYSTEM_ACCESS_PERMISSION) return;
setSelectedPermissions((prev) => {
if (prev.includes(permissionKey)) {
return prev.filter((item) => item !== permissionKey);
}
return [...prev, permissionKey];
});
};
const isPermissionGroupFullySelected = (permissionItems = []) => {
return permissionItems.length > 0 && permissionItems.every((permissionKey) => selectedPermissions.includes(permissionKey));
};
const togglePermissionGroup = (permissionItems = [], checked) => {
if (!Array.isArray(permissionItems) || permissionItems.length === 0) return;
setSelectedPermissions((prev) => {
const nextSet = new Set(prev);
permissionItems.forEach((permissionKey) => {
if (permissionKey === SYSTEM_ACCESS_PERMISSION) {
nextSet.add(SYSTEM_ACCESS_PERMISSION);
return;
}
if (checked) {
nextSet.add(permissionKey);
} else {
nextSet.delete(permissionKey);
}
});
return Array.from(nextSet);
});
};
const savePermissions = () => {
if (!selectedEmployee?.employee_id) return;
setSaving(true);
EmployeeService.saveExternalUserPermission({
external_user_id: selectedEmployee.employee_id,
username: selectedEmployee.username || "",
name: selectedEmployee.name || "",
title: selectedEmployee.title || "",
email: selectedEmployee.email || "",
allow_site: Number(selectedAllowSite),
permissions: selectedPermissions
})
.then(() => {
loadExistingPermissions();
closePermissionModal();
})
.catch((error) => {
window.alert(error?.response?.data?.message || "Failed to save external user permissions.");
})
.finally(() => {
setSaving(false);
});
};
return (
<>
<div className="list row mb-4">
<div className="col-md-12 text-primary">
<h5>
Add New Employee From HR System
<button className="btn btn-link btn-sm" onClick={() => navigate("/employees/list")}>Back</button>
</h5>
</div>
</div>
<div className="list row mb-4">
<div className="col-md-12">
<div className="mb-3 d-flex align-items-center" style={{ gap: "12px", flexWrap: "wrap" }}>
<label>
Filter By Site:
<select
className="ms-2"
value={siteFilter}
onChange={(e) => setSiteFilter(e.currentTarget.value)}
>
<option value="all">All Sites</option>
<option value={1}>Site 1</option>
<option value={2}>Site 2</option>
<option value={3}>Site 3</option>
<option value={4}>Site 4</option>
<option value={5}>Site 5</option>
</select>
</label>
<label>
Filter By Username/Name:
<input
className="ms-2"
type="text"
value={keyword}
onChange={(e) => setKeyword(e.currentTarget.value)}
/>
</label>
<button className="btn btn-primary btn-sm" onClick={loadExternalEmployees} disabled={loading}>
{loading ? "Loading..." : "Refresh"}
</button>
</div>
{loading ? (
<div className="py-4"><Spinner size="sm" className="me-2" />Loading employees...</div>
) : (
<table className="personnel-info-table">
<thead>
<tr>
<th>Username</th>
<th>Name</th>
<th>Title</th>
<th>Site</th>
<th></th>
</tr>
</thead>
<tbody>
{filteredEmployees.map((item) => (
<tr key={`${item?.employee_id}-${item?.site}`}>
<td>{item?.username}</td>
<td>{item?.name}</td>
<td>{item?.title}</td>
<td>{item?.site}</td>
<td>
{(() => {
const hasExistingPermission = !!existingPermissionMap?.[item?.employee_id];
return (
<button
className="btn btn-primary btn-sm"
onClick={() => openPermissionModal(item)}
>
{hasExistingPermission ? "Edit" : "Add"}
</button>
);
})()}
</td>
</tr>
))}
{filteredEmployees.length === 0 && (
<tr>
<td colSpan={5} style={{ textAlign: "center" }}>No active employees found for selected site.</td>
</tr>
)}
</tbody>
</table>
)}
</div>
</div>
<Modal show={showPermissionModal} onHide={closePermissionModal} size="lg">
<Modal.Header closeButton>
<Modal.Title>Set Permissions - {selectedEmployee?.username}</Modal.Title>
</Modal.Header>
<Modal.Body>
<div className="mb-3">
<strong>Allow Site:</strong> {selectedAllowSite}
</div>
{Object.entries(EMPLOYEE_PERMISSION_GROUPS).map(([groupName, permissionItems]) => (
<div key={groupName} className="mb-3">
<div className="d-flex align-items-center justify-content-between mb-1" style={{ gap: "16px" }}>
<div className="text-primary">{groupName}</div>
<label>
<input
type="checkbox"
className="me-2"
checked={isPermissionGroupFullySelected(permissionItems)}
onChange={(e) => togglePermissionGroup(permissionItems, e.currentTarget.checked)}
disabled={groupName === "System"}
/>
Select All
</label>
</div>
<div style={{ display: "flex", flexWrap: "wrap", gap: "10px 18px" }}>
{permissionItems.map((permissionKey) => (
<label key={permissionKey} style={{ minWidth: "280px" }}>
<input
type="checkbox"
className="me-2"
checked={selectedPermissions.includes(permissionKey)}
onChange={() => togglePermission(permissionKey)}
disabled={permissionKey === SYSTEM_ACCESS_PERMISSION}
/>
{permissionKey}
{permissionKey === SYSTEM_ACCESS_PERMISSION ? " (required)" : ""}
</label>
))}
</div>
</div>
))}
</Modal.Body>
<Modal.Footer>
<Button variant="secondary" onClick={closePermissionModal} disabled={saving}>
Cancel
</Button>
<Button variant="primary" onClick={savePermissions} disabled={saving}>
{saving ? <><Spinner size="sm" className="me-2" />Saving...</> : "Done"}
</Button>
</Modal.Footer>
</Modal>
</>
);
};
export default ExternalEmployeesImport;