diff --git a/src/components/Activities/Attendance.jsx b/src/components/Activities/Attendance.jsx index a4443dc9..0f726521 100644 --- a/src/components/Activities/Attendance.jsx +++ b/src/components/Activities/Attendance.jsx @@ -11,6 +11,7 @@ import { useSelector } from "react-redux"; import { useQueryClient } from "@tanstack/react-query"; import eventBus from "../../services/eventBus"; import { useSelectedProject } from "../../slices/apiDataManager"; +import Pagination from "../common/Pagination"; const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizationId, includeInactive, date }) => { const queryClient = useQueryClient(); @@ -108,6 +109,8 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat return () => eventBus.off("employee", employeeHandler); }, [employeeHandler]); + + return ( <>
Name Role - Organization + {/* Organization */} Check-In @@ -187,7 +190,7 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat {item.jobRoleName} - {item.organizationName || "--"} + {/* {item.organizationName || "--"} */} {item.checkInTime @@ -226,46 +229,12 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat {!loading && finalFilteredData.length > ITEMS_PER_PAGE && ( - + + )} ) : ( diff --git a/src/components/Activities/AttendcesLogs.jsx b/src/components/Activities/AttendcesLogs.jsx index 71c7328a..fd4ba69b 100644 --- a/src/components/Activities/AttendcesLogs.jsx +++ b/src/components/Activities/AttendcesLogs.jsx @@ -11,6 +11,7 @@ import AttendanceRepository from "../../repositories/AttendanceRepository"; import { useAttendancesLogs } from "../../hooks/useAttendance"; import { queryClient } from "../../layouts/AuthLayout"; import { ITEMS_PER_PAGE } from "../../utils/constants"; +import Pagination from "../common/Pagination"; const usePagination = (data, itemsPerPage) => { const [currentPage, setCurrentPage] = useState(1); @@ -84,56 +85,50 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { dateRange.endDate, organizationId ); - const filtering = (data) => { - const filteredData = showPending - ? data.filter((item) => item.checkOutTime === null) - : data; + const filtering = useCallback((dataToFilter) => { + const filteredData = showPending + ? dataToFilter.filter((item) => item.checkOutTime === null) + : dataToFilter; - const group1 = filteredData - .filter((d) => d.activity === 1 && isSameDay(d.checkInTime)) - .sort(sortByName); - const group2 = filteredData - .filter((d) => d.activity === 4 && isSameDay(d.checkOutTime)) - .sort(sortByName); - const group3 = filteredData - .filter((d) => d.activity === 1 && isBeforeToday(d.checkInTime)) - .sort(sortByName); - const group4 = filteredData.filter( - (d) => d.activity === 4 && isBeforeToday(d.checkOutTime) - ); - const group5 = filteredData - .filter((d) => d.activity === 2 && isBeforeToday(d.checkOutTime)) - .sort(sortByName); - const group6 = filteredData - .filter((d) => d.activity === 5) - .sort(sortByName); + const group1 = filteredData + .filter((d) => d.activity === 1 && isSameDay(d.checkInTime)) + .sort(sortByName); + const group2 = filteredData + .filter((d) => d.activity === 4 && isSameDay(d.checkOutTime)) + .sort(sortByName); + const group3 = filteredData + .filter((d) => d.activity === 1 && isBeforeToday(d.checkInTime)) + .sort(sortByName); + const group4 = filteredData.filter( + (d) => d.activity === 4 && isBeforeToday(d.checkOutTime) + ); + const group5 = filteredData + .filter((d) => d.activity === 2 && isBeforeToday(d.checkOutTime)) + .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]; - // Group by date - const groupedByDate = sortedList.reduce((acc, item) => { - const date = (item.checkInTime || item.checkOutTime)?.split("T")[0]; - if (date) { - acc[date] = acc[date] || []; - acc[date].push(item); - } - return acc; - }, {}); + // Group by date + const groupedByDate = sortedList.reduce((acc, item) => { + const date = (item.checkInTime || item.checkOutTime)?.split("T")[0]; + if (date) { + acc[date] = acc[date] || []; + acc[date].push(item); + } + return acc; + }, {}); - const sortedDates = Object.keys(groupedByDate).sort( - (a, b) => new Date(b) - new Date(a) - ); + const sortedDates = Object.keys(groupedByDate).sort( + (a, b) => new Date(b) - new Date(a) + ); + + const finalData = sortedDates.flatMap((date) => groupedByDate[date]); + setProcessedData(finalData); +}, [showPending]); - const finalData = sortedDates.flatMap((date) => groupedByDate[date]); - setProcessedData(finalData); - }; useEffect(() => { filtering(data); @@ -285,7 +280,7 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { Name Date - Organization + {/* Organization */} Check-In @@ -344,7 +339,7 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { attendance.checkInTime || attendance.checkOutTime ).format("DD-MMM-YYYY")} - {attendance.organizationName || "--"} + {/* {attendance.organizationName || "--"} */} {convertShortTime(attendance.checkInTime)} {attendance.checkOutTime @@ -378,45 +373,11 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => {
)} {filteredSearchData.length > ITEMS_PER_PAGE && ( - + )} ); diff --git a/src/components/Activities/CheckCheckOutForm.jsx b/src/components/Activities/CheckCheckOutForm.jsx index 1473f746..3d7c5e0e 100644 --- a/src/components/Activities/CheckCheckOutForm.jsx +++ b/src/components/Activities/CheckCheckOutForm.jsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; @@ -9,6 +9,7 @@ import showToast from "../../services/toastService"; import { checkIfCurrentDate } from "../../utils/dateUtils"; import { useMarkAttendance } from "../../hooks/useAttendance"; import { useSelectedProject } from "../../slices/apiDataManager"; +import { useProjectName } from "../../hooks/useProjects"; const createSchema = (modeldata) => { return z @@ -19,31 +20,36 @@ const createSchema = (modeldata) => { .max(200, "Description should be less than 200 characters") .optional(), }) - .refine((data) => { - if (modeldata?.checkInTime && !modeldata?.checkOutTime) { - const checkIn = new Date(modeldata.checkInTime); - const [time, modifier] = data.markTime.split(" "); - const [hourStr, minuteStr] = time.split(":"); - let hour = parseInt(hourStr, 10); - const minute = parseInt(minuteStr, 10); + .refine( + (data) => { + if (modeldata?.checkInTime && !modeldata?.checkOutTime) { + const checkIn = new Date(modeldata.checkInTime); + const [time, modifier] = data.markTime.split(" "); + const [hourStr, minuteStr] = time.split(":"); + let hour = parseInt(hourStr, 10); + const minute = parseInt(minuteStr, 10); - if (modifier === "PM" && hour !== 12) hour += 12; - if (modifier === "AM" && hour === 12) hour = 0; + if (modifier === "PM" && hour !== 12) hour += 12; + if (modifier === "AM" && hour === 12) hour = 0; - const checkOut = new Date(checkIn); - checkOut.setHours(hour, minute, 0, 0); + const checkOut = new Date(checkIn); + checkOut.setHours(hour, minute, 0, 0); - return checkOut >= checkIn; + return checkOut >= checkIn; + } + return true; + }, + { + message: "Checkout time must be later than check-in time", + path: ["markTime"], } - return true; - }, { - message: "Checkout time must be later than check-in time", - path: ["markTime"], - }); + ); }; const CheckInCheckOut = ({ modeldata, closeModal, handleSubmitForm }) => { + const [currentProject, setCurrentProject] = useState(null); const projectId = useSelectedProject(); + const { projectNames, loading } = useProjectName(); const { mutate: MarkAttendance } = useMarkAttendance(); const [isLoading, setIsLoading] = useState(false); const coords = usePositionTracker(); @@ -83,7 +89,7 @@ const CheckInCheckOut = ({ modeldata, closeModal, handleSubmitForm }) => { Id: modeldata?.id || null, comment: data.description, employeeID: modeldata.employeeId, - // projectId: projectId, + projectId: projectId, date: new Date().toISOString(), markTime: data.markTime, latitude: coords.latitude.toString(), @@ -95,17 +101,24 @@ const CheckInCheckOut = ({ modeldata, closeModal, handleSubmitForm }) => { closeModal(); }; + useEffect(() => { + if (projectId && projectNames) { + setCurrentProject( + projectNames?.find((project) => project.id === projectId) + ); + } + }, [projectNames, projectId, loading]); + return (
-
)} {!loading && totalPages > 1 && ( - + )} ); diff --git a/src/components/Dashboard/AttendanceChart.jsx b/src/components/Dashboard/AttendanceChart.jsx index 67950d9a..3b58b897 100644 --- a/src/components/Dashboard/AttendanceChart.jsx +++ b/src/components/Dashboard/AttendanceChart.jsx @@ -4,6 +4,7 @@ import ReactApexChart from "react-apexcharts"; import { useAttendanceOverviewData } from "../../hooks/useDashboard_Data"; import flatColors from "../Charts/flatColor"; import ChartSkeleton from "../Charts/Skelton"; +import { useSelectedProject } from "../../slices/apiDataManager"; const formatDate = (dateStr) => { const date = new Date(dateStr); @@ -16,14 +17,17 @@ const formatDate = (dateStr) => { const AttendanceOverview = () => { const [dayRange, setDayRange] = useState(7); const [view, setView] = useState("chart"); - - const projectId = useSelector((store) => store.localVariables.projectId); - const { attendanceOverviewData, loading, error } = useAttendanceOverviewData( - projectId, + const selectedProject = useSelectedProject() + const { data: attendanceOverviewData, isLoading, isError, error } = useAttendanceOverviewData( + selectedProject, dayRange ); const { tableData, roles, dates } = useMemo(() => { + if (!attendanceOverviewData || attendanceOverviewData.length === 0) { + return { tableData: [], roles: [], dates: [] }; + } + const map = new Map(); attendanceOverviewData.forEach((entry) => { @@ -36,7 +40,8 @@ const AttendanceOverview = () => { ...new Set(attendanceOverviewData.map((e) => e.role.trim())), ]; const sortedDates = [...map.keys()]; - const data = sortedDates.map((date) => { + + const tableData = sortedDates.map((date) => { const row = { date }; uniqueRoles.forEach((role) => { row[role] = map.get(date)?.[role] ?? 0; @@ -44,12 +49,8 @@ const AttendanceOverview = () => { return row; }); - return { - tableData: data, - roles: uniqueRoles, - dates: sortedDates, - }; - }, [attendanceOverviewData]); + return { tableData, roles: uniqueRoles, dates: sortedDates }; + }, [attendanceOverviewData,isLoading,selectedProject,dayRange]); const chartSeries = roles.map((role) => ({ name: role, @@ -63,41 +64,21 @@ const AttendanceOverview = () => { height: 400, toolbar: { show: false }, }, - plotOptions: { - bar: { - borderRadius: 2, - columnWidth: "60%", - }, - }, - xaxis: { - categories: tableData.map((row) => row.date), - }, + plotOptions: { bar: { borderRadius: 2, columnWidth: "60%" } }, + xaxis: { categories: tableData.map((row) => row.date) }, yaxis: { show: true, - axisBorder: { - show: true, - color: "#78909C", - offsetX: 0, - offsetY: 0, - }, - axisTicks: { - show: true, - borderType: "solid", - color: "#78909C", - width: 6, - offsetX: 0, - offsetY: 0, - }, - }, - legend: { - position: "bottom", - }, - fill: { - opacity: 1, + axisBorder: { show: true, color: "#78909C" }, + axisTicks: { show: true, color: "#78909C", width: 6 }, }, + legend: { position: "bottom" }, + fill: { opacity: 1 }, colors: roles.map((_, i) => flatColors[i % flatColors.length]), }; + if (isLoading) return
Loading...
; + if (isError) return

{error.message}

; + return (
{/* Header */} @@ -117,18 +98,14 @@ const AttendanceOverview = () => {