From 664fe2473f695e3a6e915da8675225d0bd710ca0 Mon Sep 17 00:00:00 2001 From: Pramod Mahajan Date: Thu, 26 Jun 2025 12:21:19 +0530 Subject: [PATCH 01/57] added optional chain --- src/components/Project/AssignEmployeeTable.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Project/AssignEmployeeTable.jsx b/src/components/Project/AssignEmployeeTable.jsx index eeed33fa..72ea869c 100644 --- a/src/components/Project/AssignEmployeeTable.jsx +++ b/src/components/Project/AssignEmployeeTable.jsx @@ -93,7 +93,7 @@ const AssignEmployeeTable = ({ onChange={handleRoleSelect} > {/* */} - {jobRoles.map((role) => ( + {jobRoles?.map((role) => ( -- 2.43.0 From 1b5fa173f0864a812c6af8af9191531304964c6d Mon Sep 17 00:00:00 2001 From: Pramod Mahajan Date: Thu, 26 Jun 2025 12:26:51 +0530 Subject: [PATCH 02/57] return one more params --- src/hooks/usePagination.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/usePagination.js b/src/hooks/usePagination.js index b3e12b25..ffbbcf60 100644 --- a/src/hooks/usePagination.js +++ b/src/hooks/usePagination.js @@ -14,7 +14,7 @@ const usePagination = (data, itemsPerPage) => { setCurrentPage(pageNumber); }; - return { currentPage, totalPages, currentItems, paginate }; + return { currentPage, totalPages, currentItems, paginate,setCurrentPage }; }; export default usePagination; -- 2.43.0 From fa32913e34aa8277ee74059932601284f20a1af0 Mon Sep 17 00:00:00 2001 From: Pramod Mahajan Date: Thu, 26 Jun 2025 12:28:02 +0530 Subject: [PATCH 03/57] Replaced normal hooks to react-query Hook - Employee --- package-lock.json | 55 ++ package.json | 2 + src/App.tsx | 28 +- src/components/Directory/ManageBucket.jsx | 2 +- src/components/Employee/ManageEmployee.jsx | 89 +-- src/components/Employee/ManageRole.jsx | 272 +++----- src/components/Layout/Header.jsx | 2 +- src/hooks/useEmployees.js | 682 +++++++++++++++------ src/hooks/useProfile.js | 121 ++-- src/pages/employee/EmployeeList.jsx | 157 +++-- 10 files changed, 862 insertions(+), 548 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6d709d89..39e9a3b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,8 @@ "@hookform/resolvers": "^3.10.0", "@microsoft/signalr": "^8.0.7", "@reduxjs/toolkit": "^2.5.0", + "@tanstack/react-query": "^5.81.2", + "@tanstack/react-query-devtools": "^5.81.2", "@types/web": "^0.0.216", "@vitejs/plugin-react": "^4.3.4", "apexcharts": "^4.5.0", @@ -1423,6 +1425,59 @@ "@swc/counter": "^0.1.3" } }, + "node_modules/@tanstack/query-core": { + "version": "5.81.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.81.2.tgz", + "integrity": "sha512-QLYkPdrudoMATDFa3MiLEwRhNnAlzHWDf0LKaXUqJd0/+QxN8uTPi7bahRlxoAyH0UbLMBdeDbYzWALj7THOtw==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/query-devtools": { + "version": "5.81.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.81.2.tgz", + "integrity": "sha512-jCeJcDCwKfoyyBXjXe9+Lo8aTkavygHHsUHAlxQKKaDeyT0qyQNLKl7+UyqYH2dDF6UN/14873IPBHchcsU+Zg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.81.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.81.2.tgz", + "integrity": "sha512-pe8kFlTrL2zFLlcAj2kZk9UaYYHDk9/1hg9EBaoO3cxDhOZf1FRGJeziSXKrVZyxIfs7b3aoOj/bw7Lie0mDUg==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.81.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, + "node_modules/@tanstack/react-query-devtools": { + "version": "5.81.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.81.2.tgz", + "integrity": "sha512-TX0OQ4cbgX6z2uN8c9x0QUNbyePGyUGdcgrGnV6TYEJc7KPT8PqeASuzoA5NGw1CiMGvyFAkIGA2KipvhM9d1g==", + "license": "MIT", + "dependencies": { + "@tanstack/query-devtools": "5.81.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "@tanstack/react-query": "^5.81.2", + "react": "^18 || ^19" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", diff --git a/package.json b/package.json index 757b9840..3f4d52fe 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,8 @@ "@hookform/resolvers": "^3.10.0", "@microsoft/signalr": "^8.0.7", "@reduxjs/toolkit": "^2.5.0", + "@tanstack/react-query": "^5.81.2", + "@tanstack/react-query-devtools": "^5.81.2", "@types/web": "^0.0.216", "@vitejs/plugin-react": "^4.3.4", "apexcharts": "^4.5.0", diff --git a/src/App.tsx b/src/App.tsx index 5499dba1..3fbc0cee 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,21 +1,33 @@ import { DireProvider } from "./Context/DireContext"; import AppRoutes from "./router/AppRoutes"; import { ToastContainer } from "react-toastify"; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 5 * 60 * 1000, // 5 min: data considered fresh + refetchOnWindowFocus: false, // refresh on tab switch + refetchOnReconnect: true, // re-fetch if network was lost + retry: false, + }, + }, +}); const App = () => { return (
- - - - - - - + + + + + + +
); }; -export default App +export default App; diff --git a/src/components/Directory/ManageBucket.jsx b/src/components/Directory/ManageBucket.jsx index e32aaed0..0af5108a 100644 --- a/src/components/Directory/ManageBucket.jsx +++ b/src/components/Directory/ManageBucket.jsx @@ -19,7 +19,7 @@ import { useProfile } from "../../hooks/useProfile"; const ManageBucket = () => { const { profile } = useProfile(); const [bucketList, setBucketList] = useState([]); - const { employeesList } = useAllEmployees(false); + const {employeesList} = useAllEmployees( false ); const [selectedEmployee, setSelectEmployee] = useState([]); const { buckets, loading, refetch } = useBuckets(); const [action_bucket, setAction_bucket] = useState(false); diff --git a/src/components/Employee/ManageEmployee.jsx b/src/components/Employee/ManageEmployee.jsx index 7cb4b0f1..93bd433f 100644 --- a/src/components/Employee/ManageEmployee.jsx +++ b/src/components/Employee/ManageEmployee.jsx @@ -9,20 +9,21 @@ import { useDispatch } from "react-redux"; import { changeMaster } from "../../slices/localVariablesSlice"; import { Link, useNavigate, useParams } from "react-router-dom"; import { formatDate } from "../../utils/dateUtils"; -import { useEmployeeProfile } from "../../hooks/useEmployees"; +import { useEmployeeProfile, useUpdateEmployee } from "../../hooks/useEmployees"; import { cacheData, clearCacheKey, getCachedData, } from "../../slices/apiDataManager"; import { clearApiCacheKey } from "../../slices/apiCacheSlice"; +import {useMutation} from "@tanstack/react-query"; const mobileNumberRegex = /^[0-9]\d{9}$/; const ManageEmployee = ({ employeeId, onClosed }) => { const dispatch = useDispatch(); +const { mutate: updateEmployee, isLoading } = useUpdateEmployee(); - // const { employeeId } = useParams(); const { employee, error, @@ -163,39 +164,53 @@ const ManageEmployee = ({ employeeId, onClosed }) => { const AadharNumberValue = watch("aadharNumber") || ""; - const onSubmit = (data) => { - setLoading(true); - if (data.email == "") { - data.email = null; - } - EmployeeRepository.manageEmployee(data) - .then((response) => { - cacheData("employeeProfileInfo", data); - showToast( - `Employee details ${ - data.id == null ? "created" : "updated" - } successfully.`, - "success" - ); - clearCacheKey("employeeListByProject"); - clearCacheKey("allEmployeeList"); - clearCacheKey("allInactiveEmployeeList"); - clearCacheKey("employeeProfile"); + // const onSubmit = (data) => { + // setLoading(true); + // if (data.email == "") { + // data.email = null; + // } + // EmployeeRepository.manageEmployee(data) + // .then((response) => { + // cacheData("employeeProfileInfo", data); + // showToast( + // `Employee details ${ + // data.id == null ? "created" : "updated" + // } successfully.`, + // "success" + // ); + // clearCacheKey("employeeListByProject"); + // clearCacheKey("allEmployeeList"); + // clearCacheKey("allInactiveEmployeeList"); + // clearCacheKey("employeeProfile"); + + // setLoading(false); + // reset(); + // // navigation("/employees"); + // onClosed(); + // }) + // .catch((error) => { + // const message = + // error?.response?.data?.message || + // error?.message || + // "Error occured during api calling"; + // showToast(message, "error"); + // setLoading(false); + // }); + // }; + + const onSubmit = (data) => { + if (data.email === "") { + data.email = null; + } + + updateEmployee(data, { + onSuccess: () => { + reset(); + onClosed(); + }, + }); +}; - setLoading(false); - reset(); - // navigation("/employees"); - onClosed(); - }) - .catch((error) => { - const message = - error?.response?.data?.message || - error?.message || - "Error occured during api calling"; - showToast(message, "error"); - setLoading(false); - }); - }; useEffect(() => { if (!loading && !error && employee) { @@ -233,12 +248,6 @@ const ManageEmployee = ({ employeeId, onClosed }) => { return ( <> - - {/*
- {!currentEmployee && empLoading && employeeId && ( -

Loading Employee Data...

- )} */} -

{employee ? "Update Employee" : "Create Employee"}

diff --git a/src/components/Employee/ManageRole.jsx b/src/components/Employee/ManageRole.jsx index 4d30cc16..3ab78c5c 100644 --- a/src/components/Employee/ManageRole.jsx +++ b/src/components/Employee/ManageRole.jsx @@ -1,12 +1,13 @@ -import React, { useEffect, useState } from "react"; -import useMaster from "../../hooks/masterHook/useMaster"; +import React, { useEffect, useRef, useState, useMemo } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { zodResolver } from "@hookform/resolvers/zod"; -import { RolesRepository } from "../../repositories/MastersRepository"; -import { useEmployeeRoles } from "../../hooks/useEmployees"; import { useDispatch } from "react-redux"; + +import { useEmployeeRoles, useUpdateEmployeeRoles } from "../../hooks/useEmployees"; +import useMaster from "../../hooks/masterHook/useMaster"; import { changeMaster } from "../../slices/localVariablesSlice"; +import { RolesRepository } from "../../repositories/MastersRepository"; import showToast from "../../services/toastService"; const formSchema = z.object({ @@ -15,44 +16,17 @@ const formSchema = z.object({ const ManageRole = ( {employeeId, onClosed} ) => { - - const disptach = useDispatch(); -useEffect(()=>{ - disptach(changeMaster("Application Role")); -},[disptach]) - const [isLoading, setIsLoading] = useState(false); - const { employeeRoles, loading } = useEmployeeRoles(employeeId); - const { data, loading: roleLoading } = useMaster(); + const dispatch = useDispatch(); + const formStateRef = useRef({}); - const buildDefaultRoles = () => { - const defaults = {}; - data.forEach((role) => { - const isRoleEnabled = employeeRoles?.some( - (empRole) => empRole.roleId === role.id - ); - defaults[role.id] = isRoleEnabled; - }); - - return defaults; - }; - - const [initialRoles, setInitialRoles] = useState({}); useEffect(() => { - if (employeeRoles && data) { - if (employeeRoles.length > 0) { - const updatedRoles = buildDefaultRoles(); - setInitialRoles(updatedRoles); - } else { - setInitialRoles({}); - } - } else { - setInitialRoles({}); - } - }, [employeeRoles, data]); - - + dispatch(changeMaster("Application Role")); + }, [dispatch]); + + const { employeeRoles = [], loading: empLoading } = useEmployeeRoles(employeeId); + const { data: roles = [], loading: roleLoading } = useMaster(); const { register, handleSubmit, @@ -60,167 +34,123 @@ useEffect(()=>{ reset, } = useForm({ resolver: zodResolver(formSchema), - + defaultValues: { selectedRole: {} }, }); - - useEffect(() => { - if (!data) return; - - const updatedRoles = {}; - data.forEach((role) => { - const isRoleEnabled = employeeRoles?.some( + const { + updateRoles, + isPending : isLoading, + isError, + error, + } = useUpdateEmployeeRoles({ + onClose: onClosed, + resetForm: reset, + }); + // Prepare default form values based on roles and current assignments + const selectedRoleDefaults = useMemo(() => { + const defaults = {}; + roles.forEach((role) => { + const enabled = employeeRoles.some( (empRole) => empRole.roleId === role.id && empRole.isEnabled ); - updatedRoles[role.id] = isRoleEnabled || false; + defaults[role.id] = enabled; }); - - setInitialRoles(updatedRoles); - - reset({ - selectedRole: updatedRoles, - }); - }, [employeeRoles, data, reset]); - - // const onSubmit = (formdata) => { - // setIsLoading(true); - // const result = []; - - // const selectedRoles = formdata.selectedRole; - - // for (const [roleId, isChecked] of Object.entries(selectedRoles)) { - // const existingRole = employeeRoles?.find((role) => role.roleId === roleId); - // const wasChecked = !!existingRole?.isEnabled; - - // // Only push if the checked status has changed - // if (isChecked !== wasChecked) { - // result.push({ - // id: existingRole?.id || "00000000-0000-0000-0000-000000000000", - // employeeId, - // roleId, - // isEnabled: isChecked, - // }); - // } - // } - - // if (result.length === 0) { - // showToast("No changes made", "info"); - // setIsLoading(false); - // return; - // } - - // console.log(result); - - // RolesRepository.createEmployeeRoles(result) - // .then(() => { - // showToast("Roles updated successfully", "success"); - // setIsLoading(false); - // reset(); - // onClosed(); - // }) - // .catch((err) => { - // console.error(err); - // showToast(err.message, "error"); - // setIsLoading(false); - // }); - // }; - - const onSubmit = (formdata) => { - setIsLoading(true); - const result = []; - const selectedRoles = formdata.selectedRole; - - for (const [roleId, isChecked] of Object.entries(selectedRoles)) { - const existingRole = employeeRoles?.find((role) => role.roleId === roleId); - const wasChecked = !!existingRole?.isEnabled; - - // Only push if the checked status has changed + return defaults; + }, [roles, employeeRoles]); + + // Avoid infinite loop by comparing previous form values + useEffect(() => { + const prev = JSON.stringify(formStateRef.current); + const next = JSON.stringify(selectedRoleDefaults); + + if (prev !== next) { + formStateRef.current = selectedRoleDefaults; + reset({ selectedRole: selectedRoleDefaults }); + } + }, [selectedRoleDefaults, reset]); + + const onSubmit = async (formData) => { + // setIsLoading(true); + + const updates = []; + const selected = formData.selectedRole; + + for (const [roleId, isChecked] of Object.entries(selected)) { + const existing = employeeRoles.find((r) => r.roleId === roleId); + const wasChecked = !!existing?.isEnabled; + if (isChecked !== wasChecked) { - result.push({ - id: existingRole?.id || "00000000-0000-0000-0000-000000000000", + updates.push({ + id: existing?.id || "00000000-0000-0000-0000-000000000000", employeeId, roleId, isEnabled: isChecked, }); } } - - if (result.length === 0) { + + if (updates.length === 0) { showToast("No changes made", "info"); - setIsLoading(false); + // setIsLoading(false); return; } - - console.log(result); - - RolesRepository.createEmployeeRoles(result) - .then(() => { - showToast("Roles updated successfully", "success"); - setIsLoading(false); - reset(); - onClosed(); - }) - .catch((error) => { - const message = error?.response?.data?.message || error?.message || "Error occured during api calling" - showToast(message, "error"); - setIsLoading(false); - }); + + // try { + // await RolesRepository.createEmployeeRoles(updates); + // showToast("Roles updated successfully", "success"); + // reset(); + // onClosed(); + // } catch (err) { + // const message = + // err?.response?.data?.message || err?.message || "Error occurred while updating roles"; + // showToast(message, "error"); + // } finally { + // setIsLoading(false); + // } + updateRoles(updates); }; - + + const isLoadingData = roleLoading || empLoading; + return ( -