// Employees.jsx import React, { useState, useEffect, useMemo, useRef } from "react"; import Swal from "sweetalert2"; import { confirmHoldToDelete } from "../../components/utils/confirmHoldToDelete"; import ModernButton from "../ui/ModernButton"; import EmployeeModal from "./EmployeeModal"; import EmployeeAssignmentModal from "./EmployeeAssignmentModal"; import AssignScheduleModal from "../schedule-manager/schedule-manager-components/AssignScheduleModal"; import { useLocation } from "react-router-dom"; import "../../../Styles/components/employee/employeejsx.css"; import BASE_URL from "@backend/server/config"; import Breadcrumbs from "../breadcrumbs/Breadcrumbs"; import BulkEmployeeActionsModal from "./BulkEmployeeActionsModal"; import EmployeeListView from "./employeeTableMode/employeeListView"; import EmployeeGridView from "./employeeTableMode/employeeGridView"; import { useSession } from "../../context/SessionContext"; import { secureGetItem } from "../utils/secureStorage"; import usePermissions from "../../users/hooks/usePermissions"; import { Tooltip } from "@mui/material"; import Tabs from "../breadcrumbs/Tabs"; import { Printer, Trash2, Search, Plus, AlignJustify, Grid3x3, UserRoundX, Users, Briefcase, Building2, Settings, ChevronLeft, ChevronRight, Fingerprint, } from "lucide-react"; import { useNavigate } from "react-router-dom"; function Employees() { const { state } = useLocation(); const { user } = useSession(); const { permissions, loading: permLoading } = usePermissions(user?.username); const [customId, setCustomId] = useState(""); const [statusFilter, setStatusFilter] = useState("active"); const [typeFilter, setTypeFilter] = useState("all"); const [branchFilter, setBranchFilter] = useState("all"); const [departmentFilter, setDepartmentFilter] = useState("all"); const [positionFilter, setPositionFilter] = useState("all"); const navigate = useNavigate(); const [employees, setEmployees] = useState([]); const [isInitialLoading, setIsInitialLoading] = useState(true); const [isListRefreshing, setIsListRefreshing] = useState(false); const [isSavingEmployee, setIsSavingEmployee] = useState(false); const [isLoadingLookups, setIsLoadingLookups] = useState(false); const [error, setError] = useState(""); const [refreshNotice, setRefreshNotice] = useState(""); const [isModalOpen, setIsModalOpen] = useState(false); const [editingEmployee, setEditingEmployee] = useState(null); const [selectedEmployees, setSelectedEmployees] = useState([]); const [searchInput, setSearchInput] = useState(""); const [searchQuery, setSearchQuery] = useState(""); const [activeView, setActiveView] = useState("list"); const [isBulkModalOpen, setIsBulkModalOpen] = useState(false); const [bulkApplying, setBulkApplying] = useState(false); const [assignmentOptions, setAssignmentOptions] = useState({ brands: [], branches: [], }); const [assignmentModalEmployee, setAssignmentModalEmployee] = useState(null); const [isAssignmentModalOpen, setIsAssignmentModalOpen] = useState(false); const [mobileFiltersOpen, setMobileFiltersOpen] = useState(false); const [mobileActionsOpen, setMobileActionsOpen] = useState(false); const [isAssignModalOpen, setIsAssignModalOpen] = useState(false); const [assignPreselectedEmployees, setAssignPreselectedEmployees] = useState( [], ); const [gridCurrentPage, setGridCurrentPage] = useState(1); const [workTimes, setWorkTimes] = useState([]); const tabs = useMemo( () => [ { key: "employees", label: "Employee List", sublabel: "View & Manage Employees", icon: Users, onClick: () => navigate("/employees"), }, { key: "departments", label: "Departments", sublabel: "Manage Employee Departments", icon: Briefcase, onClick: () => navigate("/department"), }, { key: "branches", label: "Branch", sublabel: "Manage Branches", icon: Building2, onClick: () => navigate("/branches"), }, { key: "biometrics", label: "Biometrics", sublabel: "Manage Biometrics", icon: Fingerprint, onClick: () => navigate("/UsersBiometrics"), }, ], [navigate], ); const [assignModalKey, setAssignModalKey] = useState(0); const latestEmployeesRequestRef = useRef(0); const normalizedRole = String(user?.role || "") .toUpperCase() .replace(/_/g, " "); const canManageAssignments = ["ADMIN", "SUPER ADMIN"].includes( normalizedRole, ); const cleanupBlockingOverlays = () => { if (typeof document === "undefined") return; try { document.body.classList.remove("swal2-shown", "swal2-height-auto"); document.body.style.removeProperty("overflow"); document.body.style.removeProperty("padding-right"); document.body.style.removeProperty("pointer-events"); document.documentElement.style.removeProperty("overflow"); document.documentElement.style.removeProperty("padding-right"); document.querySelectorAll(".swal2-container").forEach((el) => { const popup = el.querySelector(".swal2-popup"); const backdropActive = el.classList.contains("swal2-backdrop-show"); const toastActive = el.classList.contains("swal2-toast-shown"); if (!popup && !backdropActive && !toastActive) { el.remove(); } }); if (!isAssignModalOpen) { document.querySelectorAll(".MuiModal-root").forEach((el) => { const hidden = el.classList.contains("MuiModal-hidden") || el.getAttribute("aria-hidden") === "true"; if (hidden) { el.style.pointerEvents = "none"; const backdrop = el.querySelector(".MuiBackdrop-root"); if (backdrop) backdrop.style.pointerEvents = "none"; } }); document.querySelectorAll(".MuiBackdrop-root").forEach((el) => { const style = window.getComputedStyle(el); const hidden = style.visibility === "hidden" || Number(style.opacity || "1") === 0; if (hidden) { el.style.pointerEvents = "none"; } }); } } catch (err) { console.warn("Overlay cleanup failed:", err); } }; const breadcrumbItems = [ !permLoading && permissions?.employee_list && { key: "dashboard", label: "Employee Lists", path: "/employees", }, !permLoading && permissions?.department && { key: "employees", label: "Departments", path: "/department", }, !permLoading && permissions?.branches && { key: "branches", label: "Branches", path: "/branches", }, !permLoading && permissions?.user_biometrics && { key: "biometrics", label: "Biometrics", path: "/UsersBiometrics", }, ].filter(Boolean); const fetchEmployees = async ({ background = false, failureNotice = "", } = {}) => { const requestId = latestEmployeesRequestRef.current + 1; latestEmployeesRequestRef.current = requestId; const showAsBackgroundRefresh = background || employees.length > 0; if (showAsBackgroundRefresh) { setIsListRefreshing(true); } else { setIsInitialLoading(true); } setError(""); if (!failureNotice) setRefreshNotice(""); try { const response = await fetch(`${BASE_URL}/api/employeesSide/employees`); if (!response.ok) { throw new Error(`Employee list request failed (${response.status})`); } const data = await response.json(); if (requestId !== latestEmployeesRequestRef.current) return; if (data.message) { console.warn("employees.php message:", data.message); setEmployees([]); } else { setEmployees(Array.isArray(data) ? data : []); } setRefreshNotice(""); } catch (error) { if (requestId !== latestEmployeesRequestRef.current) return; console.error("Error fetching employee data:", error); if (showAsBackgroundRefresh) { setRefreshNotice( failureNotice || "List refresh failed. Your last successful changes remain visible.", ); } else { setError("Error fetching employees. Check console."); setEmployees([]); } } finally { if (requestId === latestEmployeesRequestRef.current) { if (showAsBackgroundRefresh) { setIsListRefreshing(false); } else { setIsInitialLoading(false); } } } }; const fetchAssignmentOptions = async () => { try { const response = await fetch( `${BASE_URL}/api/employee_assignment/read_assignment_options`, ); const data = await response.json(); const source = data?.data || data || {}; setAssignmentOptions({ brands: Array.isArray(source.brands) ? source.brands : [], branches: Array.isArray(source.branches) ? source.branches : [], }); } catch (error) { console.error("Error fetching assignment options:", error); setAssignmentOptions({ brands: [], branches: [] }); } }; const fetchWorkTimes = async () => { try { const res = await fetch(`${BASE_URL}/api/work_time/read_work_time`); const data = await res.json(); setWorkTimes(Array.isArray(data) ? data : []); } catch (err) { console.warn("Failed to fetch workTimes:", err); setWorkTimes([]); } }; const fetchLookupData = async () => { setIsLoadingLookups(true); try { await Promise.all([fetchWorkTimes(), fetchAssignmentOptions()]); } finally { setIsLoadingLookups(false); } }; useEffect(() => { let isMounted = true; const init = async () => { fetchEmployees(); fetchLookupData(); }; if (isMounted) init(); return () => { isMounted = false; }; // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { const timeoutId = window.setTimeout(() => { setSearchQuery(searchInput); }, 200); return () => window.clearTimeout(timeoutId); }, [searchInput]); useEffect(() => { setGridCurrentPage(1); }, [ searchQuery, statusFilter, typeFilter, branchFilter, departmentFilter, positionFilter, ]); useEffect(() => { if ( isModalOpen || isAssignModalOpen || isBulkModalOpen || isAssignmentModalOpen ) return; if (typeof window === "undefined") return; const rafId = window.requestAnimationFrame(() => { cleanupBlockingOverlays(); }); const timeoutId = window.setTimeout(() => { cleanupBlockingOverlays(); }, 250); return () => { window.cancelAnimationFrame(rafId); window.clearTimeout(timeoutId); }; }, [isModalOpen, isAssignModalOpen, isBulkModalOpen, isAssignmentModalOpen]); const handleListView = () => { setActiveView("list"); }; const handleGridView = () => { setActiveView("grid"); }; const patchSavedEmployee = (savedEmployee, responseData = {}) => { const oldEmployeeId = String( savedEmployee.old_employee_id || savedEmployee.employee_id || "", ); const nextEmployeeId = String( responseData.employee_id || savedEmployee.employee_id || oldEmployeeId, ); if (!oldEmployeeId) return; const assignment = responseData.assignment || {}; const patch = { ...savedEmployee, ...assignment, employee_id: nextEmployeeId, }; delete patch.old_employee_id; delete patch.current_user; delete patch.password; if (patch.brand_id) { const brand = assignmentOptions.brands.find( (item) => String(item.brand_id) === String(patch.brand_id), ); if (brand?.brand_name) patch.brand_name = brand.brand_name; } if (Object.prototype.hasOwnProperty.call(patch, "branch_id")) { const branch = assignmentOptions.branches.find( (item) => String(item.branch_id) === String(patch.branch_id), ); patch.branch_name = assignment.branch_name ?? branch?.branch_name ?? branch?.name ?? patch.branch_name ?? null; } setEmployees((previous) => previous.map((employee) => String(employee.employee_id) === oldEmployeeId ? { ...employee, ...patch } : employee, ), ); setEditingEmployee((previous) => previous && String(previous.employee_id) === oldEmployeeId ? { ...previous, ...patch } : previous, ); }; const handleAddOrUpdateEmployee = async (newEmployee, mode = "add") => { const url = mode === "update" ? `${BASE_URL}/api/employeesSide/update_employee` : `${BASE_URL}/api/employeesSide/add_employee`; const method = mode === "update" ? "PUT" : "POST"; const currentUser = secureGetItem("user", {}, window.localStorage) || {}; const payload = { ...newEmployee, current_user: { full_name: currentUser?.full_name || currentUser?.username || "Unknown", role: currentUser?.role || "GUEST", }, }; try { setIsSavingEmployee(true); setRefreshNotice(""); const response = await fetch(url, { method, headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }); const text = await response.text(); let data; try { data = JSON.parse(text); } catch { console.error("Server returned non-JSON:", text); return { status: "error", message: "Unexpected server response. Check console.", }; } if (data.status === "success" || data.success) { if (mode === "update") { patchSavedEmployee(newEmployee, data); fetchEmployees({ background: true, failureNotice: "Saved, but list refresh failed. Please reload if needed.", }); } else { await fetchEmployees(); } return { ...data, status: "success", employee_id: data.employee_id || newEmployee.employee_id, email: data.email || newEmployee.email, password: data.password || data.generated_password || null, }; } return { ...data, status: "error", message: data.message || "Failed to save employee.", }; } catch (error) { console.error("Error saving employee:", error); return { status: "error", message: error.message || "Network error", }; } finally { setIsSavingEmployee(false); } }; const handleEditEmployee = (employee) => { setEditingEmployee(employee); setIsModalOpen(true); }; const handleOpenAssignmentModal = (employee) => { if (!canManageAssignments) return; setAssignmentModalEmployee(employee); setIsAssignmentModalOpen(true); }; const handleAssignmentSaved = async () => { await fetchEmployees(); }; const handleDeleteEmployee = async (employee_id) => { const result = await confirmHoldToDelete({ title: "Are you sure?", text: "This action cannot be undone!", }); if (!result.isConfirmed) return; try { const currentUser = secureGetItem("user", {}, window.localStorage) || {}; const response = await fetch( `${BASE_URL}/api/employeesSide/delete_employee?id=${employee_id}&full_name=${encodeURIComponent(currentUser.full_name || "")}&role=${encodeURIComponent(currentUser.role || "")}`, { method: "DELETE", headers: { "Content-Type": "application/json" }, }, ); const data = await response.json(); if (data.success || data.status === "success") { setEmployees((prev) => prev.filter((emp) => emp.employee_id !== employee_id), ); Swal.fire({ icon: "success", title: "Deleted", text: data.message || "Employee deleted", }); } else { Swal.fire({ icon: "error", title: "Error", text: data.message || "Failed to delete", }); } } catch (error) { console.error("Error deleting employee:", error); Swal.fire({ icon: "error", title: "Error", text: "Something went wrong. See console.", }); } }; const handleToggleStatus = async (employee) => { const newStatus = employee.status === "active" ? "inactive" : "active"; try { const response = await fetch( `${BASE_URL}/api/employeesSide/update_employee_status`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ employee_id: employee.employee_id, status: newStatus, }), }, ); const data = await response.json(); if (data.success || data.status === "success") { setEmployees((prev) => prev.map((emp) => emp.employee_id === employee.employee_id ? { ...emp, status: newStatus } : emp, ), ); Swal.fire("Updated!", `Employee marked as ${newStatus}`, "success"); } else { Swal.fire("Error!", data.message || "Status update failed.", "error"); } } catch (error) { console.error("Error updating status:", error); Swal.fire("Error!", "Something went wrong.", "error"); } }; const handleDeleteSelectedEmployees = async () => { if (selectedEmployees.length === 0) { Swal.fire("Info", "No employees selected.", "info"); return; } const confirmed = await confirmHoldToDelete({ title: `Delete ${selectedEmployees.length} employees?`, text: "This action cannot be undone.", }); if (!confirmed.isConfirmed) return; try { const response = await fetch( `${BASE_URL}/api/employeesSide/delete_multiple`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ employee_ids: selectedEmployees }), }, ); const data = await response.json(); if (data.success) { setEmployees((prev) => prev.filter((emp) => !selectedEmployees.includes(emp.employee_id)), ); setSelectedEmployees([]); Swal.fire("Deleted", "Selected employees deleted.", "success"); } else { Swal.fire( "Error", data.message || "Failed to delete employees.", "error", ); } } catch (error) { console.error("Error deleting employees:", error); Swal.fire("Error", "Error deleting employees. See console.", "error"); } }; const handleOpenBulkSettings = () => { if (selectedEmployees.length === 0) { Swal.fire("Info", "Select employees first.", "info"); return; } setIsBulkModalOpen(true); }; const handleBulkUpdateEmployees = async (updates) => { if (selectedEmployees.length === 0) { Swal.fire("Info", "Select employees first.", "info"); return; } const payload = { employee_ids: selectedEmployees, ...updates, }; const currentUser = secureGetItem("user", {}, window.localStorage) || {}; payload.current_user = { full_name: currentUser?.full_name || currentUser?.username || "Unknown", role: currentUser?.role || "GUEST", }; setBulkApplying(true); try { const response = await fetch( `${BASE_URL}/api/employeesSide/bulk_update_employees`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload), }, ); const text = await response.text(); let data; try { data = JSON.parse(text); } catch { console.error("Bulk update returned non-JSON:", text); Swal.fire( "Error", "Unexpected server response. Check console.", "error", ); return; } if (data.success || data.status === "success") { await fetchEmployees(); setSelectedEmployees([]); setIsBulkModalOpen(false); Swal.fire( "Updated", data.message || "Selected employees were updated.", "success", ); } else { Swal.fire("Error", data.message || "Bulk update failed.", "error"); } } catch (error) { console.error("Error bulk updating employees:", error); Swal.fire("Error", "Something went wrong. See console.", "error"); } finally { setBulkApplying(false); } }; const handleSelectAll = (event, visibleEmployees = employees) => { const visibleIds = visibleEmployees.map((emp) => emp.employee_id); if (event.target.checked) { setSelectedEmployees((prev) => Array.from(new Set([...prev, ...visibleIds])), ); } else { setSelectedEmployees((prev) => prev.filter((id) => !visibleIds.includes(id)), ); } }; const handleSelectEmployee = (employeeId) => { setSelectedEmployees((prev) => prev.includes(employeeId) ? prev.filter((id) => id !== employeeId) : [...prev, employeeId], ); }; const normalize = (v) => v === undefined || v === null || v === "" ? "Not assigned" : String(v); const branchDisplayName = (employee) => { if (employee?.assignment_status === "invalid_no_brand") { return "Invalid: No Brand"; } return employee?.branch_name ? employee.branch_name : "Unassigned Branch"; }; const matchesBaseFilters = ( emp, { ignoreBranch = false, ignoreDept = false, ignorePos = false, ignoreType = false, ignoreStatus = false, } = {}, ) => { const fullName = [emp.first_name, emp.middle_name, emp.last_name] .filter(Boolean) .join(" ") .toLowerCase(); const safeQuery = searchQuery.replace(/\s+/g, " ").toLowerCase().trim(); const queryWords = safeQuery ? safeQuery.split(" ") : []; const haystack = [ fullName, emp.employee_id, emp.person_id, emp.biometrics_id ] .filter(Boolean) .join(" ") .toLowerCase() .replace(/\s+/g, " "); const matchesSearch = queryWords.length === 0 || queryWords.every(word => haystack.includes(word)); const matchesStatus = ignoreStatus ? true : statusFilter === "all" || emp.status === statusFilter; const matchesType = ignoreType ? true : typeFilter === "all" || (emp.employee_type || "Unknown") === typeFilter; const empBranch = branchDisplayName(emp); const empDept = normalize(emp.department_name); const empPos = normalize(emp.position_name); const matchesBranch = ignoreBranch ? true : branchFilter === "all" || empBranch === branchFilter; const matchesDept = ignoreDept ? true : departmentFilter === "all" || empDept === departmentFilter; const matchesPos = ignorePos ? true : positionFilter === "all" || empPos === positionFilter; return ( matchesSearch && matchesStatus && matchesType && matchesBranch && matchesDept && matchesPos ); }; const branchesWithCount = useMemo(() => { const map = new Map(); assignmentOptions.branches.forEach((branch) => { const name = branch.branch_name || branch.name; if (name && !map.has(name)) map.set(name, 0); }); employees.forEach((emp) => { const b = branchDisplayName(emp); const baseMatch = matchesBaseFilters(emp, { ignoreBranch: true, ignoreDept: true, ignorePos: true, }); if (!map.has(b)) map.set(b, 0); if (baseMatch) map.set(b, map.get(b) + 1); }); return Array.from(map.entries()) .map(([name, count]) => ({ name, count })) .sort((a, b) => a.name.localeCompare(b.name)); }, [ employees, assignmentOptions.branches, searchQuery, statusFilter, typeFilter, branchFilter, departmentFilter, positionFilter, ]); const departmentsWithCount = useMemo(() => { const map = new Map(); employees.forEach((emp) => { const b = branchDisplayName(emp); const d = normalize(emp.department_name); const baseMatch = matchesBaseFilters(emp, { ignoreBranch: false, ignoreDept: true, ignorePos: true, }); if ((branchFilter === "all" || b === branchFilter) && baseMatch) { if (!map.has(d)) map.set(d, 0); map.set(d, map.get(d) + 1); } }); return Array.from(map.entries()) .map(([name, count]) => ({ name, count })) .sort((a, b) => a.name.localeCompare(b.name)); }, [ employees, branchFilter, searchQuery, statusFilter, typeFilter, departmentFilter, positionFilter, ]); const positionsWithCount = useMemo(() => { const map = new Map(); employees.forEach((emp) => { const b = branchDisplayName(emp); const d = normalize(emp.department_name); const p = normalize(emp.position_name); const baseMatch = matchesBaseFilters(emp, { ignoreBranch: false, ignoreDept: false, ignorePos: true, }); if ( (branchFilter === "all" || b === branchFilter) && (departmentFilter === "all" || d === departmentFilter) && baseMatch ) { if (!map.has(p)) map.set(p, 0); map.set(p, map.get(p) + 1); } }); return Array.from(map.entries()) .map(([name, count]) => ({ name, count })) .sort((a, b) => a.name.localeCompare(b.name)); }, [ employees, branchFilter, departmentFilter, searchQuery, statusFilter, typeFilter, positionFilter, ]); const typesWithCount = useMemo(() => { const map = new Map(); employees.forEach((emp) => { const b = branchDisplayName(emp); const d = normalize(emp.department_name); const p = normalize(emp.position_name); const t = emp.employee_type || "Unknown"; const baseMatch = matchesBaseFilters(emp, { ignoreType: true, ignoreBranch: false, ignoreDept: false, ignorePos: false, ignoreStatus: false, }); if ( (branchFilter === "all" || b === branchFilter) && (departmentFilter === "all" || d === departmentFilter) && (positionFilter === "all" || p === positionFilter) && baseMatch ) { if (!map.has(t)) map.set(t, 0); map.set(t, map.get(t) + 1); } }); return Array.from(map.entries()) .map(([name, count]) => ({ name, count })) .sort((a, b) => a.name.localeCompare(b.name)); }, [ employees, branchFilter, departmentFilter, positionFilter, searchQuery, statusFilter, typeFilter, ]); const statusWithCount = useMemo(() => { const map = { active: 0, inactive: 0 }; employees.forEach((emp) => { const b = branchDisplayName(emp); const d = normalize(emp.department_name); const p = normalize(emp.position_name); const baseMatch = matchesBaseFilters(emp, { ignoreStatus: true, ignoreBranch: false, ignoreDept: false, ignorePos: false, ignoreType: false, }); if ( (branchFilter === "all" || b === branchFilter) && (departmentFilter === "all" || d === departmentFilter) && (positionFilter === "all" || p === positionFilter) && baseMatch ) { const s = emp.status === "active" ? "active" : "inactive"; map[s] = (map[s] || 0) + 1; } }); return map; }, [ employees, branchFilter, departmentFilter, positionFilter, searchQuery, typeFilter, statusFilter, ]); const filteredEmployees = employees .filter((employee) => { const safeQuery = searchQuery.replace(/\s+/g, " ").toLowerCase().trim(); const queryWords = safeQuery ? safeQuery.split(" ") : []; const fullName = [employee.first_name, employee.middle_name, employee.last_name] .filter(Boolean) .join(" ") .toLowerCase(); const haystack = [ fullName, employee.employee_id, employee.person_id, employee.biometrics_id ] .filter(Boolean) .join(" ") .toLowerCase() .replace(/\s+/g, " "); const matchesSearch = queryWords.length === 0 || queryWords.every(word => haystack.includes(word)); const matchesStatus = statusFilter === "all" || employee.status === statusFilter; const matchesType = typeFilter === "all" || employee.employee_type === typeFilter; const empBranch = branchDisplayName(employee); const empDept = normalize(employee.department_name); const empPos = normalize(employee.position_name); const matchesBranch = branchFilter === "all" || empBranch === branchFilter; const matchesDept = departmentFilter === "all" || empDept === departmentFilter; const matchesPos = positionFilter === "all" || empPos === positionFilter; return ( matchesSearch && matchesStatus && matchesType && matchesBranch && matchesDept && matchesPos ); }) .sort((a, b) => { if (a.status === "active" && b.status !== "active") return -1; if (a.status !== "active" && b.status === "active") return 1; return 0; }); const gridItemsPerPage = 18; const gridTotalPages = Math.ceil(filteredEmployees.length / gridItemsPerPage); const paginatedGridEmployees = activeView === "grid" ? filteredEmployees.slice( (gridCurrentPage - 1) * gridItemsPerPage, gridCurrentPage * gridItemsPerPage, ) : filteredEmployees; const gridPageNumbers = useMemo(() => { const pages = []; for (let i = 1; i <= gridTotalPages; i++) { if ( i === 1 || i === gridTotalPages || Math.abs(i - gridCurrentPage) <= 1 ) { pages.push(i); } else if (pages[pages.length - 1] !== "...") { pages.push("..."); } } return pages; }, [gridTotalPages, gridCurrentPage]); const handlePrintSelected = () => { const selectedData = employees.filter((emp) => selectedEmployees.includes(emp.employee_id), ); const printWindow = window.open("", "_blank", "width=1000,height=800"); const tableHtml = `
Selected Personnel Records
| ID | Name | Branch | Department | Position | Contact | Date of Birth | |
|---|---|---|---|---|---|---|---|
| ${emp.employee_id} |
${emp.last_name}, ${emp.first_name} ${emp.middle_name ? emp.middle_name.charAt(0) + "." : ""}
|
${branchDisplayName(emp)} | ${emp.department_name || "—"} | ${emp.position_name || "—"} | ${emp.email || "—"} | ${emp.contact_number || "—"} | ${emp.date_of_birth ? new Date(emp.date_of_birth).toLocaleDateString("en-US", { year: "numeric", month: "short", day: "numeric" }) : "—"} |
Showing{" "} {(gridCurrentPage - 1) * gridItemsPerPage + 1} {" "} to{" "} {Math.min( gridCurrentPage * gridItemsPerPage, filteredEmployees.length, )} {" "} of{" "} {filteredEmployees.length} {" "} employees
No employees found{searchQuery ? ` for "${searchQuery}"` : ""}.