diff --git a/src/components/Activities/AttendcesLogs.jsx b/src/components/Activities/AttendcesLogs.jsx index 0a28ffd3..1b137c42 100644 --- a/src/components/Activities/AttendcesLogs.jsx +++ b/src/components/Activities/AttendcesLogs.jsx @@ -6,35 +6,45 @@ import RenderAttendanceStatus from "./RenderAttendanceStatus"; import { useSelector, useDispatch } from "react-redux"; import { fetchAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice"; import DateRangePicker from "../common/DateRangePicker"; -import { clearCacheKey, getCachedData } from "../../slices/apiDataManager"; import eventBus from "../../services/eventBus"; -import AttendanceRepository from "../../repositories/AttendanceRepository"; -import { useAttendancesLogs } from "../../hooks/useAttendance"; -import { queryClient } from "../../layouts/AuthLayout"; const usePagination = (data, itemsPerPage) => { const [currentPage, setCurrentPage] = useState(1); - const maxPage = Math.ceil(data.length / itemsPerPage); + const totalItems = Array.isArray(data) ? data.length : 0; + const maxPage = Math.ceil(totalItems / itemsPerPage); + const currentItems = useMemo(() => { + if (!Array.isArray(data) || data.length === 0) { + return []; + } 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), []); + const paginate = useCallback((pageNumber) => { + if (pageNumber > 0 && pageNumber <= maxPage) { + setCurrentPage(pageNumber); + } + }, [maxPage]); + + const resetPage = useCallback(() => setCurrentPage(1), []); // This is returned by the hook return { currentPage, totalPages: maxPage, currentItems, paginate, - resetPage, + resetPage, // Ensure resetPage is returned here }; }; const AttendanceLog = ({ handleModalData, + projectId, + setshowOnlyCheckout, + showOnlyCheckout, + searchQuery, // Prop for search query }) => { const selectedProject = useSelector( (store) => store.localVariables.projectId @@ -45,50 +55,74 @@ const AttendanceLog = ({ const [showPending,setShowPending] = useState(false) const [isRefreshing, setIsRefreshing] = useState(false); - const [processedData, setProcessedData] = useState([]); - const today = new Date(); - today.setHours(0, 0, 0, 0); + const today = useMemo(() => { + const d = new Date(); + d.setHours(0, 0, 0, 0); + return d; + }, []); - const yesterday = new Date(); - yesterday.setDate(yesterday.getDate() - 1); + const yesterday = useMemo(() => { + const d = new Date(); + d.setDate(d.getDate() - 1); + return d; + }, []); - const isSameDay = (dateStr) => { + const isSameDay = useCallback((dateStr) => { if (!dateStr) return false; const d = new Date(dateStr); d.setHours(0, 0, 0, 0); return d.getTime() === today.getTime(); - }; + }, [today]); - const isBeforeToday = (dateStr) => { + const isBeforeToday = useCallback((dateStr) => { if (!dateStr) return false; const d = new Date(dateStr); d.setHours(0, 0, 0, 0); return d.getTime() < today.getTime(); - }; + }, [today]); - const sortByName = (a, b) => { - const nameA = a.firstName.toLowerCase() + a.lastName.toLowerCase(); - const nameB = b.firstName.toLowerCase() + b.lastName.toLowerCase(); - return nameA?.localeCompare(nameB); - }; + const sortByName = useCallback((a, b) => { + const nameA = `${a.firstName || ""} ${a.lastName || ""}`.toLowerCase(); + const nameB = `${b.firstName || ""} ${b.lastName || ""}`.toLowerCase(); + return nameA.localeCompare(nameB); + }, []); - const { - data = [], - isLoading, - error, - refetch, - isFetching, - } = useAttendancesLogs( - selectedProject, - dateRange.startDate, - dateRange.endDate - ); - const filtering = (data) => { - const filteredData = showPending + useEffect(() => { + const { startDate, endDate } = dateRange; + dispatch( + fetchAttendanceData({ + projectId, + fromDate: startDate, + toDate: endDate, + }) + ); + setIsRefreshing(false); + }, [dateRange, projectId, dispatch, isRefreshing]); + + const processedData = useMemo(() => { + let filteredData = showOnlyCheckout ? data.filter((item) => item.checkOutTime === null) : data; + // Apply search query filter + if (searchQuery) { + const lowerCaseSearchQuery = searchQuery.toLowerCase(); + filteredData = filteredData.filter((att) => { + // Construct a full name from available parts, filtering out null/undefined + const fullName = [att.firstName, att.middleName, att.lastName] + .filter(Boolean) // This removes null, undefined, or empty string parts + .join(" ") + .toLowerCase(); + + return ( + att.employeeName?.toLowerCase().includes(lowerCaseSearchQuery) || + att.employeeId?.toLowerCase().includes(lowerCaseSearchQuery) || + fullName.includes(lowerCaseSearchQuery) + ); + }); + } + const group1 = filteredData .filter((d) => d.activity === 1 && isSameDay(d.checkInTime)) .sort(sortByName); @@ -131,74 +165,68 @@ const AttendanceLog = ({ (a, b) => new Date(b) - new Date(a) ); - const finalData = sortedDates.flatMap((date) => groupedByDate[date]); - setProcessedData(finalData); - }; - - useEffect(() => { - filtering(data); - }, [data, showPending]); + // Create the final sorted array + return sortedDates.flatMap((date) => groupedByDate[date]); + }, [data, showOnlyCheckout, searchQuery, isSameDay, isBeforeToday, sortByName]); const { currentPage, totalPages, currentItems: paginatedAttendances, paginate, - resetPage, + resetPage, // Destructure resetPage here } = usePagination(processedData, 20); + // Reset page when processedData changes (due to filters/search) useEffect(() => { resetPage(); - }, [processedData, resetPage]); + }, [processedData, resetPage]); // Add resetPage to dependency array const handler = useCallback( (msg) => { const { startDate, endDate } = dateRange; - const checkIn = msg.response.checkInTime.substring(0, 10); + const checkIn = msg.response.checkInTime ? msg.response.checkInTime.substring(0, 10) : null; + if ( - selectedProject === msg.projectId && + projectId === msg.projectId && + checkIn && startDate <= checkIn && checkIn <= endDate ) { - queryClient.setQueriesData(["attendanceLogs"],(oldData)=>{ - if(!oldData) { - queryClient.invalidateQueries({queryKey:["attendanceLogs"]}) - } - return oldData.map((record) => - record.id === msg.response.id ? { ...record, ...msg.response } : record + dispatch( + fetchAttendanceData({ + projectId, + fromDate: startDate, + toDate: endDate, + }) ); - }) - - filtering(updatedAttendance); - resetPage(); } }, - [selectedProject, dateRange, data, filtering, resetPage] + [projectId, dateRange, dispatch] ); + useEffect(() => { useEffect(() => { eventBus.on("attendance_log", handler); return () => eventBus.off("attendance_log", handler); }, [handler]); + const employeeHandler = useCallback( const employeeHandler = useCallback( (msg) => { const { startDate, endDate } = dateRange; - if (data.some((item) => item.employeeId == msg.employeeId)) { - // dispatch( - // fetchAttendanceData({ - // , - // fromDate: startDate, - // toDate: endDate, - // }) - // ); - - refetch() - } + dispatch( + fetchAttendanceData({ + projectId, + fromDate: startDate, + toDate: endDate, + }) + ); }, - [selectedProject, dateRange, data] + [projectId, dateRange, dispatch] ); + useEffect(() => { useEffect(() => { eventBus.on("employee", employeeHandler); return () => eventBus.off("employee", employeeHandler); @@ -230,18 +258,18 @@ const AttendanceLog = ({
refetch()} />
-
- {isLoading ? ( -

Loading...

- ) : data?.length > 0 ? ( +
+ {processedData && processedData.length > 0 ? ( @@ -260,82 +288,97 @@ const AttendanceLog = ({ - {paginatedAttendances.reduce((acc, attendance, index, arr) => { - const currentDate = moment( - attendance.checkInTime || attendance.checkOutTime - ).format("YYYY-MM-DD"); - const previousAttendance = arr[index - 1]; - const previousDate = previousAttendance - ? moment( + {(loading || isRefreshing) && ( + + + + )} + {!loading && + !isRefreshing && + paginatedAttendances.reduce((acc, attendance, index, arr) => { + const currentDate = moment( + attendance.checkInTime || attendance.checkOutTime + ).format("YYYY-MM-DD"); + const previousAttendance = arr[index - 1]; + const previousDate = previousAttendance + ? moment( previousAttendance.checkInTime || - previousAttendance.checkOutTime + previousAttendance.checkOutTime ).format("YYYY-MM-DD") - : null; + : null; - if (!previousDate || currentDate !== previousDate) { + if (!previousDate || currentDate !== previousDate) { + acc.push( + + + + ); + } acc.push( - - + + + + + ); - } - acc.push( - - - - - - - - ); - return acc; - }, [])} + return acc; + }, [])}
Loading...
+ + {moment(currentDate).format("DD-MM-YYYY")} + +
- - {moment(currentDate).format("DD-MM-YYYY")} - +
+ + + {moment( + attendance.checkInTime || attendance.checkOutTime + ).format("DD-MMM-YYYY")} + {convertShortTime(attendance.checkInTime)} + {attendance.checkOutTime + ? convertShortTime(attendance.checkOutTime) + : "--"} + +
- - - {moment( - attendance.checkInTime || attendance.checkOutTime - ).format("DD-MMM-YYYY")} - {convertShortTime(attendance.checkInTime)} - {attendance.checkOutTime - ? convertShortTime(attendance.checkOutTime) - : "--"} - - -
) : ( -
No Record Available !
- )} + !loading && + !isRefreshing && ( +
+ No employee logs. +
+ ) + ) + }
- {paginatedAttendances?.length == 0 && data?.length > 0 && ( -
No Pending Record Available !
- )} - {processedData.length > 10 && ( + {!loading && !isRefreshing && processedData.length > 20 && (
@@ -244,4 +357,4 @@ const AttendancePage = () => { ); }; -export default AttendancePage; +export default AttendancePage; \ No newline at end of file