Adding Switch button in attendence component. #129
@ -1,4 +1,4 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState, useMemo, useCallback } from "react";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import Avatar from "../common/Avatar";
|
import Avatar from "../common/Avatar";
|
||||||
import { convertShortTime } from "../../utils/dateUtils";
|
import { convertShortTime } from "../../utils/dateUtils";
|
||||||
@ -7,13 +7,28 @@ import { useSelector, useDispatch } from "react-redux";
|
|||||||
import { fetchAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice";
|
import { fetchAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice";
|
||||||
import DateRangePicker from "../common/DateRangePicker";
|
import DateRangePicker from "../common/DateRangePicker";
|
||||||
import { getCachedData } from "../../slices/apiDataManager";
|
import { getCachedData } from "../../slices/apiDataManager";
|
||||||
import usePagination from "../../hooks/usePagination";
|
|
||||||
|
|
||||||
const AttendanceLog = ({ handleModalData, projectId }) => {
|
const usePagination = (data, itemsPerPage) => {
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const maxPage = Math.ceil(data.length / itemsPerPage);
|
||||||
|
|
||||||
|
const currentItems = useMemo(() => {
|
||||||
|
const startIndex = (currentPage - 1) * itemsPerPage;
|
||||||
|
const endIndex = startIndex + itemsPerPage;
|
||||||
|
return data.slice(startIndex, endIndex);
|
||||||
|
}, [data, currentPage, itemsPerPage]);
|
||||||
|
|
||||||
|
const paginate = useCallback((pageNumber) => setCurrentPage(pageNumber), []);
|
||||||
|
const resetPage = useCallback(() => setCurrentPage(1), []);
|
||||||
|
|
||||||
|
return { currentPage, totalPages: maxPage, currentItems, paginate, resetPage };
|
||||||
|
};
|
||||||
|
|
||||||
|
const AttendanceLog = ({ handleModalData, projectId, showOnlyCheckout }) => {
|
||||||
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
|
const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" });
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const { data, loading, error } = useSelector((store) => store.attendanceLogs);
|
const { data, loading, error } = useSelector((store) => store.attendanceLogs);
|
||||||
const [isRefreshing, setIsRefreshing] = useState(true);
|
const [isRefreshing, setIsRefreshing] = useState(false);
|
||||||
const [processedData, setProcessedData] = useState([]);
|
const [processedData, setProcessedData] = useState([]);
|
||||||
|
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
@ -44,7 +59,6 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { startDate, endDate } = dateRange;
|
const { startDate, endDate } = dateRange;
|
||||||
if (startDate && endDate) {
|
|
||||||
dispatch(
|
dispatch(
|
||||||
fetchAttendanceData({
|
fetchAttendanceData({
|
||||||
projectId,
|
projectId,
|
||||||
@ -52,25 +66,29 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
|||||||
toDate: endDate,
|
toDate: endDate,
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
setIsRefreshing(false);
|
||||||
}, [dateRange, projectId, isRefreshing]);
|
}, [dateRange, projectId, dispatch, isRefreshing]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const group1 = data
|
const filteredData = showOnlyCheckout
|
||||||
|
? data.filter((item) => item.checkOutTime === null)
|
||||||
|
: data;
|
||||||
|
|
||||||
|
const group1 = filteredData
|
||||||
.filter((d) => d.activity === 1 && isSameDay(d.checkInTime))
|
.filter((d) => d.activity === 1 && isSameDay(d.checkInTime))
|
||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
const group2 = data
|
const group2 = filteredData
|
||||||
.filter((d) => d.activity === 4 && isSameDay(d.checkOutTime))
|
.filter((d) => d.activity === 4 && isSameDay(d.checkOutTime))
|
||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
const group3 = data
|
const group3 = filteredData
|
||||||
.filter((d) => d.activity === 1 && isBeforeToday(d.checkInTime))
|
.filter((d) => d.activity === 1 && isBeforeToday(d.checkInTime))
|
||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
const group4 = data
|
const group4 = filteredData
|
||||||
.filter((d) => d.activity === 4 && isBeforeToday(d.checkOutTime));
|
.filter((d) => d.activity === 4 && isBeforeToday(d.checkOutTime));
|
||||||
const group5 = data
|
const group5 = filteredData
|
||||||
.filter((d) => d.activity === 2 && isBeforeToday(d.checkOutTime))
|
.filter((d) => d.activity === 2 && isBeforeToday(d.checkOutTime))
|
||||||
.sort(sortByName);
|
.sort(sortByName);
|
||||||
const group6 = data.filter((d) => d.activity === 5).sort(sortByName);
|
const group6 = filteredData.filter((d) => d.activity === 5).sort(sortByName);
|
||||||
|
|
||||||
const sortedList = [...group1, ...group2, ...group3, ...group4, ...group5, ...group6];
|
const sortedList = [...group1, ...group2, ...group3, ...group4, ...group5, ...group6];
|
||||||
|
|
||||||
@ -90,13 +108,18 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
|||||||
// Create the final sorted array
|
// Create the final sorted array
|
||||||
const finalData = sortedDates.flatMap((date) => groupedByDate[date]);
|
const finalData = sortedDates.flatMap((date) => groupedByDate[date]);
|
||||||
setProcessedData(finalData);
|
setProcessedData(finalData);
|
||||||
}, [data]);
|
}, [data, showOnlyCheckout]);
|
||||||
|
|
||||||
const { currentPage, totalPages, currentItems: paginatedAttendances, paginate } = usePagination(
|
const { currentPage, totalPages, currentItems: paginatedAttendances, paginate, resetPage } = usePagination(
|
||||||
processedData,
|
processedData,
|
||||||
10
|
10
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Reset to the first page whenever processedData changes (due to switch on/off)
|
||||||
|
useEffect(() => {
|
||||||
|
resetPage();
|
||||||
|
}, [processedData, resetPage]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
@ -108,10 +131,10 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
|||||||
</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 ? "spin" : ""
|
className={`bx bx-refresh cursor-pointer fs-4 ${loading || isRefreshing ? "spin" : ""
|
||||||
}`}
|
}`}
|
||||||
title="Refresh"
|
title="Refresh"
|
||||||
onClick={() => setIsRefreshing(!isRefreshing)}
|
onClick={() => setIsRefreshing(true)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -134,8 +157,12 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{loading && <td colSpan={5}>Loading...</td>}
|
{(loading || isRefreshing) && (
|
||||||
{paginatedAttendances.reduce((acc, attendance, index, arr) => {
|
<tr>
|
||||||
|
<td colSpan={6}>Loading...</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
|
{!loading && !isRefreshing && paginatedAttendances.reduce((acc, attendance, index, arr) => {
|
||||||
const currentDate = moment(attendance.checkInTime || attendance.checkOutTime).format("YYYY-MM-DD");
|
const currentDate = moment(attendance.checkInTime || attendance.checkOutTime).format("YYYY-MM-DD");
|
||||||
const previousAttendance = arr[index - 1];
|
const previousAttendance = arr[index - 1];
|
||||||
const previousDate = previousAttendance ? moment(previousAttendance.checkInTime || previousAttendance.checkOutTime).format("YYYY-MM-DD") : null;
|
const previousDate = previousAttendance ? moment(previousAttendance.checkInTime || previousAttendance.checkOutTime).format("YYYY-MM-DD") : null;
|
||||||
@ -191,10 +218,14 @@ const AttendanceLog = ({ handleModalData, projectId }) => {
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
)}
|
)}
|
||||||
{!loading && data.length === 0 && <span>No employee logs</span>}
|
{!loading && !isRefreshing && data.length === 0 && <span>No employee logs</span>}
|
||||||
{error && <td colSpan={6}>{error}</td>}
|
{error && !loading && !isRefreshing && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan={6}>{error}</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!loading && processedData.length > 10 && (
|
{!loading && !isRefreshing && processedData.length > 10 && (
|
||||||
<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" : ""}`}>
|
||||||
|
@ -21,7 +21,7 @@ import { REGULARIZE_ATTENDANCE } from "../../utils/constants";
|
|||||||
|
|
||||||
const AttendancePage = () => {
|
const AttendancePage = () => {
|
||||||
const [activeTab, setActiveTab] = useState("all");
|
const [activeTab, setActiveTab] = useState("all");
|
||||||
|
const [showOnlyCheckout, setShowOnlyCheckout] = useState(false);
|
||||||
const loginUser = getCachedProfileData();
|
const loginUser = getCachedProfileData();
|
||||||
var selectedProject = useSelector((store) => store.localVariables.projectId);
|
var selectedProject = useSelector((store) => store.localVariables.projectId);
|
||||||
const { projects, loading: projectLoading } = useProjects();
|
const { projects, loading: projectLoading } = useProjects();
|
||||||
@ -86,6 +86,10 @@ const AttendancePage = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleToggle = (event) => {
|
||||||
|
setShowOnlyCheckout(event.target.checked);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (modelConfig !== null) {
|
if (modelConfig !== null) {
|
||||||
openModel();
|
openModel();
|
||||||
@ -100,6 +104,17 @@ const AttendancePage = () => {
|
|||||||
dispatch(setProjectId(loginUser?.projects[0]));
|
dispatch(setProjectId(loginUser?.projects[0]));
|
||||||
}
|
}
|
||||||
}, [selectedProject, loginUser?.projects]);
|
}, [selectedProject, loginUser?.projects]);
|
||||||
|
|
||||||
|
// Filter attendance data based on the toggle
|
||||||
|
// const filteredAttendance = showOnlyCheckout
|
||||||
|
// ? attendances?.filter(
|
||||||
|
// (att) => att?.checkOutTime !== null && att?.checkInTime !== null
|
||||||
|
// )
|
||||||
|
// : attendances;
|
||||||
|
const filteredAttendance = showOnlyCheckout
|
||||||
|
? attendances?.filter((att) => att?.checkOutTime === null)
|
||||||
|
: attendances;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isCreateModalOpen && modelConfig && (
|
{isCreateModalOpen && modelConfig && (
|
||||||
@ -198,6 +213,26 @@ const AttendancePage = () => {
|
|||||||
Regularization
|
Regularization
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li
|
||||||
|
className={`nav-item ms-auto ${
|
||||||
|
activeTab === "regularization" ? "d-none" : ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<label className="switch switch-primary">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="switch-input"
|
||||||
|
checked={showOnlyCheckout}
|
||||||
|
onChange={handleToggle}
|
||||||
|
/>
|
||||||
|
<span className="switch-toggle-slider">
|
||||||
|
<span className="switch-on"></span>
|
||||||
|
<span className="switch-off"></span>
|
||||||
|
</span>
|
||||||
|
<span className="switch-label m-2">Pending Actions</span>
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div className="tab-content attedanceTabs py-2">
|
<div className="tab-content attedanceTabs py-2">
|
||||||
{projectLoading && <span>Loading..</span>}
|
{projectLoading && <span>Loading..</span>}
|
||||||
@ -205,12 +240,12 @@ const AttendancePage = () => {
|
|||||||
|
|
||||||
{activeTab === "all" && (
|
{activeTab === "all" && (
|
||||||
<>
|
<>
|
||||||
{!projectLoading && attendances.length === 0 && (
|
{!projectLoading && filteredAttendance?.length === 0 && (
|
||||||
<p>No Employee assigned yet.</p>
|
<p>No Employee assigned yet.</p>
|
||||||
)}
|
)}
|
||||||
<div className="tab-pane fade show active py-0">
|
<div className="tab-pane fade show active py-0">
|
||||||
<Attendance
|
<Attendance
|
||||||
attendance={attendances}
|
attendance={filteredAttendance}
|
||||||
handleModalData={handleModalData}
|
handleModalData={handleModalData}
|
||||||
getRole={getRole}
|
getRole={getRole}
|
||||||
/>
|
/>
|
||||||
@ -218,12 +253,12 @@ const AttendancePage = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
||||||
{activeTab === "logs" && (
|
{activeTab === "logs" && (
|
||||||
<div className="tab-pane fade show active py-0">
|
<div className="tab-pane fade show active py-0">
|
||||||
<AttendanceLog
|
<AttendanceLog
|
||||||
handleModalData={handleModalData}
|
handleModalData={handleModalData}
|
||||||
projectId={selectedProject}
|
projectId={selectedProject}
|
||||||
|
showOnlyCheckout={showOnlyCheckout}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user