Files
worldshine-redesign/client/src/components/employees/ExternalEmployeesImport.js
Lixian Zhou 08756fc941
All checks were successful
Build And Deploy Main / build-and-deploy (push) Successful in 34s
fix
2026-03-16 15:46:37 -04:00

245 lines
8.9 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 [loading, setLoading] = useState(false);
const [saving, setSaving] = useState(false);
const [employees, setEmployees] = useState([]);
const [siteFilter, setSiteFilter] = useState(EventsService.site || 3);
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(EventsService.site || 3);
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();
}, []);
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 = siteFilter === 'all'
? (Number(employee?.site) || EventsService.site || 3)
: Number(siteFilter);
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(EventsService.site || 3);
};
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 savePermissions = () => {
if (!selectedEmployee?.employee_id) return;
setSaving(true);
EmployeeService.saveExternalUserPermission({
external_user_id: selectedEmployee.employee_id,
username: selectedEmployee.username || "",
name: selectedEmployee.name || "",
email: selectedEmployee.email || "",
allow_site: Number(selectedAllowSite),
permissions: selectedPermissions
})
.then(() => {
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>
<button
className="btn btn-primary btn-sm"
onClick={() => openPermissionModal(item)}
>
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="text-primary mb-1">{groupName}</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;