Replaced normal hooks to react-query Hook - Employee

This commit is contained in:
Pramod Mahajan 2025-06-26 12:28:02 +05:30
parent 1b5fa173f0
commit fa32913e34
10 changed files with 862 additions and 548 deletions

55
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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 (
<div className="app">
<QueryClientProvider client={queryClient}>
<DireProvider>
<AppRoutes />
</DireProvider>
<ToastContainer>
</ToastContainer>
<ToastContainer />
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</div>
);
};
export default App
export default App;

View File

@ -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);

View File

@ -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");
// 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) => {
setLoading(true);
if (data.email == "") {
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);
updateEmployee(data, {
onSuccess: () => {
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 (
<>
{/* <div className="c">
{!currentEmployee && empLoading && employeeId && (
<p>Loading Employee Data...</p>
)} */}
<form onSubmit={handleSubmit( onSubmit )} className="p-sm-0 p-2">
<div className="text-center"><p className="fs-6 fw-semibold"> {employee ? "Update Employee" : "Create Employee"}</p></div>
<div className="row mb-3">

View File

@ -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 dispatch = useDispatch();
const formStateRef = useRef({});
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 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,83 +34,53 @@ 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;
});
return defaults;
}, [roles, employeeRoles]);
setInitialRoles(updatedRoles);
// Avoid infinite loop by comparing previous form values
useEffect(() => {
const prev = JSON.stringify(formStateRef.current);
const next = JSON.stringify(selectedRoleDefaults);
reset({
selectedRole: updatedRoles,
});
}, [employeeRoles, data, reset]);
if (prev !== next) {
formStateRef.current = selectedRoleDefaults;
reset({ selectedRole: selectedRoleDefaults });
}
}, [selectedRoleDefaults, reset]);
// const onSubmit = (formdata) => {
const onSubmit = async (formData) => {
// setIsLoading(true);
// const result = [];
// const selectedRoles = formdata.selectedRole;
const updates = [];
const selected = formData.selectedRole;
// for (const [roleId, isChecked] of Object.entries(selectedRoles)) {
// const existingRole = employeeRoles?.find((role) => role.roleId === roleId);
// const wasChecked = !!existingRole?.isEnabled;
for (const [roleId, isChecked] of Object.entries(selected)) {
const existing = employeeRoles.find((r) => r.roleId === roleId);
const wasChecked = !!existing?.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
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,
@ -144,83 +88,69 @@ useEffect(()=>{
}
}
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 (
<div
className={`modal fade `}
id="managerole-modal"
tabIndex="-1"
aria-hidden="true"
>
<div className="modal-dialog modal-simple modal-md d-flex align-items-center justify-content-center">
<div className="modal-content ">
<div className="modal-body">
<button
type="button"
className="btn-close"
data-bs-dismiss="modal"
aria-label="Close"
></button>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="text-start my-0">
<div className="text-start mb-3">
<p className="lead">Select Roles</p>
</div>
{isLoadingData ? (
<p>Loading...</p>
) : (
<div
className="d-flex flex-wrap justify-content-between align-items-center pb-5 "
style={{ maxHeight: "70vh", overflowY: "scroll" }}
className="d-flex flex-wrap justify-content-between pb-4"
style={{ maxHeight: "70vh", overflowY: "auto" }}
>
{roleLoading && <p>Loading...</p>}
{loading && <p>Loading...</p>}
{data &&
data.map((item) => (
<div className="col-md-6 col-lg-4 mb-4" key={item.id}>
{roles.map((role) => (
<div className="col-md-6 col-lg-4 mb-3" key={role.id}>
<div className="form-check ms-2 text-start">
<input
className="form-check-input"
type="checkbox"
id={item.id}
{...register(`selectedRole.${item.id}`)}
id={role.id}
{...register(`selectedRole.${role.id}`)}
/>
<label
className="form-check-label text-bold"
htmlFor={item.id}
>
<small>{item.role || "--"}</small>
<label className="form-check-label" htmlFor={role.id}>
<small>{role.role || "--"}</small>
</label>
</div>
</div>
))}
</div>
{errors.selected && (
<div className="text-center">{errors.selected.message}</div>
)}
<div className="col-12 text-center">
<button type="submit" className="btn btn-sm btn-primary me-3">
{isLoading ? "Please Wait" : "Submit"}
{errors.selectedRole && (
<div className="text-danger text-center">
{errors.selectedRole.message}
</div>
)}
<div className="text-center mt-3">
<button type="submit" className="btn btn-sm btn-primary me-3" disabled={isLoading}>
{isLoading ? "Please Wait..." : "Submit"}
</button>
<button
type="reset"
@ -232,10 +162,6 @@ useEffect(()=>{
</button>
</div>
</form>
</div>
</div>
</div>
</div>
);
};

View File

@ -20,7 +20,7 @@ import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import { MANAGE_PROJECT } from "../../utils/constants";
const Header = () => {
const { profile } = useProfile();
const {profile} = useProfile();
const location = useLocation();
const dispatch = useDispatch(changeMaster("Job Role"));
const { data, loading } = useMaster();

View File

@ -3,236 +3,518 @@ import { cacheData, getCachedData } from "../slices/apiDataManager";
import { RolesRepository } from "../repositories/MastersRepository";
import EmployeeRepository from "../repositories/EmployeeRepository";
import ProjectRepository from "../repositories/ProjectRepository";
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
import showToast from "../services/toastService";
import {useSelector} from "react-redux";
import {store} from "../store/store";
export const useAllEmployees = (showInactive) => {
const [employeesList, setEmployeeList] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const fetchData = async () => {
try {
let EmployeeList_cached = getCachedData("AllEmployees");
if (!EmployeeList_cached) {
setLoading(true);
const response = await EmployeeRepository.getAllEmployeeList(showInactive);
cacheData("AllEmployees", response.data);
setEmployeeList(response.data);
setLoading(false);
} else {
setEmployeeList(EmployeeList_cached);
setLoading(false);
}
} catch (error) {
setError("Failed to fetch data.");
setLoading(false);
}
// export const useAllEmployees = (showInactive) => {
// const [employeesList, setEmployeeList] = useState([]);
// const [loading, setLoading] = useState(false);
// const [error, setError] = useState();
// const fetchData = async () => {
// try {
// let EmployeeList_cached = getCachedData("AllEmployees");
// if (!EmployeeList_cached) {
// setLoading(true);
// const response = await EmployeeRepository.getAllEmployeeList(showInactive);
// cacheData("AllEmployees", response.data);
// setEmployeeList(response.data);
// setLoading(false);
// } else {
// setEmployeeList(EmployeeList_cached);
// setLoading(false);
// }
// } catch (error) {
// setError("Failed to fetch data.");
// setLoading(false);
// }
// };
// useEffect(() => {
// fetchData();
// }, []);
// return { employeesList, loading, error };
// };
// export const useEmployees = (selectedProject) => {
// const [employees, setEmployeeList] = useState([]);
// const [loading, setLoading] = useState(true);
// const [projects, setProjects] = useState([]);
// const fetchData = async (projectid) => {
// try {
// let EmployeeByProject_Cache = getCachedData("employeeListByProject");
// if (
// !EmployeeByProject_Cache ||
// !EmployeeByProject_Cache.projectId === projectid
// ) {
// EmployeeRepository.getEmployeeListByproject(projectid)
// .then((response) => {
// setEmployeeList(response);
// cacheData("employeeListByProject", {
// data: response,
// projectId: projectid,
// });
// })
// .catch((error) => {
// setError("Failed to fetch data.");
// });
// } else {
// setEmployeeList(EmployeeByProject_Cache.data);
// }
// setLoading(false);
// } catch (err) {
// setError("Failed to fetch data.");
// setLoading(false);
// }
// };
// useEffect(() => {
// if (selectedProject) {
// fetchData(selectedProject);
// }
// }, [selectedProject]);
// return { employees, loading, projects, reCallAllEmployee };
// };
// export const useEmployeeRoles = (employeeId) => {
// const [loading, setLoading] = useState(true);
// const [error, setError] = useState();
// const [employeeRoles, setEmployeeRoles] = useState([]);
// const fetchData = async (employeeid) => {
// try {
// let response = await RolesRepository.getEmployeeRoles(employeeid);
// setEmployeeRoles(response.data);
// cacheData("employeelist", response.data);
// } catch (err) {
// setError("Failed to fetch data.");
// setEmployeeRoles([]);
// } finally {
// setLoading(false);
// }
// };
// useEffect(() => {
// if (employeeId) {
// fetchData(employeeId);
// }
// }, [employeeId]);
// return { employeeRoles, loading, error };
// };
// export const useEmployeesByProject = (projectId) => {
// const [loading, setLoading] = useState(false);
// const [error, setError] = useState();
// const [employees, setEmployees] = useState([]);
// const fetchData = async () => {
// const Employees_cache = getCachedData("employeeListByProject");
// if (!Employees_cache || Employees_cache.projectId !== projectId) {
// setEmployees(true);
// ProjectRepository.getEmployeesByProject(projectId)
// .then((response) => {
// setEmployees(response.data);
// cacheData("employeeListByProject", {
// data: response.data,
// projectId,
// });
// setLoading(false);
// })
// .catch((error) => {
// setError("Failed to fetch data.");
// setLoading(false);
// });
// } else {
// setEmployees(Employees_cache.data);
// setLoading(false);
// }
// };
// useEffect(() => {
// fetchData(projectId);
// }, [projectId]);
// return { employees, loading, error, recallProjectEmplloyee: fetchData };
// };
// export const useEmployeesAllOrByProjectId = (projectId, showInactive) => {
// const [employees, setEmployees] = useState([]);
// const [loading, setLoading] = useState(false);
// const [error, setError] = useState(null);
// const fetchData = async (showInactive) => {
// if ( projectId )
// {
// const Employees_cache = getCachedData("employeeListByProject");
// if (!Employees_cache || Employees_cache.projectId !== projectId) {
// setLoading(true);
// setError(null);
// try {
// const response = await ProjectRepository.getEmployeesByProject(
// projectId
// );
// setEmployees(response.data);
// cacheData("employeeListByProject", {
// data: response.data,
// projectId,
// });
// setLoading(false);
// } catch (err) {
// setError("Failed to fetch data.");
// setLoading(false);
// }
// } else {
// setEmployees(Employees_cache.data);
// setLoading(false);
// }
// } else
// {
// const cacheKey = showInactive
// ? "allInactiveEmployeeList"
// : "allEmployeeList";
// try {
// const response = await EmployeeRepository.getAllEmployeeList(
// showInactive
// );
// setEmployees(response.data);
// cacheData(cacheKey, { data: response.data });
// setLoading(false);
// } catch (err) {
// setError("Failed to fetch data.");
// setLoading(false);
// }
// }
// };
// useEffect(() => {
// fetchData(showInactive); // Fetch data when the component mounts or projectId changes
// }, [projectId]); // Re-fetch when projectId changes
// return {
// employees,
// loading,
// error,
// recallEmployeeData: fetchData,
// };
// };
// export const useEmployeeProfile = (employeeId) => {
// const [loading, setLoading] = useState(true);
// const [error, setError] = useState();
// const [employee, setEmployees] = useState(null);
// const fetchData = async () => {
// if (!employeeId) {
// // Reset the state if no employeeId (e.g., opening for 'add' mode)
// setEmployees(null);
// setLoading(false);
// return;
// }
// const Employee_cache = getCachedData("employeeProfile");
// if (!Employee_cache || Employee_cache.employeeId !== employeeId) {
// EmployeeRepository.getEmployeeProfile(employeeId)
// .then((response) => {
// setEmployees(response.data);
// cacheData("employeeProfile", { data: response.data, employeeId });
// setLoading(false);
// })
// .catch((error) => {
// setError("Failed to fetch data.");
// setLoading(false);
// });
// } else {
// setEmployees(Employee_cache.data);
// setLoading(false);
// }
// };
// useEffect(() => {
// fetchData();
// }, [employeeId]);
// return { employee, loading, error };
// };
// Query ---------------------------------------------------------------------------
export const useAllEmployees = ( showInactive ) =>
{
const {
data = [],
isLoading,
error,
refetch, // optional if you want recall functionality
} = useQuery({
queryKey: ['allEmployee', showInactive],
queryFn: async () => {
const res = await EmployeeRepository.getAllEmployeeList(showInactive);
return res.data;
},
});
return {
employeesList: data,
loading: isLoading,
error,
recallEmployeeData: refetch,
};
useEffect(() => {
fetchData();
}, []);
return { employeesList, loading, error };
};
export const useEmployees = (selectedProject) => {
const [employees, setEmployeeList] = useState([]);
const [loading, setLoading] = useState(true);
const [projects, setProjects] = useState([]);
// ManageBucket.jsx
export const useEmployees = ( selectedProject ) =>
{
const fetchData = async (projectid) => {
try {
let EmployeeByProject_Cache = getCachedData("employeeListByProject");
if (
!EmployeeByProject_Cache ||
!EmployeeByProject_Cache.projectId === projectid
) {
EmployeeRepository.getEmployeeListByproject(projectid)
.then((response) => {
setEmployeeList(response);
cacheData("employeeListByProject", {
data: response,
projectId: projectid,
const {
data = [],
isLoading,
error,
refetch,
} = useQuery({
queryKey: ["employeeListByProject", selectedProject],
queryFn: async () => {
const res = await EmployeeRepository.getEmployeeListByproject(selectedProject);
return res.data || res;
},
enabled: !!selectedProject,
});
})
.catch((error) => {
setError("Failed to fetch data.");
});
} else {
setEmployeeList(EmployeeByProject_Cache.data);
}
setLoading(false);
} catch (err) {
setError("Failed to fetch data.");
setLoading(false);
}
return {
employees: data,
loading: isLoading,
projects: [], // if needed, pass this separately or manage from another hook
reCallAllEmployee: refetch,
error,
};
useEffect(() => {
if (selectedProject) {
fetchData(selectedProject);
}
}, [selectedProject]);
return { employees, loading, projects, reCallAllEmployee };
};
// ManageRole.jsx
export const useEmployeeRoles = (employeeId) => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState();
const [employeeRoles, setEmployeeRoles] = useState([]);
const fetchData = async (employeeid) => {
try {
let response = await RolesRepository.getEmployeeRoles(employeeid);
setEmployeeRoles(response.data);
cacheData("employeelist", response.data);
} catch (err) {
setError("Failed to fetch data.");
setEmployeeRoles([]);
} finally {
setLoading(false);
}
const {
data = [],
isLoading: loading,
error,
} = useQuery({
queryKey: ['employeeRoles', employeeId],
queryFn: async () => {
const res = await RolesRepository.getEmployeeRoles(employeeId);
return res.data;
},
enabled: !!employeeId,
});
return {
employeeRoles: data,
loading,
error,
};
useEffect(() => {
if (employeeId) {
fetchData(employeeId);
}
}, [employeeId]);
return { employeeRoles, loading, error };
};
// EmployeeProfile.jsx
export const useEmployeesByProject = (projectId) => {
const [loading, setLoading] = useState(false);
const [error, setError] = useState();
const [employees, setEmployees] = useState([]);
const {
data = [],
isLoading: loading,
error,
refetch: recallProjectEmplloyee,
} = useQuery({
queryKey: ['projectEmployees', projectId],
queryFn: async () => {
const res = await ProjectRepository.getEmployeesByProject(projectId);
return res.data;
},
enabled: !!projectId,
});
const fetchData = async () => {
const Employees_cache = getCachedData("employeeListByProject");
if (!Employees_cache || Employees_cache.projectId !== projectId) {
setEmployees(true);
ProjectRepository.getEmployeesByProject(projectId)
.then((response) => {
setEmployees(response.data);
cacheData("employeeListByProject", {
data: response.data,
projectId,
});
setLoading(false);
})
.catch((error) => {
setError("Failed to fetch data.");
setLoading(false);
});
} else {
setEmployees(Employees_cache.data);
setLoading(false);
}
return {
employees: data,
loading,
error,
recallProjectEmplloyee,
};
useEffect(() => {
fetchData(projectId);
}, [projectId]);
return { employees, loading, error, recallProjectEmplloyee: fetchData };
};
// EmployeeList.jsx
export const useEmployeesAllOrByProjectId = (projectId, showInactive) => {
const [employees, setEmployees] = useState([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState(null);
const isAllEmployees = !projectId && projectId !== undefined;
const fetchData = async (showInactive) => {
if ( projectId )
{
const Employees_cache = getCachedData("employeeListByProject");
if (!Employees_cache || Employees_cache.projectId !== projectId) {
setLoading(true);
setError(null);
try {
const response = await ProjectRepository.getEmployeesByProject(
projectId
);
setEmployees(response.data);
cacheData("employeeListByProject", {
data: response.data,
projectId,
});
setLoading(false);
} catch (err) {
setError("Failed to fetch data.");
setLoading(false);
}
const queryKey = isAllEmployees
? ['allEmployees', showInactive]
: ['projectEmployees', projectId];
const queryFn = async () => {
if (isAllEmployees) {
const res = await EmployeeRepository.getAllEmployeeList(showInactive);
return res.data;
} else {
setEmployees(Employees_cache.data);
setLoading(false);
}
} else
{
const cacheKey = showInactive
? "allInactiveEmployeeList"
: "allEmployeeList";
try {
const response = await EmployeeRepository.getAllEmployeeList(
showInactive
);
setEmployees(response.data);
cacheData(cacheKey, { data: response.data });
setLoading(false);
} catch (err) {
setError("Failed to fetch data.");
setLoading(false);
}
const res = await ProjectRepository.getEmployeesByProject(projectId);
return res.data;
}
};
useEffect(() => {
fetchData(showInactive); // Fetch data when the component mounts or projectId changes
}, [projectId]); // Re-fetch when projectId changes
const {
data: employees = [],
isLoading,
error,
refetch,
} = useQuery({
queryKey,
queryFn,
enabled: isAllEmployees || !!projectId,
});
return {
employees,
loading: isLoading,
error,
recallEmployeeData: refetch,
};
};
// ManageEmployee.jsx
export const useEmployeeProfile = (employeeId) => {
const isEnabled = !!employeeId;
const {
data = null,
isLoading: loading,
error,
} = useQuery({
queryKey: ['employeeProfile', employeeId],
queryFn: async () => {
if (!employeeId) return null;
const res = await EmployeeRepository.getEmployeeProfile(employeeId);
return res.data;
},
enabled: isEnabled,
});
return {
employee: data,
loading,
error,
recallEmployeeData: fetchData,
};
};
export const useEmployeeProfile = (employeeId) => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState();
const [employee, setEmployees] = useState(null);
const fetchData = async () => {
if (!employeeId) {
// Reset the state if no employeeId (e.g., opening for 'add' mode)
setEmployees(null);
setLoading(false);
return;
}
const Employee_cache = getCachedData("employeeProfile");
if (!Employee_cache || Employee_cache.employeeId !== employeeId) {
EmployeeRepository.getEmployeeProfile(employeeId)
.then((response) => {
setEmployees(response.data);
cacheData("employeeProfile", { data: response.data, employeeId });
setLoading(false);
})
.catch((error) => {
setError("Failed to fetch data.");
setLoading(false);
// Mutation------------------------------------------------------------------
export const useUpdateEmployee = () =>
{
const selectedProject = useSelector((store)=>store.localVariables.projectId)
const queryClient = useQueryClient();
return useMutation({
mutationFn: (employeeData) => EmployeeRepository.manageEmployee(employeeData),
onSuccess: (_, variables) => {
const id = variables.id || variables.employeeId;
// Cache invalidation
queryClient.invalidateQueries( ['allEmployee',false]);
queryClient.invalidateQueries(['employeeProfile', id]);
queryClient.invalidateQueries( {queryKey: [ 'projectEmployees' ]} );
queryClient.invalidateQueries( [ 'employeeListByProject' ,selectedProject] );
showToast( `Employee ${ id ? 'updated' : 'created' } successfully`, 'success' );
},
onError: (error) => {
const msg = error?.response?.data?.message || error.message || 'Something went wrong';
showToast(msg, 'error');
},
});
} else {
setEmployees(Employee_cache.data);
setLoading(false);
}
};
useEffect(() => {
fetchData();
}, [employeeId]);
return { employee, loading, error };
};
export const useSuspendEmployee = ({ setIsDeleteModalOpen, setemployeeLodaing }) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: (id) => {
setemployeeLodaing(true);
return EmployeeRepository.deleteEmployee(id);
},
onSuccess: () => {
showToast("Employee deleted successfully.", "success");
queryClient.invalidateQueries( ['allEmployee',false]);
queryClient.invalidateQueries( {queryKey: [ 'projectEmployees' ]} );
queryClient.invalidateQueries( [ 'employeeListByProject' ,selectedProject] );
setIsDeleteModalOpen(false);
},
onError: (error) => {
const message =
error.response?.data?.message ||
error.message ||
"An unexpected error occurred";
showToast(message, "error");
setIsDeleteModalOpen(false);
},
onSettled: () => {
setemployeeLodaing(false);
},
});
};
// Manage Role
export const useUpdateEmployeeRoles = ({ onClose, resetForm, onSuccessCallback } = {}) => {
const queryClient = useQueryClient();
const mutation = useMutation({
mutationFn: (updates) => RolesRepository.createEmployeeRoles(updates),
onSuccess: () => {
showToast("Roles updated successfully", "success");
resetForm?.();
onClose?.();
onSuccessCallback?.();
queryClient.invalidateQueries( {queryKey: [ "employeeRoles" ]} );
queryClient.invalidateQueries( {queryKey: [ "profile" ]} );
},
onError: (err) => {
const message =
err?.response?.data?.message || err?.message || "Error occurred while updating roles";
showToast(message, "error");
},
});
return {
updateRoles: mutation.mutate,
isPending: mutation.isPending,
isError: mutation.isError,
error: mutation.error,
};
};

View File

@ -3,60 +3,99 @@ import AuthRepository from "../repositories/AuthRepository";
import {cacheData, cacheProfileData, getCachedData, getCachedProfileData} from "../slices/apiDataManager";
import {useSelector} from "react-redux";
import eventBus from "../services/eventBus";
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
let hasFetched = false;
let hasReceived = false;
// export const useProfile = () => {
// const loggedUser = useSelector( ( store ) => store.globalVariables.loginUser );
// const [profile, setProfile] = useState(null);
// const [loading, setLoading] = useState(false);
// const [error, setError] = useState("");
// const fetchData = async () => {
// try {
// setLoading(true);
// let response = await AuthRepository.profile();
// setProfile(response.data);
// cacheProfileData(response.data);
// } catch (error) {
// setError("Failed to fetch data.");
// } finally {
// setLoading(false);
// }
// };
// const validation = () => {
// if (!hasFetched) {
// hasFetched = true;
// if (!loggedUser) {
// fetchData();
// } else {
// setProfile(loggedUser);
// }
// }
// setProfile(loggedUser);
// }
// useEffect(() => {
// validation();
// }, [loggedUser]);
// const handler = useCallback(
// (data) => {
// if(!getCachedData("hasReceived")){
// cacheData("hasReceived", true);
// hasFetched = false;
// validation();
// }
// },[]
// );
// useEffect(() => {
// eventBus.on("assign_project_one", handler);
// return () => eventBus.off("assign_project_one", handler);
// }, [handler]);
// return { profile, loading, error };
// };
export const useProfile = () => {
const loggedUser = useSelector( ( store ) => store.globalVariables.loginUser );
const [profile, setProfile] = useState(null);
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const loggedUser = useSelector((store) => store.globalVariables.loginUser);
const queryClient = useQueryClient();
const fetchData = async () => {
try {
setLoading(true);
let response = await AuthRepository.profile();
setProfile(response.data);
const {
data: profile,
error,
isLoading,
refetch,
} = useQuery({
queryKey: ["profile"],
queryFn: async () => {
const response = await AuthRepository.profile();
cacheProfileData(response.data);
} catch (error) {
setError("Failed to fetch data.");
} finally {
setLoading(false);
}
};
return response.data;
},
initialData: loggedUser || undefined,
enabled: true,
staleTime: 10 * 60 * 1000,
});
const validation = () => {
if (!hasFetched) {
hasFetched = true;
if (!loggedUser) {
fetchData();
} else {
setProfile(loggedUser);
}
}
setProfile(loggedUser);
}
useEffect(() => {
validation();
}, [loggedUser]);
const handler = useCallback(
(data) => {
if(!getCachedData("hasReceived")){
cacheData("hasReceived", true);
hasFetched = false;
validation();
}
},[]
);
const handler = useCallback(() => {
queryClient.invalidateQueries({ queryKey: ["profile"] });
}, [queryClient]);
useEffect(() => {
eventBus.on("assign_project_one", handler);
return () => eventBus.off("assign_project_one", handler);
}, [handler]);
return { profile, loading, error };
return {
profile,
loading: isLoading,
error,
refetch,
};
};

View File

@ -5,7 +5,7 @@ import { Link, NavLink, useNavigate } from "react-router-dom";
import Avatar from "../../components/common/Avatar";
import Breadcrumb from "../../components/common/Breadcrumb";
import ManageEmp from "../../components/Employee/ManageRole";
import { useEmployeesAllOrByProjectId } from "../../hooks/useEmployees";
import { useEmployeesAllOrByProjectId, useSuspendEmployee } from "../../hooks/useEmployees";
import { useProjects } from "../../hooks/useProjects";
import { useProfile } from "../../hooks/useProfile";
import { hasUserPermission } from "../../utils/authUtils";
@ -26,6 +26,7 @@ import { useSelector } from "react-redux";
import eventBus from "../../services/eventBus";
import { newlineChars } from "pdf-lib";
import GlobalModel from "../../components/common/GlobalModel";
import usePagination from "../../hooks/usePagination";
const EmployeeList = () => {
const selectedProjectId = useSelector((store) => store.localVariables.projectId);
@ -40,9 +41,10 @@ const EmployeeList = () => {
const [projectsList, setProjectsList] = useState(projects || []);
const [employeeList, setEmployeeList] = useState([]);
const [modelConfig, setModelConfig] = useState();
const [currentPage, setCurrentPage] = useState(1);
const [itemsPerPage] = useState(ITEMS_PER_PAGE);
const [ modelConfig, setModelConfig ] = useState();
const [EmpForManageRole,setEmpForManageRole] = useState(null)
// const [currentPage, setCurrentPage] = useState(1);
// const [itemsPerPage] = useState(ITEMS_PER_PAGE);
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const [isEmployeeModalOpen, setIsEmployeeModalOpen] = useState(false);
const [searchText, setSearchText] = useState("");
@ -51,7 +53,16 @@ const EmployeeList = () => {
const [selectedEmployeeId, setSelecedEmployeeId] = useState(null);
const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [selectedEmpFordelete, setSelectedEmpFordelete] = useState(null);
const [employeeLodaing, setemployeeLodaing] = useState(false);
const [ employeeLodaing, setemployeeLodaing ] = useState( false );
const {
mutate: suspendEmployee,
isPending: empLodaing
} = useSuspendEmployee({
setIsDeleteModalOpen,
setemployeeLodaing
} );
const navigate = useNavigate();
@ -65,49 +76,26 @@ const EmployeeList = () => {
const fullName = `${item.firstName} ${item.lastName}`.toLowerCase();
const email = item.email ? item.email.toLowerCase() : "";
const phoneNumber = item.phoneNumber ? item.phoneNumber.toLowerCase() : "";
const jobRole = item.jobRole ? item.jobRole.toLowerCase() : ""; // Get jobRole and convert to lowercase
const jobRole = item.jobRole ? item.jobRole.toLowerCase() : "";
return (
fullName.includes(value) ||
email.includes(value) ||
phoneNumber.includes(value) ||
jobRole.includes(value) // Include jobRole in the search
jobRole.includes(value)
);
});
setFilteredData(results);
};
useEffect(() => {
setCurrentPage(1);
if (!loading && Array.isArray(employees)) {
// Sort by full name (firstName + lastName)
const sorted = [...employees].sort((a, b) => {
const nameA = `${a.firstName || ""}${a.middleName || ""}${b.lastName || ""
}`.toLowerCase();
const nameB = `${b.firstName || ""}${b.middleName || ""}${b.lastName || ""
}`.toLowerCase();
return nameA?.localeCompare(nameB);
});
setEmployeeList(sorted);
setFilteredData(sorted);
}
}, [loading, employees, selectedProject, showAllEmployees]); // Add showAllEmployees to dependencies
const displayData = searchText ? filteredData : employeeList;
const indexOfLastItem = currentPage * itemsPerPage;
const indexOfFirstItem = indexOfLastItem - itemsPerPage;
const currentItems = Array.isArray(displayData)
? displayData.slice(indexOfFirstItem, indexOfLastItem)
: [];
const paginate = (pageNumber) => setCurrentPage(pageNumber);
const totalPages = Array.isArray(displayData)
? Math.ceil(displayData.length / itemsPerPage)
: 0;
const { currentPage, totalPages, currentItems, paginate,setCurrentPage } = usePagination(
displayData,
ITEMS_PER_PAGE
);
const openModal = () => {
setIsCreateModalOpen(true);
};
@ -127,32 +115,50 @@ const EmployeeList = () => {
recallEmployeeData(showInactive);
};
const handleShow = () => setShowModal(true);
const handleClose = () => setShowModal(false);
const handleClose = () => setShowModal( false );
const suspendEmployee = (id) => {
setemployeeLodaing(true);
EmployeeRepository.deleteEmployee(id)
.then((response) => {
showToast("Employee deleted successfully.", "success");
clearCacheKey("employeeListByProject");
clearCacheKey("allEmployeeList");
clearCacheKey("allInactiveEmployeeList");
clearCacheKey("employeeProfile");
setEmployeeList([]);
recallEmployeeData(showInactive);
setemployeeLodaing(false);
setIsDeleteModalOpen(false);
})
.catch((error) => {
const message =
error.response?.data?.message ||
error.message ||
"An unexpected error occurred";
showToast(message, "error");
setemployeeLodaing(false);
setIsDeleteModalOpen(false);
useEffect(() => {
setCurrentPage(1)
if (!loading && Array.isArray(employees)) {
// Sort by full name (firstName + lastName)
const sorted = [...employees].sort((a, b) => {
const nameA = `${a.firstName || ""}${a.middleName || ""}${b.lastName || ""
}`.toLowerCase();
const nameB = `${b.firstName || ""}${b.middleName || ""}${b.lastName || ""
}`.toLowerCase();
return nameA?.localeCompare(nameB);
});
};
setEmployeeList(sorted);
setFilteredData(sorted);
}
}, [loading, employees, selectedProject, showAllEmployees]);
// const suspendEmployee = (id) => {
// setemployeeLodaing(true);
// EmployeeRepository.deleteEmployee(id)
// .then((response) => {
// showToast("Employee deleted successfully.", "success");
// clearCacheKey("employeeListByProject");
// clearCacheKey("allEmployeeList");
// clearCacheKey("allInactiveEmployeeList");
// clearCacheKey("employeeProfile");
// setEmployeeList([]);
// recallEmployeeData(showInactive);
// setemployeeLodaing(false);
// setIsDeleteModalOpen(false);
// })
// .catch((error) => {
// const message =
// error.response?.data?.message ||
// error.message ||
// "An unexpected error occurred";
// showToast(message, "error");
// setemployeeLodaing(false);
// setIsDeleteModalOpen(false);
// });
// };
const handleConfigData = (config) => {
setModelConfig(config);
@ -241,28 +247,11 @@ const handleAllEmployeesToggle = (e) => {
return (
<>
{isCreateModalOpen && (
<ManageEmp employeeId={modelConfig} onClosed={closeModal} />
{EmpForManageRole && (
<GlobalModel isOpen={EmpForManageRole} closeModal={() => setEmpForManageRole( null )}>
<ManageEmp employeeId={EmpForManageRole} onClosed={()=>setEmpForManageRole(null)} />
</GlobalModel>
)}
{/* {showModal && (<div
className={`modal fade ${showModal ? "show" : ""} `}
tabIndex="-1"
role="dialog"
style={{ display: showModal ? "block" : "none" }}
aria-hidden={!showModal}
>
<div className="modal-dialog modal-xl modal-dialog-centered ">
<div
className="modal-content overflow-y-auto overflow-x-hidden"
style={{ maxHeight: "90vh" }}
>
<ManageEmployee
employeeId={selectedEmployeeId}
onClosed={closeModal}
/>
</div>
</div>
</div> )} */}
{showModal && (
<GlobalModel isOpen={showModal} size="lg" closeModal={()=>setShowModal(false)}>
@ -650,7 +639,7 @@ const handleAllEmployeesToggle = (e) => {
data-bs-toggle="modal"
data-bs-target="#managerole-modal"
onClick={() =>
handleConfigData(item.id)
setEmpForManageRole(item.id)
}
>
<i className="bx bx-cog bx-sm"></i>{" "}
@ -670,7 +659,7 @@ const handleAllEmployeesToggle = (e) => {
<div style={{ width: "1%" }}></div>
{/* Pagination */}
{!loading && displayData.length > itemsPerPage && (
{!loading && displayData.length > ITEMS_PER_PAGE && (
<nav aria-label="Page">
<ul className="pagination pagination-sm justify-content-end py-1">
<li