186 lines
6.5 KiB
JavaScript
186 lines
6.5 KiB
JavaScript
import React, { useCallback, useEffect, useState } from "react";
|
||
import Avatar from "../common/Avatar";
|
||
import { convertShortTime } from "../../utils/dateUtils";
|
||
import RegularizationActions from "./RegularizationActions";
|
||
import { useSelector } from "react-redux";
|
||
import { useRegularizationRequests } from "../../hooks/useAttendance";
|
||
import moment from "moment";
|
||
import usePagination from "../../hooks/usePagination";
|
||
import eventBus from "../../services/eventBus";
|
||
import { cacheData } from "../../slices/apiDataManager";
|
||
|
||
const Regularization = ({ handleRequest, searchQuery }) => {
|
||
const selectedProject = useSelector((store) => store.localVariables.projectId);
|
||
const [regularizesList, setRegularizedList] = useState([]);
|
||
const { regularizes, loading, refetch } = useRegularizationRequests(selectedProject);
|
||
|
||
// Update regularizesList when regularizes data changes
|
||
useEffect(() => {
|
||
setRegularizedList(regularizes);
|
||
}, [regularizes]);
|
||
|
||
const sortByName = useCallback((a, b) => {
|
||
const nameA = (a.firstName + a.lastName).toLowerCase();
|
||
const nameB = (b.firstName + b.lastName).toLowerCase();
|
||
return nameA.localeCompare(nameB);
|
||
}, []);
|
||
|
||
const handler = useCallback(
|
||
(msg) => {
|
||
if (selectedProject === msg.projectId) { // Use strict equality for comparison
|
||
// Filter out the updated item to effectively remove it from the list
|
||
// as it's likely been processed (approved/rejected)
|
||
const updatedAttendance = regularizesList?.filter(item => item.id !== msg.response.id);
|
||
cacheData("regularizedList", {
|
||
data: updatedAttendance,
|
||
projectId: selectedProject,
|
||
});
|
||
// Refetch to get the latest data from the source, ensuring consistency
|
||
refetch();
|
||
}
|
||
},
|
||
[selectedProject, regularizesList, refetch] // Added regularizesList and refetch to dependencies
|
||
);
|
||
|
||
const employeeHandler = useCallback(
|
||
(msg) => {
|
||
// If any regularization request belongs to the updated employee, refetch
|
||
if (regularizes?.some((item) => item.employeeId === msg.employeeId)) { // Use strict equality
|
||
refetch();
|
||
}
|
||
},
|
||
[regularizes, refetch] // Added refetch to dependencies
|
||
);
|
||
|
||
// Event bus listeners
|
||
useEffect(() => {
|
||
eventBus.on("regularization", handler);
|
||
return () => eventBus.off("regularization", handler);
|
||
}, [handler]);
|
||
|
||
useEffect(() => {
|
||
eventBus.on("employee", employeeHandler);
|
||
return () => eventBus.off("employee", employeeHandler);
|
||
}, [employeeHandler]);
|
||
|
||
// Search filter logic
|
||
const filteredData = [...regularizesList]
|
||
?.filter((item) => {
|
||
if (!searchQuery) return true;
|
||
const lowerSearch = searchQuery.toLowerCase();
|
||
const fullName = `${item.firstName || ""} ${item.lastName || ""}`.toLowerCase();
|
||
|
||
return (
|
||
item.firstName?.toLowerCase().includes(lowerSearch) ||
|
||
item.lastName?.toLowerCase().includes(lowerSearch) ||
|
||
fullName.includes(lowerSearch) ||
|
||
item.employeeId?.toLowerCase().includes(lowerSearch)
|
||
);
|
||
})
|
||
.sort(sortByName);
|
||
|
||
const { currentPage, totalPages, currentItems, paginate } = usePagination(filteredData, 20);
|
||
|
||
return (
|
||
<div className="table-responsive text-nowrap pb-4">
|
||
<table className="table mb-0">
|
||
<thead>
|
||
<tr>
|
||
<th colSpan={2}>Name</th>
|
||
<th>Date</th>
|
||
<th>
|
||
<i className="bx bxs-down-arrow-alt text-success"></i>Check-In
|
||
</th>
|
||
<th>
|
||
<i className="bx bxs-up-arrow-alt text-danger"></i>Check-Out
|
||
</th>
|
||
<th>Action</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
{!loading && currentItems?.length > 0 ? (
|
||
currentItems.map((att, index) => (
|
||
<tr key={index}>
|
||
<td colSpan={2}>
|
||
<div className="d-flex justify-content-start align-items-center">
|
||
<Avatar firstName={att.firstName} lastName={att.lastName} />
|
||
<div className="d-flex flex-column">
|
||
<a href="#" className="text-heading text-truncate">
|
||
<span className="fw-normal">
|
||
{att.firstName} {att.lastName}
|
||
</span>
|
||
</a>
|
||
</div>
|
||
</div>
|
||
</td>
|
||
<td>{moment(att.checkOutTime).format("DD-MMM-YYYY")}</td>
|
||
<td>{convertShortTime(att.checkInTime)}</td>
|
||
<td>
|
||
{att.checkOutTime ? convertShortTime(att.checkOutTime) : "--"}
|
||
</td>
|
||
<td className="text-center">
|
||
<RegularizationActions
|
||
attendanceData={att}
|
||
handleRequest={handleRequest}
|
||
refresh={refetch}
|
||
/>
|
||
</td>
|
||
</tr>
|
||
))
|
||
) : (
|
||
<tr>
|
||
<td
|
||
colSpan={6}
|
||
className="text-center"
|
||
style={{
|
||
height: "200px",
|
||
verticalAlign: "middle",
|
||
borderBottom: "none",
|
||
}}
|
||
>
|
||
{loading ? "Loading..." : "No Record Found"}
|
||
</td>
|
||
</tr>
|
||
)}
|
||
</tbody>
|
||
</table>
|
||
|
||
{!loading && totalPages > 1 && (
|
||
<nav aria-label="Page ">
|
||
<ul className="pagination pagination-sm justify-content-end py-1 mt-3">
|
||
<li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
|
||
<button
|
||
className="page-link btn-xs"
|
||
onClick={() => paginate(currentPage - 1)}
|
||
>
|
||
«
|
||
</button>
|
||
</li>
|
||
{[...Array(totalPages)].map((_, index) => (
|
||
<li
|
||
key={index}
|
||
className={`page-item ${currentPage === index + 1 ? "active" : ""}`}
|
||
>
|
||
<button className="page-link" onClick={() => paginate(index + 1)}>
|
||
{index + 1}
|
||
</button>
|
||
</li>
|
||
))}
|
||
<li
|
||
className={`page-item ${currentPage === totalPages ? "disabled" : ""}`}
|
||
>
|
||
<button
|
||
className="page-link"
|
||
onClick={() => paginate(currentPage + 1)}
|
||
>
|
||
»
|
||
</button>
|
||
</li>
|
||
</ul>
|
||
</nav>
|
||
)}
|
||
</div>
|
||
);
|
||
};
|
||
|
||
export default Regularization; |