Refactor_Expenses #321
@ -4,7 +4,7 @@ import Avatar from "../common/Avatar";
|
|||||||
import { convertShortTime } from "../../utils/dateUtils";
|
import { convertShortTime } from "../../utils/dateUtils";
|
||||||
import RenderAttendanceStatus from "./RenderAttendanceStatus";
|
import RenderAttendanceStatus from "./RenderAttendanceStatus";
|
||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import { fetchAttendanceData, setAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice";
|
import { fetchAttendanceData, setAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice"; // Corrected typo: atttendanceLogsSlice to attedanceLogsSlice
|
||||||
import DateRangePicker from "../common/DateRangePicker";
|
import DateRangePicker from "../common/DateRangePicker";
|
||||||
import eventBus from "../../services/eventBus";
|
import eventBus from "../../services/eventBus";
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ const AttendanceLog = ({
|
|||||||
handleModalData,
|
handleModalData,
|
||||||
projectId,
|
projectId,
|
||||||
setshowOnlyCheckout,
|
setshowOnlyCheckout,
|
||||||
showOnlyCheckout,
|
showOnlyCheckout, // Prop for showPending state
|
||||||
searchQuery, // Prop for search query
|
searchQuery, // Prop for search query
|
||||||
}) => {
|
}) => {
|
||||||
const selectedProject = useSelector(
|
const selectedProject = useSelector(
|
||||||
@ -52,10 +52,13 @@ const AttendanceLog = ({
|
|||||||
);
|
);
|
||||||
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
|
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const [loading, setLoading] = useState(false);
|
|
||||||
const [showPending,setShowPending] = useState(false)
|
|
||||||
|
|
||||||
const [isRefreshing, setIsRefreshing] = useState(false);
|
// Get data, loading, and fetching state from the Redux store's attendanceLogs slice
|
||||||
|
const { data: attendanceLogsData, loading: logsLoading, isFetching: logsFetching } = useSelector(
|
||||||
|
(state) => state.attendanceLogs // Assuming your slice is named 'attendanceLogs'
|
||||||
|
);
|
||||||
|
|
||||||
|
const [isRefreshing, setIsRefreshing] = useState(false); // Local state for refresh spinner
|
||||||
|
|
||||||
const today = useMemo(() => {
|
const today = useMemo(() => {
|
||||||
const d = new Date();
|
const d = new Date();
|
||||||
@ -89,6 +92,7 @@ const AttendanceLog = ({
|
|||||||
return nameA.localeCompare(nameB);
|
return nameA.localeCompare(nameB);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Effect to fetch attendance data when dateRange or projectId changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { startDate, endDate } = dateRange;
|
const { startDate, endDate } = dateRange;
|
||||||
dispatch(
|
dispatch(
|
||||||
@ -98,13 +102,13 @@ const AttendanceLog = ({
|
|||||||
toDate: endDate,
|
toDate: endDate,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
setIsRefreshing(false);
|
setIsRefreshing(false); // Reset refreshing state after fetch attempt
|
||||||
}, [dateRange, projectId, dispatch, isRefreshing]);
|
}, [dateRange, projectId, dispatch, isRefreshing]); // isRefreshing is a dependency because it triggers a re-fetch
|
||||||
|
|
||||||
const processedData = useMemo(() => {
|
const processedData = useMemo(() => {
|
||||||
let filteredData = showOnlyCheckout
|
let filteredData = showOnlyCheckout // Use the prop directly
|
||||||
? data.filter((item) => item.checkOutTime === null)
|
? attendanceLogsData.filter((item) => item.checkOutTime === null) // Use attendanceLogsData
|
||||||
: data;
|
: attendanceLogsData; // Use attendanceLogsData
|
||||||
|
|
||||||
// Apply search query filter
|
// Apply search query filter
|
||||||
if (searchQuery) {
|
if (searchQuery) {
|
||||||
@ -168,7 +172,7 @@ const AttendanceLog = ({
|
|||||||
|
|
||||||
// Create the final sorted array
|
// Create the final sorted array
|
||||||
return sortedDates.flatMap((date) => groupedByDate[date]);
|
return sortedDates.flatMap((date) => groupedByDate[date]);
|
||||||
}, [data, showOnlyCheckout, searchQuery, isSameDay, isBeforeToday, sortByName]);
|
}, [attendanceLogsData, showOnlyCheckout, searchQuery, isSameDay, isBeforeToday, sortByName]); // Added attendanceLogsData to dependencies
|
||||||
|
|
||||||
const {
|
const {
|
||||||
currentPage,
|
currentPage,
|
||||||
@ -178,10 +182,10 @@ const AttendanceLog = ({
|
|||||||
resetPage, // Destructure resetPage here
|
resetPage, // Destructure resetPage here
|
||||||
} = usePagination(processedData, 20);
|
} = usePagination(processedData, 20);
|
||||||
|
|
||||||
// Effect to reset pagination when search query changes
|
// Effect to reset pagination when search query or showOnlyCheckout changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
resetPage();
|
resetPage();
|
||||||
}, [searchQuery, resetPage]); // Add resetPage to dependencies
|
}, [searchQuery, showOnlyCheckout, resetPage]); // Add resetPage to dependencies
|
||||||
|
|
||||||
const handler = useCallback(
|
const handler = useCallback(
|
||||||
(msg) => {
|
(msg) => {
|
||||||
@ -192,7 +196,8 @@ const AttendanceLog = ({
|
|||||||
startDate <= checkIn &&
|
startDate <= checkIn &&
|
||||||
checkIn <= endDate
|
checkIn <= endDate
|
||||||
) {
|
) {
|
||||||
const updatedAttendance = data.map((item) =>
|
// Create a new array to avoid direct mutation of Redux state data
|
||||||
|
const updatedAttendance = attendanceLogsData.map((item) => // Use attendanceLogsData
|
||||||
item.id === msg.response.id
|
item.id === msg.response.id
|
||||||
? { ...item, ...msg.response }
|
? { ...item, ...msg.response }
|
||||||
: item
|
: item
|
||||||
@ -200,16 +205,14 @@ const AttendanceLog = ({
|
|||||||
dispatch(setAttendanceData(updatedAttendance)); // Update Redux store
|
dispatch(setAttendanceData(updatedAttendance)); // Update Redux store
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[projectId, dateRange, data, dispatch]
|
[projectId, dateRange, attendanceLogsData, dispatch] // Added attendanceLogsData to dependencies
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
eventBus.on("attendance_log", handler);
|
eventBus.on("attendance_log", handler);
|
||||||
return () => eventBus.off("attendance_log", handler);
|
return () => eventBus.off("attendance_log", handler);
|
||||||
}, [handler]);
|
}, [handler]);
|
||||||
|
|
||||||
const employeeHandler = useCallback(
|
|
||||||
const employeeHandler = useCallback(
|
const employeeHandler = useCallback(
|
||||||
(msg) => {
|
(msg) => {
|
||||||
const { startDate, endDate } = dateRange;
|
const { startDate, endDate } = dateRange;
|
||||||
@ -224,12 +227,17 @@ const AttendanceLog = ({
|
|||||||
[projectId, dateRange, dispatch]
|
[projectId, dateRange, dispatch]
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
// Removed duplicate useEffect, keeping only one
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
eventBus.on("employee", employeeHandler);
|
eventBus.on("employee", employeeHandler);
|
||||||
return () => eventBus.off("employee", employeeHandler);
|
return () => eventBus.off("employee", employeeHandler);
|
||||||
}, [employeeHandler]);
|
}, [employeeHandler]);
|
||||||
|
|
||||||
|
const handleRefreshClick = () => {
|
||||||
|
setIsRefreshing(true); // Set refreshing state to true
|
||||||
|
// The useEffect for fetching data will trigger because isRefreshing is a dependency
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
@ -246,20 +254,20 @@ const AttendanceLog = ({
|
|||||||
type="checkbox"
|
type="checkbox"
|
||||||
className="form-check-input"
|
className="form-check-input"
|
||||||
role="switch"
|
role="switch"
|
||||||
disabled={isFetching}
|
disabled={logsFetching} // Use logsFetching from Redux store
|
||||||
id="inactiveEmployeesCheckbox"
|
id="inactiveEmployeesCheckbox"
|
||||||
checked={showPending}
|
checked={showOnlyCheckout} // Use the prop directly
|
||||||
onChange={(e) => setShowPending(e.target.checked)}
|
onChange={(e) => setshowOnlyCheckout(e.target.checked)} // Use the prop setter
|
||||||
/>
|
/>
|
||||||
<label className="form-check-label ms-0">Show Pending</label>
|
<label className="form-check-label ms-0">Show Pending</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-md-2 m-0 text-end">
|
<div className="col-md-2 m-0 text-end">
|
||||||
<i
|
<i
|
||||||
className={`bx bx-refresh cursor-pointer fs-4 ${loading || isRefreshing ? "spin" : ""
|
className={`bx bx-refresh cursor-pointer fs-4 ${logsLoading || isRefreshing ? "spin" : "" // Use logsLoading for overall loading, isRefreshing for local spinner
|
||||||
}`}
|
}`}
|
||||||
title="Refresh"
|
title="Refresh"
|
||||||
onClick={() => refetch()}
|
onClick={handleRefreshClick} // Call the new handler
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -286,13 +294,13 @@ const AttendanceLog = ({
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{(loading || isRefreshing) && (
|
{(logsLoading || isRefreshing) && ( // Use logsLoading and isRefreshing
|
||||||
<tr>
|
<tr>
|
||||||
<td colSpan={6}>Loading...</td>
|
<td colSpan={6}>Loading...</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
)}
|
||||||
{!loading &&
|
{!logsLoading && // Use logsLoading
|
||||||
!isRefreshing &&
|
!isRefreshing && // Use isRefreshing
|
||||||
paginatedAttendances.reduce((acc, attendance, index, arr) => {
|
paginatedAttendances.reduce((acc, attendance, index, arr) => {
|
||||||
const currentDate = moment(
|
const currentDate = moment(
|
||||||
attendance.checkInTime || attendance.checkOutTime
|
attendance.checkInTime || attendance.checkOutTime
|
||||||
@ -362,8 +370,8 @@ const AttendanceLog = ({
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
) : (
|
) : (
|
||||||
!loading &&
|
!logsLoading && // Use logsLoading
|
||||||
!isRefreshing && (
|
!isRefreshing && ( // Use isRefreshing
|
||||||
<div
|
<div
|
||||||
className="d-flex justify-content-center align-items-center text-muted"
|
className="d-flex justify-content-center align-items-center text-muted"
|
||||||
style={{
|
style={{
|
||||||
@ -375,7 +383,7 @@ const AttendanceLog = ({
|
|||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!loading && !isRefreshing && processedData.length > 20 && (
|
{!logsLoading && !isRefreshing && processedData.length > 20 && ( // Use logsLoading and isRefreshing
|
||||||
<nav aria-label="Page ">
|
<nav aria-label="Page ">
|
||||||
<ul className="pagination pagination-sm justify-content-end py-1">
|
<ul className="pagination pagination-sm justify-content-end py-1">
|
||||||
<li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
|
<li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user