From 8bcfcc5718bc9342a34d00ee9add1ed9a8eb4479 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Tue, 7 Oct 2025 12:17:27 +0530 Subject: [PATCH] fixed attendance - check In -out and persisted date range from Redux store for attendance logs --- src/components/Activities/Attendance.jsx | 4 +- src/components/Activities/AttendcesLogs.jsx | 78 +++++------ .../Activities/CheckCheckOutForm.jsx | 12 +- src/components/common/DateRangePicker.jsx | 48 ++++--- src/hooks/useAttendance.js | 127 +++++++++++------- src/pages/Activities/AttendancePage.jsx | 36 ++--- src/slices/localVariablesSlice.jsx | 30 +++-- 7 files changed, 188 insertions(+), 147 deletions(-) diff --git a/src/components/Activities/Attendance.jsx b/src/components/Activities/Attendance.jsx index a4443dc9..9a082976 100644 --- a/src/components/Activities/Attendance.jsx +++ b/src/components/Activities/Attendance.jsx @@ -12,7 +12,7 @@ import { useQueryClient } from "@tanstack/react-query"; import eventBus from "../../services/eventBus"; import { useSelectedProject } from "../../slices/apiDataManager"; -const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizationId, includeInactive, date }) => { +const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizationId, }) => { const queryClient = useQueryClient(); const [loading, setLoading] = useState(false); const navigate = useNavigate(); @@ -24,7 +24,7 @@ const Attendance = ({ getRole, handleModalData, searchTerm, projectId, organizat loading: attLoading, recall: attrecall, isFetching - } = useAttendance(selectedProject, organizationId, includeInactive, date); + } = useAttendance(selectedProject, organizationId); const filteredAttendance = ShowPending ? attendance?.filter( (att) => att?.checkInTime !== null && att?.checkOutTime === null diff --git a/src/components/Activities/AttendcesLogs.jsx b/src/components/Activities/AttendcesLogs.jsx index 71c7328a..267bec1d 100644 --- a/src/components/Activities/AttendcesLogs.jsx +++ b/src/components/Activities/AttendcesLogs.jsx @@ -5,7 +5,11 @@ import { convertShortTime } from "../../utils/dateUtils"; import RenderAttendanceStatus from "./RenderAttendanceStatus"; import { useSelector, useDispatch } from "react-redux"; import DateRangePicker from "../common/DateRangePicker"; -import { clearCacheKey, getCachedData, useSelectedProject } from "../../slices/apiDataManager"; +import { + clearCacheKey, + getCachedData, + useSelectedProject, +} from "../../slices/apiDataManager"; import eventBus from "../../services/eventBus"; import AttendanceRepository from "../../repositories/AttendanceRepository"; import { useAttendancesLogs } from "../../hooks/useAttendance"; @@ -33,7 +37,7 @@ const usePagination = (data, itemsPerPage) => { }; }; -const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { +const AttendanceLog = ({ handleModalData, searchTerm, organizationId }) => { // const selectedProject = useSelector( // (store) => store.localVariables.projectId // ); @@ -41,7 +45,7 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" }); const dispatch = useDispatch(); const [loading, setLoading] = useState(false); - const [showPending, setShowPending] = useState(false) + const [showPending, setShowPending] = useState(false); const [isRefreshing, setIsRefreshing] = useState(false); const [processedData, setProcessedData] = useState([]); @@ -151,33 +155,6 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { }); }, [processedData, searchTerm]); -// const filteredSearchData = useMemo(() => { -// let tempData = processedData; - -// if (searchTerm) { -// const lowercasedSearchTerm = searchTerm.toLowerCase(); -// tempData = tempData.filter((item) => { -// const fullName = `${item.firstName} ${item.lastName}`.toLowerCase(); -// return fullName.includes(lowercasedSearchTerm); -// }); -// } - -// if (filters?.selectedOrganization) { -// tempData = tempData.filter( -// (item) => item.organization?.name === filters.selectedOrganization -// ); -// } - -// if (filters?.selectedServices?.length > 0) { -// tempData = tempData.filter((item) => -// filters.selectedServices.includes(item.service?.name) -// ); -// } - -// return tempData; -// }, [processedData, searchTerm, filters]); - - const { currentPage, totalPages, @@ -235,7 +212,7 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { // }) // ); - refetch() + refetch(); } }, [selectedProject, dateRange, data, refetch] @@ -270,11 +247,16 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { - -
+
{isLoading ? ( -
+

Loading...

) : filteredSearchData?.length > 0 ? ( @@ -287,7 +269,8 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { Date Organization - Check-In + {" "} + Check-In Check-Out @@ -303,9 +286,9 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { const previousAttendance = arr[index - 1]; const previousDate = previousAttendance ? moment( - previousAttendance.checkInTime || - previousAttendance.checkOutTime - ).format("YYYY-MM-DD") + previousAttendance.checkInTime || + previousAttendance.checkOutTime + ).format("YYYY-MM-DD") : null; if (!previousDate || currentDate !== previousDate) { @@ -344,7 +327,7 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { attendance.checkInTime || attendance.checkOutTime ).format("DD-MMM-YYYY")} - {attendance.organizationName || "--"} + {attendance.organizationName || "--"} {convertShortTime(attendance.checkInTime)} {attendance.checkOutTime @@ -366,7 +349,12 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { ) : ( -
No data available for the selected date range. Please Select another date.
+
+ + No data available for the selected date range. Please Select + another date. + +
)}
{paginatedAttendances?.length == 0 && filteredSearchData?.length > 0 && ( @@ -392,8 +380,9 @@ const AttendanceLog = ({ handleModalData, searchTerm ,organizationId}) => { (pageNumber) => (
  • ); }; @@ -76,6 +87,7 @@ export default DateRangePicker; + export const DateRangePicker1 = ({ startField = "startDate", endField = "endDate", diff --git a/src/hooks/useAttendance.js b/src/hooks/useAttendance.js index 7929223d..70c06cdd 100644 --- a/src/hooks/useAttendance.js +++ b/src/hooks/useAttendance.js @@ -1,5 +1,9 @@ import { useEffect, useState } from "react"; -import { cacheData, getCachedData, useSelectedProject } from "../slices/apiDataManager"; +import { + cacheData, + getCachedData, + useSelectedProject, +} from "../slices/apiDataManager"; import AttendanceRepository from "../repositories/AttendanceRepository"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import showToast from "../services/toastService"; @@ -7,11 +11,8 @@ import { useDispatch, useSelector } from "react-redux"; import { store } from "../store/store"; import { setDefaultDateRange } from "../slices/localVariablesSlice"; - - // ----------------------------Query----------------------------- - // export const useAttendance = (projectId) => { // const dispatch = useDispatch() // const { @@ -41,7 +42,10 @@ import { setDefaultDateRange } from "../slices/localVariablesSlice"; // }; // }; -export const useAttendance = (projectId, organizationId, includeInactive = false, date = null) => { +export const useAttendance = ( + projectId, + organizationId, +) => { const dispatch = useDispatch(); const { @@ -51,13 +55,11 @@ export const useAttendance = (projectId, organizationId, includeInactive = false refetch: recall, isFetching, } = useQuery({ - queryKey: ["attendance", projectId, organizationId, includeInactive, date], // include filters in cache key + queryKey: ["attendance", projectId, organizationId], // include filters in cache key queryFn: async () => { const response = await AttendanceRepository.getAttendance( projectId, organizationId, - includeInactive, - date ); return response.data; }, @@ -70,12 +72,17 @@ export const useAttendance = (projectId, organizationId, includeInactive = false return { attendance, loading, error, recall, isFetching }; }; -export const useAttendancesLogs = (projectId, fromDate, toDate,organizationId) => { +export const useAttendancesLogs = ( + projectId, + fromDate, + toDate, + organizationId +) => { const dispatch = useDispatch(); const enabled = !!projectId && !!fromDate && !!toDate; const query = useQuery({ - queryKey: ['attendanceLogs', projectId, fromDate, toDate,organizationId], + queryKey: ["attendanceLogs", projectId, fromDate, toDate, organizationId], queryFn: async () => { const res = await AttendanceRepository.getAttendanceFilteredByDate( projectId, @@ -87,7 +94,7 @@ export const useAttendancesLogs = (projectId, fromDate, toDate,organizationId) = }, enabled, }); - + useEffect(() => { if (query.data && fromDate && toDate) { dispatch( @@ -101,8 +108,6 @@ export const useAttendancesLogs = (projectId, fromDate, toDate,organizationId) = return query; }; - - export const useEmployeeAttendacesLog = (id) => { const { data: logs = [], @@ -117,7 +122,10 @@ export const useEmployeeAttendacesLog = (id) => { }, enabled: !!id, onError: (error) => { - showToast(error.message || "Error while fetching Attendance Logs", "error"); + showToast( + error.message || "Error while fetching Attendance Logs", + "error" + ); }, }); @@ -135,16 +143,22 @@ export const useAttendanceByEmployee = (employeeId, fromDate, toDate) => { return useQuery({ queryKey: ["employeeAttendance", employeeId, fromDate, toDate], queryFn: async () => { - const res = await AttendanceRepository.getAttendanceByEmployee(employeeId, fromDate, toDate); + const res = await AttendanceRepository.getAttendanceByEmployee( + employeeId, + fromDate, + toDate + ); return res.data; }, - enabled + enabled, }); }; - - -export const useRegularizationRequests = (projectId, organizationId, IncludeInActive = false) => { +export const useRegularizationRequests = ( + projectId, + organizationId, + IncludeInActive = false +) => { const dispatch = useDispatch(); const { @@ -159,7 +173,7 @@ export const useRegularizationRequests = (projectId, organizationId, IncludeInAc const response = await AttendanceRepository.getRegularizeList( projectId, organizationId, - IncludeInActive, + IncludeInActive ); return response.data; }, @@ -172,48 +186,61 @@ export const useRegularizationRequests = (projectId, organizationId, IncludeInAc return { regularizes, loading, error, recall, isFetching }; }; - // -------------------Mutation-------------------------------------- export const useMarkAttendance = () => { const queryClient = useQueryClient(); const selectedProject = useSelectedProject(); - const selectedDateRange = useSelector((store)=>store.localVariables.defaultDateRange) + const selectedDateRange = useSelector( + (store) => store.localVariables.attendance.defaultDateRange + ); + const selectedOrganization = useSelector( + (store) => store.localVariables.attendance.SelectedOrg + ); return useMutation({ - mutationFn: async ({payload,forWhichTab}) => { + mutationFn: async ({ payload, forWhichTab }) => { const res = await AttendanceRepository.markAttendance(payload); return res.data; }, - onSuccess: (data,variables) => { - if(variables.forWhichTab == 1){ - queryClient.setQueryData(["attendance",selectedProject], (oldData) => { - if (!oldData) return oldData; - return oldData.map((emp) => - emp.employeeId === data.employeeId ? { ...emp, ...data } : emp - ); - }); - }else if(variables.forWhichTab == 2){ - // queryClient.invalidateQueries({ - // queryKey: ["attendanceLogs"], - // }); - queryClient.setQueryData(["attendanceLogs",selectedProject,selectedDateRange.startDate,selectedDateRange.endDate], (oldData) => { - if (!oldData) return oldData; - return oldData.map((record) => - record.id === data.id ? { ...record, ...data } : record - ); - }); - queryClient.invalidateQueries({queryKey:["regularizedList"]}) - }else( - queryClient.setQueryData(["regularizedList",selectedProject], (oldData) => { - if (!oldData) return oldData; - return oldData.filter((record) => record.id !== data.id) - }), - queryClient.invalidateQueries({queryKey:["attendanceLogs"]}) - ) + onSuccess: (data, variables) => { + if (variables.forWhichTab == 1) { + queryClient.setQueryData(["attendance", selectedProject,selectedOrganization], (oldData) => { - if(variables.forWhichTab !== 3) showToast("Attendance marked successfully", "success"); + if (!oldData) return oldData; + return oldData.map((emp) => + emp.employeeId === data.employeeId ? { ...emp, ...data } : emp + ); + }); + } else if (variables.forWhichTab == 2) { + queryClient.setQueryData( + [ + "attendanceLogs", + selectedProject, + selectedDateRange.startDate, + selectedDateRange.endDate,selectedOrganization + ], + (oldData) => { + if (!oldData) return oldData; + return oldData.map((record) => + record.id === data.id ? { ...record, ...data } : record + ); + } + ); + queryClient.invalidateQueries({ queryKey: ["regularizedList"] }); + } else + queryClient.setQueryData( + ["regularizedList", selectedProject], + (oldData) => { + if (!oldData) return oldData; + return oldData.filter((record) => record.id !== data.id); + } + ), + queryClient.invalidateQueries({ queryKey: ["attendanceLogs"] }); + + if (variables.forWhichTab !== 3) + showToast("Attendance marked successfully", "success"); }, onError: (error) => { showToast(error.message || "Failed to mark attendance", "error"); diff --git a/src/pages/Activities/AttendancePage.jsx b/src/pages/Activities/AttendancePage.jsx index 4cd5956a..fcf8c9b4 100644 --- a/src/pages/Activities/AttendancePage.jsx +++ b/src/pages/Activities/AttendancePage.jsx @@ -16,7 +16,10 @@ import { setProjectId } from "../../slices/localVariablesSlice"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { REGULARIZE_ATTENDANCE } from "../../utils/constants"; import eventBus from "../../services/eventBus"; -import { useProjectAssignedOrganizations, useProjectName } from "../../hooks/useProjects"; +import { + useProjectAssignedOrganizations, + useProjectName, +} from "../../hooks/useProjects"; import GlobalModel from "../../components/common/GlobalModel"; import CheckCheckOutmodel from "../../components/Activities/CheckCheckOutForm"; import AttendLogs from "../../components/Activities/AttendLogs"; @@ -101,11 +104,11 @@ const AttendancePage = () => { {(modelConfig?.action === 0 || modelConfig?.action === 1 || modelConfig?.action === 2) && ( - - )} + + )} {/* For view logs */} {modelConfig?.action === 6 && ( @@ -134,8 +137,9 @@ const AttendancePage = () => {
  • - - diff --git a/src/slices/localVariablesSlice.jsx b/src/slices/localVariablesSlice.jsx index 784100e0..b7885cf7 100644 --- a/src/slices/localVariablesSlice.jsx +++ b/src/slices/localVariablesSlice.jsx @@ -4,10 +4,11 @@ const localVariablesSlice = createSlice({ name: "localVariables", initialState: { selectedMaster: "Application Role", - regularizationCount: 0, - defaultDateRange: { - startDate: null, - endDate: null, + // Attendances + attendance: { + regularizationCount: 0, + defaultDateRange: { startDate: null, endDate: null }, + SelectedOrg:null, }, projectId: null, reload: false, @@ -28,9 +29,20 @@ const localVariablesSlice = createSlice({ changeMaster: (state, action) => { state.selectedMaster = action.payload; }, + + + // ─── ATTENDANCE ───────────────────────── updateRegularizationCount: (state, action) => { - state.regularizationCount = action.payload; + state.attendance.regularizationCount = action.payload; }, + setDefaultDateRange: (state, action) => { + state.attendance.defaultDateRange = action.payload; + }, + setOrganization:(state,action)=>{ + state.attendance.SelectedOrg = action.payload; + }, + + setProjectId: (state, action) => { localStorage.setItem("project", null); state.projectId = action.payload; @@ -39,10 +51,6 @@ const localVariablesSlice = createSlice({ refreshData: (state, action) => { state.reload = action.payload; }, - setDefaultDateRange: (state, action) => { - state.defaultDateRange = action.payload; - }, - openOrgModal: (state, action) => { state.OrganizationModal.isOpen = true; state.OrganizationModal.orgData = action.payload?.orgData || null; @@ -83,6 +91,6 @@ export const { closeOrgModal, toggleOrgModal, openAuthModal, - closeAuthModal, + closeAuthModal,setOrganization } = localVariablesSlice.actions; -export default localVariablesSlice.reducer; \ No newline at end of file +export default localVariablesSlice.reducer;