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..be7a72ba 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,21 +1,25 @@ import { DireProvider } from "./Context/DireContext"; import AppRoutes from "./router/AppRoutes"; import { ToastContainer } from "react-toastify"; +import { QueryClientProvider } from '@tanstack/react-query'; +import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; +import { queryClient } from "./layouts/AuthLayout"; + const App = () => { return (
- - - - - - - + + + + + + +
); }; -export default App +export default App; diff --git a/src/components/Activities/InfraPlanning.jsx b/src/components/Activities/InfraPlanning.jsx index 47c4dba9..da0a9a33 100644 --- a/src/components/Activities/InfraPlanning.jsx +++ b/src/components/Activities/InfraPlanning.jsx @@ -8,7 +8,7 @@ import WorkAreaModel from "../Project/Infrastructure/WorkAreaModel"; import TaskModel from "../Project/Infrastructure/TaskModel"; import ProjectRepository from "../../repositories/ProjectRepository"; import Breadcrumb from "../../components/common/Breadcrumb"; -import {useProjectDetails, useProjects} from "../../hooks/useProjects"; +import {useProjectDetails, useProjectInfra, useProjects} from "../../hooks/useProjects"; import {useHasUserPermission} from "../../hooks/useHasUserPermission"; import {MANAGE_PROJECT_INFRA} from "../../utils/constants"; import {useDispatch, useSelector} from "react-redux"; @@ -21,17 +21,14 @@ const InfraPlanning = () => { const {profile: LoggedUser, refetch : fetchData} = useProfile() const dispatch = useDispatch() - const {projects,loading:project_listLoader,error:projects_error} = useProjects() - const selectedProject = useSelector((store)=>store.localVariables.projectId) + const {projectInfra, isLoading, error} = useProjectInfra( selectedProject ) + + + const ManageInfra = useHasUserPermission( MANAGE_PROJECT_INFRA ) - const {projects_Details, loading: project_deatilsLoader, error: project_error,refetch} = useProjectDetails( selectedProject ) const reloadedData = useSelector( ( store ) => store.localVariables.reload ) - - // useEffect( () => - // { - // dispatch(setProjectId(projects[0]?.id)) - // }, [ projects ] ) + useEffect( () => { @@ -47,34 +44,20 @@ const InfraPlanning = () =>
-
- {/*
-
- -
- -
*/} + {ManageInfra ? ( +
- {project_deatilsLoader && (

Loading...

)} - {( !project_deatilsLoader && projects_Details?.buildings.length === 0 ) && (

No Result Found

)} - - - - {(!project_deatilsLoader && projects_Details?.buildings?.length > 0) && ()} + {isLoading && (

Loading...

)} + {( !isLoading && projectInfra?.length === 0 ) && (

No Result Found

)} + {(!isLoading && projectInfra?.length > 0) && ()}
+ ) : ( +
+ +

Access Denied: You don't have permission to perform this action. !

+
+ )}
diff --git a/src/components/Activities/ReportTask.jsx b/src/components/Activities/ReportTask.jsx index 13b7228a..8194a5cc 100644 --- a/src/components/Activities/ReportTask.jsx +++ b/src/components/Activities/ReportTask.jsx @@ -1,21 +1,29 @@ -import React, { useState,useEffect } from "react"; +import React, { useState, useEffect } from "react"; import { formatDate } from "../../utils/dateUtils"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import showToast from "../../services/toastService"; import { TasksRepository } from "../../repositories/TaskRepository"; +import { useReportTask } from "../../hooks/useTasks"; -export const ReportTask = ({ report, closeModal, refetch }) => { - const [loading, setloading] = useState(false); +export const ReportTask = ({ report, closeModal }) => { + const { mutate: reportTask, isPending } = useReportTask({ + onSuccessCallback: () => { + reset(); + closeModal(); + }, + }); const maxPending = report?.workItem?.plannedWork - report?.workItem?.completedWork; const schema = z.object({ - completedTask: z - .preprocess( - (val) => (val === "" || val === null || Number.isNaN(val) ? undefined : Number(val)), + completedTask: z.preprocess( + (val) => + val === "" || val === null || Number.isNaN(val) + ? undefined + : Number(val), z .number({ required_error: "Completed Work must be a number", @@ -26,49 +34,35 @@ export const ReportTask = ({ report, closeModal, refetch }) => { message: `Completed task cannot exceed total pending tasks: ${maxPending}`, }) ), - comment: z.string().min(1, "Comment cannot be empty"), -}); + comment: z.string().min(1, "Comment cannot be empty"), + }); - const { register, handleSubmit, - formState: {errors}, - reset + formState: { errors }, + reset, } = useForm({ resolver: zodResolver(schema), defaultValues: { completedTask: 0, comment: "" }, }); - -useEffect(() => { - if (report) { - reset({ completedTask: 0, comment: "" }); // optional: customize default if needed - } -}, [report, reset]); - - - const onSubmit = async (data) => { - try { - setloading(true); - const reportData = { - ...data, - id: report?.id, - reportedDate: new Date().toISOString(), - checkList: [], - }; - - let response = await TasksRepository.reportTask(reportData); - showToast("Task Reported Successfully.", "success"); - refetch(); - reset() - setloading(false); - closeModal(); - } catch ( error ) - { - const msg = error.response.data.message || error.message || "Error Occur During Api Call" - showToast(msg, "error"); + useEffect(() => { + if (report) { + reset({ completedTask: 0, comment: "" }); } + }, [report, reset]); + + const onSubmit = (data) => { + + const reportData = { + ...data, + id: report?.id, + reportedDate: new Date().toISOString(), + checkList: [], + }; + + reportTask({ reportData, workAreaId: report?.workItem?.workArea?.id }); }; const handleClose = () => { closeModal(); @@ -76,153 +70,130 @@ useEffect(() => { }; return ( - -

Report Task

-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
-
- -
- - {errors.completedTask && ( -
- {errors.completedTask.message} -
- )} -
-
-
- -
- @@ -131,26 +141,26 @@ const CreateRole = ({ modalType, onClose }) => { )}
- -
- - +
{masterFeatures.map((feature, featureIndex) => ( - -
- - -
+
+
{feature.name}
-
{feature.featurePermissions.map((perm, permIndex) => { - const refIndex = (featureIndex * 10) + permIndex; + const refIndex = featureIndex * 10 + permIndex; return (
-
+
- (popoverRefs.current[refIndex] = el) - } + ref={(el) => (popoverRefs.current[refIndex] = el)} tabIndex="0" className="d-flex align-items-center avatar-group justify-content-center" - data-bs-toggle="popover" refIndex + data-bs-toggle="popover" + refIndex data-bs-trigger="focus" data-bs-placement="right" data-bs-html="true" @@ -182,23 +191,26 @@ const CreateRole = ({ modalType, onClose }) => { `} >   - - +
- - ) + ); })}
-

- ))} {errors.selectedPermissions && (

{errors.selectedPermissions.message}

@@ -206,33 +218,23 @@ const CreateRole = ({ modalType, onClose }) => { {!masterFeatures &&

Loading...

}
- - { - masterFeatures && ( - -
- - -
- ) - } - + {masterFeatures && ( +
+ + +
+ )} ); }; export default CreateRole; - - - - - diff --git a/src/components/master/CreateWorkCategory.jsx b/src/components/master/CreateWorkCategory.jsx index 0a7bc31b..81b2eab9 100644 --- a/src/components/master/CreateWorkCategory.jsx +++ b/src/components/master/CreateWorkCategory.jsx @@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository'; import { clearApiCacheKey } from '../../slices/apiCacheSlice'; import { getCachedData,cacheData } from '../../slices/apiDataManager'; import showToast from '../../services/toastService'; +import {useCreateWorkCategory} from '../../hooks/masterHook/useMaster'; const schema = z.object({ @@ -16,58 +17,64 @@ const schema = z.object({ const CreateWorkCategory = ({onClose}) => { - const[isLoading,setIsLoading] = useState(false) - const { - register, - handleSubmit, - formState: { errors },reset - - } = useForm({ - resolver: zodResolver(schema), - defaultValues: { - name: "", - description: "", - - }, - }); - - const onSubmit = (data) => { - setIsLoading(true) - // const result = { - // name: data.name, - // description: data.description, - // }; - - MasterRespository.createWorkCategory(data).then((resp)=>{ - setIsLoading(false) - resetForm() - const cachedData = getCachedData("Work Category"); - const updatedData = [...cachedData, resp?.data]; - cacheData("Work Category", updatedData); - showToast("Work Category Added successfully.", "success"); + const { + register, + handleSubmit, + formState: { errors }, + reset, +} = useForm({ + resolver: zodResolver(schema), + defaultValues: { + name: "", + description: "", + }, +}); - onClose() - }).catch((error)=>{ - showToast(error?.response?.data?.message, "error"); - setIsLoading(false) - }) +const [descriptionLength, setDescriptionLength] = useState(0); +const maxDescriptionLength = 255; + +const { mutate: createWorkCategory, isPending: isLoading } = useCreateWorkCategory(() => { + resetForm(); + onClose?.(); +}); + +const onSubmit = (payload) => { + createWorkCategory(payload) + }; + + // const onSubmit = (data) => { + // setIsLoading(true) + + + // MasterRespository.createWorkCategory(data).then((resp)=>{ + // setIsLoading(false) + // resetForm() + // const cachedData = getCachedData("Work Category"); + // const updatedData = [...cachedData, resp?.data]; + // cacheData("Work Category", updatedData); + // showToast("Work Category Added successfully.", "success"); + + // onClose() + // }).catch((error)=>{ + // showToast(error?.response?.data?.message, "error"); + // setIsLoading(false) + // }) - }; - const resetForm = () => { - reset({ - name: "", - description: "" - }); - setDescriptionLength(0); - } + // }; - useEffect(()=>{ - return ()=>resetForm() - },[]) - - const [descriptionLength, setDescriptionLength] = useState(0); - const maxDescriptionLength = 255; +const resetForm = () => { + reset({ + name: "", + description: "", + }); + setDescriptionLength(0); +}; + +useEffect(() => { + return () => resetForm(); +}, []); + return (<>
diff --git a/src/components/master/EditActivity.jsx b/src/components/master/EditActivity.jsx index 503bf8c0..cba8dad5 100644 --- a/src/components/master/EditActivity.jsx +++ b/src/components/master/EditActivity.jsx @@ -5,6 +5,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import {MasterRespository} from "../../repositories/MastersRepository"; import showToast from "../../services/toastService"; import {getCachedData,cacheData} from "../../slices/apiDataManager"; +import {useUpdateActivity} from "../../hooks/masterHook/useMaster"; const schema = z.object({ @@ -23,111 +24,107 @@ const schema = z.object({ const UpdateActivity = ({ activityData, onClose }) => { - const [isLoading, setIsLoading] = useState(false); + const { mutate: updateActivity, isPending: isLoading } = useUpdateActivity(() => onClose?.()); - const { - register, - handleSubmit, - control, - setValue, - reset, - setError, - clearErrors, - getValues, - formState: { errors }, - } = useForm({ - resolver: zodResolver(schema), - defaultValues: { - id:activityData.id, - activityName: activityData.activityName, - unitOfMeasurement: activityData.unitOfMeasurement, - checkLists: activityData.checkLists || [], - }, - }); +const { + register, + handleSubmit, + control, + setValue, + reset, + setError, + clearErrors, + getValues, + formState: { errors }, +} = useForm({ + resolver: zodResolver(schema), + defaultValues: { + id: activityData?.id, + activityName: activityData?.activityName, + unitOfMeasurement: activityData?.unitOfMeasurement, + checkList: activityData?.checkLists || [], + }, +}); - const { fields: checkListItems, append, remove } = useFieldArray({ - control, - name: "checkList", - }); +const { fields: checkListItems, append, remove } = useFieldArray({ + control, + name: "checkList", +}); - // Load initial data - useEffect(() => { - if (activityData) { - reset( { - id:activityData.id, - activityName: activityData.activityName, - unitOfMeasurement: activityData.unitOfMeasurement, - checkList: activityData.checkLists || [], - }); - } - }, [activityData]); +useEffect(() => { + if (activityData) { + reset({ + id: activityData.id, + activityName: activityData.activityName, + unitOfMeasurement: activityData.unitOfMeasurement, + checkList: activityData.checkLists || [], + }); + } +}, [activityData, reset]); - - const handleChecklistChange = (index, value) => { - setValue(`checkList.${index}`, value); +const addChecklistItem = () => { + const values = getValues("checkList"); + const lastIndex = checkListItems.length - 1; + + if ( + checkListItems.length > 0 && + (!values?.[lastIndex] || values[lastIndex].description.trim() === "") + ) { + setError(`checkList.${lastIndex}.description`, { + type: "manual", + message: "Please fill this checklist item before adding another.", + }); + return; + } + + clearErrors(`checkList.${lastIndex}.description`); + append({ id: null, description: "", isMandatory: false }); +}; + +const removeChecklistItem = (index) => { + remove(index); +}; + +const handleChecklistChange = (index, value) => { + setValue(`checkList.${index}`, value); +}; + +const onSubmit = (formData) => { + const payload = { ...formData, id: activityData.id }; + updateActivity({ id: activityData.id, payload }); }; - - // Submit handler - const onSubmit = async(data) => { - setIsLoading(true); +// const onSubmit = async(data) => { + // setIsLoading(true); - const Activity = {...data, id:activityData.id} - try - { - const response = await MasterRespository.updateActivity( activityData?.id, Activity ); - const updatedActivity = response.data; - const cachedData = getCachedData("Activity") + // const Activity = {...data, id:activityData.id} + // try + // { + // const response = await MasterRespository.updateActivity( activityData?.id, Activity ); + // const updatedActivity = response.data; + // const cachedData = getCachedData("Activity") - if (cachedData) { - const updatedActivities = cachedData.map((activity) => - activity.id === updatedActivity.id ? { ...activity, ...updatedActivity } : activity - ); + // if (cachedData) { + // const updatedActivities = cachedData.map((activity) => + // activity.id === updatedActivity.id ? { ...activity, ...updatedActivity } : activity + // ); - cacheData( "Activity", updatedActivities ); - onClose() - } - setIsLoading( false ) - showToast("Activity Successfully Updated", "success"); - } catch ( err ) - { - setIsLoading( false ) + // cacheData( "Activity", updatedActivities ); + // onClose() + // } + // setIsLoading( false ) + // showToast("Activity Successfully Updated", "success"); + // } catch ( err ) + // { + // setIsLoading( false ) - showToast("error.message", "error"); - } - }; + // showToast("error.message", "error"); + // } + // }; - - - // Add new checklist item - const addChecklistItem = () => { - const values = getValues("checkList"); - const lastIndex = checkListItems.length - 1; - - if ( - checkListItems.length > 0 && - (!values?.[lastIndex] || values[lastIndex].description.trim() === "") - ) { - setError(`checkList.${lastIndex}.description`, { - type: "manual", - message: "Please fill this checklist item before adding another.", - }); - return; - } - - clearErrors(`checkList.${lastIndex}.description`); - append({ id: null, description: "", isMandatory: false }); - }; - - const removeChecklistItem = (index) => { - remove(index); - }; - - - // for tooltip - useEffect(() => { - const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]')); - tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el)); - }, []); +useEffect(() => { + const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]')); + tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el)); +}, []); return ( @@ -232,7 +229,7 @@ const UpdateActivity = ({ activityData, onClose }) => { className="btn btn-xs btn-primary mt-2" onClick={addChecklistItem} > - @@ -256,4 +253,4 @@ const UpdateActivity = ({ activityData, onClose }) => { ); }; -export default UpdateActivity; +export default UpdateActivity; \ No newline at end of file diff --git a/src/components/master/EditContactCategory.jsx b/src/components/master/EditContactCategory.jsx index 331802d6..f8a403ae 100644 --- a/src/components/master/EditContactCategory.jsx +++ b/src/components/master/EditContactCategory.jsx @@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository'; import { clearApiCacheKey } from '../../slices/apiCacheSlice'; import { getCachedData,cacheData } from '../../slices/apiDataManager'; import showToast from '../../services/toastService'; +import {useUpdateContactCategory} from '../../hooks/masterHook/useMaster'; const schema = z.object({ @@ -15,65 +16,72 @@ const schema = z.object({ }); const EditContactCategory= ({data,onClose}) => { +const { + register, + handleSubmit, + formState: { errors }, + reset, +} = useForm({ + resolver: zodResolver(schema), + defaultValues: { + name: data?.name || "", + description: data?.description || "", + }, +}); - const[isLoading,setIsLoading] = useState(false) - const { - register, - handleSubmit, - formState: { errors },reset - - } = useForm({ - resolver: zodResolver(schema), - defaultValues: { - name: data?.name || "", - description:data?.description || "", - - }, - }); - - const onSubmit = (formdata) => { - setIsLoading(true) - const result = { - id:data?.id, - name: formdata?.name, - description: formdata.description, - }; +const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0); +const maxDescriptionLength = 255; + +const { mutate: updateContactCategory, isPending: isLoading } = useUpdateContactCategory(() => onClose?.()); + +const onSubmit = (formData) => { + const payload = { + id: data?.id, + name: formData.name, + description: formData.description, + }; + + updateContactCategory({id:data?.id,payload}); + }; + // const onSubmit = (formdata) => { + // setIsLoading(true) + // const result = { + // id:data?.id, + // name: formdata?.name, + // description: formdata.description, + // }; - MasterRespository.updateContactCategory(data?.id,result).then((resp)=>{ - setIsLoading(false) - showToast("Contact Category Updated successfully.", "success"); - const cachedData = getCachedData("Contact Category"); - if (cachedData) { + // MasterRespository.updateContactCategory(data?.id,result).then((resp)=>{ + // setIsLoading(false) + // showToast("Contact Category Updated successfully.", "success"); + // const cachedData = getCachedData("Contact Category"); + // if (cachedData) { - const updatedData = cachedData.map((category) => - category.id === data?.id ? { ...category, ...resp.data } : category - ); - cacheData("Contact Category", updatedData); - } + // const updatedData = cachedData.map((category) => + // category.id === data?.id ? { ...category, ...resp.data } : category + // ); + // cacheData("Contact Category", updatedData); + // } - onClose() - }).catch((error)=>{ - showToast(error?.response?.data?.message, "error") - setIsLoading(false) - }) + // onClose() + // }).catch((error)=>{ + // showToast(error?.response?.data?.message, "error") + // setIsLoading(false) + // }) - }; - const resetForm = () => { - reset({ - name: "", - description: "" - }); - setDescriptionLength(0); - } + // }; - useEffect(()=>{ - return ()=>resetForm() - },[]) - - const [descriptionLength, setDescriptionLength] = useState(0); - const maxDescriptionLength = 255; +const resetForm = () => { + reset({ name: "", description: "" }); + setDescriptionLength(0); +}; + +useEffect(() => { + return () => resetForm(); +}, []); + return (<>
diff --git a/src/components/master/EditContactTag.jsx b/src/components/master/EditContactTag.jsx index 1c0f71d1..70ab0794 100644 --- a/src/components/master/EditContactTag.jsx +++ b/src/components/master/EditContactTag.jsx @@ -6,6 +6,7 @@ import { MasterRespository } from '../../repositories/MastersRepository'; import { clearApiCacheKey } from '../../slices/apiCacheSlice'; import { getCachedData,cacheData } from '../../slices/apiDataManager'; import showToast from '../../services/toastService'; +import {useUpdateContactTag} from '../../hooks/masterHook/useMaster'; const schema = z.object({ @@ -15,65 +16,72 @@ const schema = z.object({ }); const EditContactTag= ({data,onClose}) => { +const { + register, + handleSubmit, + formState: { errors }, + reset +} = useForm({ + resolver: zodResolver(schema), + defaultValues: { + name: data?.name || "", + description: data?.description || "", + }, +}); - const[isLoading,setIsLoading] = useState(false) - const { - register, - handleSubmit, - formState: { errors },reset - - } = useForm({ - resolver: zodResolver(schema), - defaultValues: { - name: data?.name || "", - description:data?.description || "", - - }, - }); - - const onSubmit = (formdata) => { - setIsLoading(true) - const result = { - id:data?.id, - name: formdata?.name, - description: formdata.description, - }; +const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0); +const maxDescriptionLength = 255; + +const { mutate: updateContactTag, isPending: isLoading } = useUpdateContactTag(() => onClose?.()); + +const onSubmit = (formData) => { + const payload = { + id: data?.id, + name: formData.name, + description: formData.description, + }; + debugger + updateContactTag({ id: data?.id, payload} ); + } + // const onSubmit = (formdata) => { + // setIsLoading(true) + // const result = { + // id:data?.id, + // name: formdata?.name, + // description: formdata.description, + // }; - MasterRespository.updateContactTag(data?.id,result).then((resp)=>{ - setIsLoading(false) - showToast("Contact Tag Updated successfully.", "success"); - const cachedData = getCachedData("Contact Tag"); - if (cachedData) { + // MasterRespository.updateContactTag(data?.id,result).then((resp)=>{ + // setIsLoading(false) + // showToast("Contact Tag Updated successfully.", "success"); + // const cachedData = getCachedData("Contact Tag"); + // if (cachedData) { - const updatedData = cachedData.map((category) => - category.id === data?.id ? { ...category, ...resp.data } : category - ); - cacheData("Contact Tag", updatedData); - } + // const updatedData = cachedData.map((category) => + // category.id === data?.id ? { ...category, ...resp.data } : category + // ); + // cacheData("Contact Tag", updatedData); + // } - onClose() - }).catch((error)=>{ - showToast(error?.response?.data?.message, "error") - setIsLoading(false) - }) + // onClose() + // }).catch((error)=>{ + // showToast(error?.response?.data?.message, "error") + // setIsLoading(false) + // }) - }; - const resetForm = () => { - reset({ - name: "", - description: "" - }); - setDescriptionLength(0); - } + // }; - useEffect(()=>{ - return ()=>resetForm() - },[]) - - const [descriptionLength, setDescriptionLength] = useState(0); - const maxDescriptionLength = 255; +const resetForm = () => { + reset({ name: "", description: "" }); + setDescriptionLength(0); +}; + +useEffect(() => { + return () => resetForm(); +}, []); + return (<>
diff --git a/src/components/master/EditJobRole.jsx b/src/components/master/EditJobRole.jsx index 93d9ce79..c10cd457 100644 --- a/src/components/master/EditJobRole.jsx +++ b/src/components/master/EditJobRole.jsx @@ -5,6 +5,7 @@ import { zodResolver } from '@hookform/resolvers/zod'; import { MasterRespository } from '../../repositories/MastersRepository'; import { cacheData,getCachedData } from '../../slices/apiDataManager'; import showToast from '../../services/toastService'; +import {useUpdateJobRole} from '../../hooks/masterHook/useMaster'; @@ -17,63 +18,81 @@ const schema = z.object({ const EditJobRole = ({data,onClose}) => { - - const[isLoading,setIsLoading] = useState(false) - const { - register, - handleSubmit, - formState: { errors } ,reset - } = useForm({ - resolver: zodResolver(schema), - defaultValues: { - role: data?.name || "", - description:data?.description || "", - - }, - }); - - const onSubmit = (formdata) => { - setIsLoading(true) - const result = { - id:data?.id, - name: formdata?.role, - description: formdata.description, - }; - - - - MasterRespository.updateJobRole(data?.id,result).then((resp)=>{ - setIsLoading(false) - showToast("JobRole Update successfully.", "success"); - const cachedData = getCachedData("Job Role"); - if (cachedData) { - - const updatedData = cachedData.map((role) => - role.id === data?.id ? { ...role, ...resp.data } : role - ); - cacheData("Job Role", updatedData); - } - - onClose() - }).catch((error)=>{ - showToast(error.message, "error") - setIsLoading(false) - }) - - }; - - - useEffect(() => { - reset({ - role: data?.name, - description: data?.description - }); - setDescriptionLength(data?.description?.length || 0); - }, [data, reset]); - - const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0); +const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0); const maxDescriptionLength = 255; + const { + register, + handleSubmit, + formState: { errors }, + reset, + watch, + } = useForm({ + resolver: zodResolver(schema), + defaultValues: { + role: data?.name || "", + description: data?.description || "", + }, + }); + + const { mutate: updateJobRole, isPendin:isLoading } = useUpdateJobRole(() => { + onClose?.(); + }); +// const onSubmit = (formdata) => { + // setIsLoading(true) + // const result = { + // id:data?.id, + // name: formdata?.role, + // description: formdata.description, + // }; + + + + // MasterRespository.updateJobRole(data?.id,result).then((resp)=>{ + // setIsLoading(false) + // showToast("JobRole Update successfully.", "success"); + // const cachedData = getCachedData("Job Role"); + // if (cachedData) { + + // const updatedData = cachedData.map((role) => + // role.id === data?.id ? { ...role, ...resp.data } : role + // ); + // cacheData("Job Role", updatedData); + // } + + // onClose() + // }).catch((error)=>{ + // showToast(error.message, "error") + // setIsLoading(false) + // }) + + // }; + + const onSubmit = (formData) => { + updateJobRole({ + id: data?.id, + payload: { + id: data?.id, + name: formData.role, + description: formData.description, + }, + }); + }; + + useEffect(() => { + reset({ + role: data?.name || "", + description: data?.description || "", + }); + setDescriptionLength(data?.description?.length || 0); + }, [data, reset]); + + useEffect(() => { + const sub = watch((values) => { + setDescriptionLength(values.description?.length || 0); + }); + return () => sub.unsubscribe(); + }, [watch]); return (<> diff --git a/src/components/master/EditRole.jsx b/src/components/master/EditRole.jsx index d67400b1..91891b90 100644 --- a/src/components/master/EditRole.jsx +++ b/src/components/master/EditRole.jsx @@ -7,6 +7,7 @@ import { useFeatures } from "../../hooks/useMasterRole"; import { MasterRespository } from "../../repositories/MastersRepository"; import { cacheData, getCachedData } from "../../slices/apiDataManager"; import showToast from "../../services/toastService"; +import {useUpdateApplicationRole} from "../../hooks/masterHook/useMaster"; @@ -27,128 +28,149 @@ const updateSchema = z.object({ const EditMaster = ({ master, onClose }) => { - const [isLoading, setIsLoading] = useState(false) - const { masterFeatures } = useFeatures() - const popoverRefs = useRef([]); +const maxDescriptionLength = 255; +const popoverRefs = useRef([]); +const { masterFeatures } = useFeatures(); +const { mutate: updateApplicationRole, isPending: isLoading } = useUpdateApplicationRole(() => onClose?.()); - const buildDefaultPermissions = () => { - const defaults = {}; - masterFeatures.forEach((feature) => { - feature.featurePermissions.forEach((perm) => { - const existing = master?.item?.featurePermission?.find( - (p) => p.id === perm.id - ); - defaults[perm.id] = existing ? existing.isEnabled : false; - }); +const buildDefaultPermissions = () => { + const defaults = {}; + masterFeatures.forEach((feature) => { + feature.featurePermissions.forEach((perm) => { + const existing = master?.item?.featurePermission?.find(p => p.id === perm.id); + defaults[perm.id] = existing?.isEnabled || false; }); - return defaults; - - }; - - - const initialPermissions = buildDefaultPermissions(); - const { - register, - handleSubmit, - formState: { errors, dirtyFields }, - setError, reset - } = useForm({ - resolver: zodResolver(updateSchema), - defaultValues: { - role: master?.item?.role, - description: master?.item?.description, - permissions: initialPermissions, - }, }); + return defaults; +}; - const onSubmit = (data) => { - setIsLoading(true) - const existingIds = new Set( - master?.item?.featurePermission?.map((p) => p.id) - ); +const initialPermissions = buildDefaultPermissions(); +const { + register, + handleSubmit, + formState: { errors, dirtyFields }, + setError, + reset, +} = useForm({ + resolver: zodResolver(updateSchema), + defaultValues: { + role: master?.item?.role || "", + description: master?.item?.description || "", + permissions: initialPermissions, + }, +}); - const updatedPermissions = Object.entries(data.permissions) - .filter(([id, value]) => { - if (existingIds.has(id)) return true; +const [descriptionLength, setDescriptionLength] = useState(master?.item?.description?.length || 0); - return ( - value === true || - (dirtyFields.permissions && dirtyFields.permissions[id]) - ); - }) - .map(([id, value]) => ({ id, isEnabled: value })); +const onSubmit = (data) => { + const existingIds = new Set(master?.item?.featurePermission?.map(p => p.id)); - - if (updatedPermissions.length === 0) { - setError("permissions", { - type: "manual", - message: "At least one permission must be selected.", - }); - return; - } - - const updatedRole = { - id: master?.item?.id, - role: data.role, - description: data.description, - featuresPermission: updatedPermissions, - }; - MasterRespository.updateRoles(master?.item?.id, updatedRole).then((resp) => { - setIsLoading(false) - - - const cachedData = getCachedData("Application Role"); - - if (cachedData) { - - const updatedData = cachedData.map((role) => - role.id === resp.data?.id ? { ...role, ...resp.data } : role - ); - - cacheData("Application Role", updatedData); - } - showToast("Application Role Updated successfully.", "success"); - setIsLoading(false) - onClose() - }).catch((Err) => { - showToast(Err.message, "error"); - setIsLoading(false) + const updatedPermissions = Object.entries(data.permissions) + .filter(([id, value]) => { + return existingIds.has(id) || value === true || (dirtyFields.permissions?.[id]); }) + .map(([id, value]) => ({ id, isEnabled: value })); + if (updatedPermissions.length === 0) { + setError("permissions", { + type: "manual", + message: "At least one permission must be selected.", + }); + return; + } + + const payload = { + id: master?.item?.id, + role: data.role, + description: data.description, + featuresPermission: updatedPermissions, }; - useEffect(() => { - reset({ - role: master?.item?.role, - description: master?.item?.description, - permissions: initialPermissions, - }); - setDescriptionLength(master?.item?.description?.length || 0); - }, [master, reset]); + updateApplicationRole({ id: payload.id, payload }); +}; +// const onSubmit = (data) => { +// setIsLoading(true) +// const existingIds = new Set( +// master?.item?.featurePermission?.map((p) => p.id) +// ); - const [descriptionLength, setDescriptionLength] = useState(master?.item?.description?.length || 0); - const maxDescriptionLength = 255; - useEffect(() => { - popoverRefs.current.forEach((el) => { - if (el) { - new bootstrap.Popover(el, { - trigger: "focus", - placement: "right", - html: true, - content: el.getAttribute("data-bs-content"), // use inline content from attribute - }); - } - }); - }, [masterFeatures]); +// const updatedPermissions = Object.entries(data.permissions) +// .filter(([id, value]) => { +// if (existingIds.has(id)) return true; + +// return ( +// value === true || +// (dirtyFields.permissions && dirtyFields.permissions[id]) +// ); +// }) +// .map(([id, value]) => ({ id, isEnabled: value })); + + +// if (updatedPermissions.length === 0) { +// setError("permissions", { +// type: "manual", +// message: "At least one permission must be selected.", +// }); +// return; +// } + +// const updatedRole = { +// id: master?.item?.id, +// role: data.role, +// description: data.description, +// featuresPermission: updatedPermissions, +// }; +// MasterRespository.updateRoles(master?.item?.id, updatedRole).then((resp) => { +// setIsLoading(false) + + +// const cachedData = getCachedData("Application Role"); + +// if (cachedData) { + +// const updatedData = cachedData.map((role) => +// role.id === resp.data?.id ? { ...role, ...resp.data } : role +// ); + +// cacheData("Application Role", updatedData); +// } +// showToast("Application Role Updated successfully.", "success"); +// setIsLoading(false) +// onClose() +// }).catch((Err) => { +// showToast(Err.message, "error"); +// setIsLoading(false) +// }) + +// }; +useEffect(() => { + reset({ + role: master?.item?.role || "", + description: master?.item?.description || "", + permissions: buildDefaultPermissions(), + }); + setDescriptionLength(master?.item?.description?.length || 0); +}, [master, reset]); + +useEffect(() => { + popoverRefs.current.forEach((el) => { + if (el) { + new bootstrap.Popover(el, { + trigger: "focus", + placement: "right", + html: true, + content: el.getAttribute("data-bs-content"), + }); + } + }); +}, [masterFeatures]); + return ( - {/*
- -
*/}
{ - const[isLoading,setIsLoading] = useState(false) - const { - register, - handleSubmit, - formState: { errors } ,reset - } = useForm({ - resolver: zodResolver(schema), - defaultValues: { - name: data?.name || "", - description:data?.description || "", - - }, - }); - - const onSubmit = (formdata) => { - setIsLoading(true) - const result = { - id:data?.id, - name: formdata?.name, - description: formdata.description, - }; +const { + register, + handleSubmit, + formState: { errors }, + reset, +} = useForm({ + resolver: zodResolver(schema), + defaultValues: { + name: data?.name || "", + description: data?.description || "", + }, +}); + +const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0); +const maxDescriptionLength = 255; + +const { mutate: updateWorkCategory, isPending: isLoading } = useUpdateWorkCategory(() => onClose?.()); + +const onSubmit = (formdata) => { + const payload = { + id: data?.id, + name: formdata.name, + description: formdata.description, + }; + + updateWorkCategory({id:data?.id,payload}); +}; + + // const onSubmit = (formdata) => { + // setIsLoading(true) + // const result = { + // id:data?.id, + // name: formdata?.name, + // description: formdata.description, + // }; - MasterRespository.updateWorkCategory(data?.id,result).then((resp)=>{ - setIsLoading(false) - showToast("Work Category Update successfully.", "success"); - const cachedData = getCachedData("Work Category"); - if (cachedData) { + // MasterRespository.updateWorkCategory(data?.id,result).then((resp)=>{ + // setIsLoading(false) + // showToast("Work Category Update successfully.", "success"); + // const cachedData = getCachedData("Work Category"); + // if (cachedData) { - const updatedData = cachedData.map((category) => - category.id === data?.id ? { ...category, ...resp.data } : category - ); - cacheData("Work Category", updatedData); - } + // const updatedData = cachedData.map((category) => + // category.id === data?.id ? { ...category, ...resp.data } : category + // ); + // cacheData("Work Category", updatedData); + // } - onClose() - }).catch((error)=>{ - showToast(error?.response?.data?.message, "error") - setIsLoading(false) - }) + // onClose() + // }).catch((error)=>{ + // showToast(error?.response?.data?.message, "error") + // setIsLoading(false) + // }) - }; + // }; +useEffect(() => { + reset({ + name: data?.name || "", + description: data?.description || "", + }); + setDescriptionLength(data?.description?.length || 0); +}, [data, reset]); - - useEffect(() => { - reset({ - name: data?.name, - description: data?.description - }); - setDescriptionLength(data?.description?.length || 0); - }, [data, reset]); - - const [descriptionLength, setDescriptionLength] = useState(data?.description?.length || 0); - const maxDescriptionLength = 255; return (<> - {/*
- -
- */}
{ - const [ isDeleteModalOpen, setIsDeleteModalOpen ] = useState( false ); + const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const { mutate: deleteMasterItem, isPending } = useDeleteMasterItem(); - const handleSelectedMasterDeleted = async () => - { - const deleteFn = MasterRespository[modaldata.masterType]; - if (!deleteFn) { - showToast(`No delete strategy defined for master type`,"error"); - return false; + // const handleSelectedMasterDeleted = async () => + // { + // debugger + // const deleteFn = MasterRespository[modaldata.masterType]; + // if (!deleteFn) { + // showToast(`No delete strategy defined for master type`,"error"); + // return false; + // } + // try + // { + // const response = await deleteFn( modaldata?.item?.id ); + // const selected_cachedData = getCachedData( modaldata?.masterType ); + // const updated_master = selected_cachedData?.filter(item => item.id !== modaldata?.item.id); + // cacheData( modaldata?.masterType, updated_master ) + + // showToast(`${modaldata?.masterType} is deleted successfully`, "success"); + // handleCloseDeleteModal() + + // } catch ( error ) + // { + // const message = error.response.data.message || error.message || "Error occured api during call" + // showToast(message, "success"); + // } + // } + + const handleSelectedMasterDeleted = () => { + if (!modaldata?.masterType || !modaldata?.item?.id) { + showToast("Missing master type or item", "error"); + return; } - try - { - const response = await deleteFn( modaldata?.item?.id ); - const selected_cachedData = getCachedData( modaldata?.masterType ); - const updated_master = selected_cachedData?.filter(item => item.id !== modaldata?.item.id); - cacheData( modaldata?.masterType, updated_master ) - - showToast(`${modaldata?.masterType} is deleted successfully`, "success"); - handleCloseDeleteModal() - - } catch ( error ) - { - const message = error.response.data.message || error.message || "Error occured api during call" - showToast(message, "success"); - } - } - + deleteMasterItem( + { + masterType: modaldata.masterType, + item: modaldata.item, + validateFn: modaldata.validateFn, // optional + }, + { + onSuccess: () => { + handleCloseDeleteModal(); + }, + } + ); + }; useEffect(() => { if (modaldata?.modalType === "delete") { @@ -55,7 +75,7 @@ const MasterModal = ({ modaldata, closeModal }) => { const handleCloseDeleteModal = () => { setIsDeleteModalOpen(false); - closeModal(); + closeModal(); }; if (modaldata?.modalType === "delete" && isDeleteModalOpen) { @@ -88,7 +108,9 @@ const MasterModal = ({ modaldata, closeModal }) => { >
{
-
{ `${modaldata?.modalType} `}
- -
+
{`${modaldata?.modalType} `}
+ +
{modaldata.modalType === "Application Role" && ( - + )} {modaldata.modalType === "Edit-Application Role" && ( @@ -122,7 +147,10 @@ const MasterModal = ({ modaldata, closeModal }) => { )} {modaldata.modalType === "Edit-Activity" && ( - + )} {modaldata.modalType === "Work Category" && ( @@ -133,10 +161,10 @@ const MasterModal = ({ modaldata, closeModal }) => { {modaldata.modalType === "Contact Category" && ( )} - {modaldata.modalType === "Edit-Contact Category" && ( + {modaldata.modalType === "Edit-Contact Category" && ( )} - {modaldata.modalType === "Contact Tag" && ( + {modaldata.modalType === "Contact Tag" && ( )} {modaldata.modalType === "Edit-Contact Tag" && ( diff --git a/src/hooks/masterHook/useMaster.js b/src/hooks/masterHook/useMaster.js index a5c43a51..20caff62 100644 --- a/src/hooks/masterHook/useMaster.js +++ b/src/hooks/masterHook/useMaster.js @@ -1,7 +1,9 @@ -import {useState,useEffect} from "react" +import {useState,useEffect, useCallback} from "react" import { MasterRespository } from "../../repositories/MastersRepository"; import { cacheData,getCachedData } from "../../slices/apiDataManager"; import { useSelector } from "react-redux"; +import {useMutation, useQueries, useQuery, useQueryClient} from "@tanstack/react-query"; +import showToast from "../../services/toastService"; @@ -9,214 +11,687 @@ import { useSelector } from "react-redux"; -export const useFeatures = () => - useMasterData("masterFeatures", MasterRespository.getFeatures); -export const useMasterRole = () => - useMasterData("masterRole", MasterRespository.getRoles); +// const useMaster = () => { - -const useMaster = (isMa) => { - - const selectedMaster = useSelector((store)=>store.localVariables.selectedMaster); - const [data, setData] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(""); - useEffect(() => { - const fetchData = async () => { - if (!selectedMaster) return; - setLoading(true); - try { - const cachedData = getCachedData(selectedMaster); - if (cachedData) { +// const selectedMaster = useSelector((store)=>store.localVariables.selectedMaster); +// const [data, setData] = useState([]); +// const [loading, setLoading] = useState(true); +// const [error, setError] = useState(""); +// useEffect(() => { +// const fetchData = async () => { +// if (!selectedMaster) return; +// setLoading(true); +// try { +// const cachedData = getCachedData(selectedMaster); +// if (cachedData) { - setData(cachedData); +// setData(cachedData); - } else { - let response; - switch (selectedMaster) { - case "Application Role": - response = await MasterRespository.getRoles(); - response = response.data; - break; - case "Job Role": - response = await MasterRespository.getJobRole(); - response = response.data - break; - case "Activity": - response = await MasterRespository.getActivites(); - response = response.data - break; - case "Work Category": - response = await MasterRespository.getWorkCategory(); - response = response.data - break; - case "Contact Category": - response = await MasterRespository.getContactCategory(); - response = response.data - break; - case "Contact Tag": - response = await MasterRespository.getContactTag(); - response = response.data - break; - case "Status": - response = [{description: null,featurePermission: null,id: "02dd4761-363c-49ed-8851-3d2489a3e98d",status:"status 1"},{description: null,featurePermission: null,id: "03dy9761-363c-49ed-8851-3d2489a3e98d",status:"status 2"},{description: null,featurePermission: null,id: "03dy7761-263c-49ed-8851-3d2489a3e98d",status:"Status 3"}]; - break; - default: - response = []; - } +// } else { +// let response; +// switch (selectedMaster) { +// case "Application Role": +// response = await MasterRespository.getRoles(); +// response = response.data; +// break; +// case "Job Role": +// response = await MasterRespository.getJobRole(); +// response = response.data +// break; +// case "Activity": +// response = await MasterRespository.getActivites(); +// response = response.data +// break; +// case "Work Category": +// response = await MasterRespository.getWorkCategory(); +// response = response.data +// break; +// case "Contact Category": +// response = await MasterRespository.getContactCategory(); +// response = response.data +// break; +// case "Contact Tag": +// response = await MasterRespository.getContactTag(); +// response = response.data +// break; +// case "Status": +// response = [{description: null,featurePermission: null,id: "02dd4761-363c-49ed-8851-3d2489a3e98d",status:"status 1"},{description: null,featurePermission: null,id: "03dy9761-363c-49ed-8851-3d2489a3e98d",status:"status 2"},{description: null,featurePermission: null,id: "03dy7761-263c-49ed-8851-3d2489a3e98d",status:"Status 3"}]; +// break; +// default: +// response = []; +// } - if (response) { - setData(response); - cacheData(selectedMaster, response); - } - } - } catch (err) { - setError("Failed to fetch data."); - } finally { - setLoading(false); - } - }; +// if (response) { +// setData(response); +// cacheData(selectedMaster, response); +// } +// } +// } catch (err) { +// setError("Failed to fetch data."); +// } finally { +// setLoading(false); +// } +// }; - if ( selectedMaster ) - { +// if ( selectedMaster ) +// { - fetchData(); - } +// fetchData(); +// } - }, [selectedMaster]); +// }, [selectedMaster]); - return { data, loading, error } +// return { data, loading, error } +// }; + + + + +// export const useActivitiesMaster = () => +// { +// const [ activities, setActivites ] = useState( [] ) +// const [ loading, setloading ] = useState( false ); +// const [ error, setError ] = useState() +// const fetchActivities =async () => { +// setloading(true); +// try { +// const response = await MasterRespository.getActivites(); +// setActivites(response.data); +// cacheData( "ActivityMaster", response.data ); +// setloading(false); +// } catch (err) { +// setError(err); +// setloading(false); +// } +// } +// useEffect( () => +// { +// const cacheddata = getCachedData( "ActivityMaster" ); +// if ( !cacheddata ) +// { +// fetchActivities() +// } else +// { +// setActivites(cacheddata); +// } +// }, [] ) + +// return {activities,loading,error} +// } + +// export const useWorkCategoriesMaster = () => +// { +// const [ categories, setCategories ] = useState( [] ) +// const [ categoryLoading, setloading ] = useState( false ); +// const [ categoryError, setError ] = useState( "" ) + +// const fetchCategories =async () => { +// const cacheddata = getCachedData("Work Category"); + +// if (!cacheddata) { +// setloading(true); +// try { +// const response = await MasterRespository.getWorkCategory(); +// setCategories(response.data); +// cacheData("Work Category", response.data); +// } catch (err) { +// setError(err); +// console.log(err); +// } finally { +// setloading(false); +// } +// } else { +// setCategories(cacheddata); +// } +// } +// useEffect( () => +// { +// fetchCategories() +// }, [] ) + +// return {categories,categoryLoading,categoryError} +// } + +// export const useContactCategory = () => +// { +// const [ contactCategory, setContactCategory ] = useState( [] ) +// const [ loading, setLoading ] = useState( false ) +// const [ Error, setError ] = useState() + +// const fetchConatctCategory = async() => +// { +// const cache_Category = getCachedData( "Contact Category" ); +// if ( !cache_Category ) +// { +// try +// { +// let resp = await MasterRespository.getContactCategory(); +// setContactCategory( resp.data ); +// cacheData("Contact Category",resp.data) +// } catch ( error ) +// { +// setError(error) +// } +// } else +// { +// setContactCategory(cache_Category) +// } +// } + +// useEffect( () => +// { +// fetchConatctCategory() +// }, [] ) +// return { contactCategory,loading,Error} +// } +// export const useContactTags = () => { +// const [contactTags, setContactTags] = useState([]); +// const [loading, setLoading] = useState(false); +// const [error, setError] = useState(null); + +// useEffect(() => { +// const fetchContactTag = async () => { +// const cache_Tags = getCachedData("Contact Tag"); + +// if (!cache_Tags) { +// setLoading(true); +// try { +// const resp = await MasterRespository.getContactTag(); +// setContactTags(resp.data); +// cacheData("Contact Tag", resp.data); +// } catch (err) { +// setError(err); +// } finally { +// setLoading(false); +// } +// } else { +// setContactTags(cache_Tags); +// } +// }; + +// fetchContactTag(); +// }, []); + +// return { contactTags, loading, error }; +// }; + +// Separate matser------------- + +export const useActivitiesMaster = () => +{ + const { data:activities=[],isLoading:loading,error} = useQuery( { + queryKey: [ "ActivityMaster" ], + queryFn: async() => + { + const response = await MasterRespository.getActivites(); + return response.data + }, + onError: (error) => { + showToast(error?.response?.data?.message || error.message || "Failed to fetch ActivityMasters", "error"); + }, + } ) + return {activities,loading,error} +} +export const useWorkCategoriesMaster = () => { + const { + data: categories = [], + isLoading: categoryLoading, + error: categoryError, + } = useQuery({ + queryKey: ["Work Category"], + queryFn: async () => { + const response = await MasterRespository.getWorkCategory(); + return response.data; + }, + onError: (error) => { + showToast( + error?.response?.data?.message || + error.message || + "Failed to fetch work categories", + "error" + ); + }, + }); + + return { categories, categoryLoading, categoryError }; +}; + + +export const useContactCategory = () => +{ + const {data:contactCategory=[],isLoading:loading,error:Error } = useQuery( { + queryKey: [ "Contact Category" ], + queryFn: async () => + { + let resp = await MasterRespository.getContactCategory(); + return resp.data + }, + onError: (error) => { + showToast(error?.response?.data?.message || error.message || "Failed to fetch Contact categories", "error"); + }, + } ) + return { contactCategory,loading,Error} +} + +export const useContactTags = () => { + const { + data: contactTags = [], + isLoading: loading, + error, + } = useQuery({ + queryKey: ["Contact Tag"], + queryFn: async () => { + const res = await MasterRespository.getContactTag(); + return res.data; + }, + onError: (error) => { + showToast( + error?.response?.data?.message || + error.message || + "Failed to fetch Contact Tag", + "error" + ); + }, + }); + + return { contactTags, loading, error }; +}; + +// ===Application Masters Query================================================= + +const fetchMasterData = async (masterType) => { + switch (masterType) { + case "Application Role": + return (await MasterRespository.getRoles()).data; + case "Job Role": + return (await MasterRespository.getJobRole()).data; + case "Activity": + return (await MasterRespository.getActivites()).data; + case "Work Category": + return (await MasterRespository.getWorkCategory()).data; + case "Contact Category": + return (await MasterRespository.getContactCategory()).data; + case "Contact Tag": + return (await MasterRespository.getContactTag()).data; + case "Status": + return [ + { + description: null, + featurePermission: null, + id: "02dd4761-363c-49ed-8851-3d2489a3e98d", + status: "status 1", + }, + { + description: null, + featurePermission: null, + id: "03dy9761-363c-49ed-8851-3d2489a3e98d", + status: "status 2", + }, + { + description: null, + featurePermission: null, + id: "03dy7761-263c-49ed-8851-3d2489a3e98d", + status: "Status 3", + }, + ]; + default: + return []; + } +}; + +const useMaster = () => { + const selectedMaster = useSelector((store) => store.localVariables.selectedMaster); + const queryFn = useCallback(() => fetchMasterData(selectedMaster), [selectedMaster]); + const { + data = [], + isLoading, + error, + } = useQuery({ + queryKey: ["masterData", selectedMaster], + queryFn, + enabled: !!selectedMaster, + staleTime: 1000 * 60 * 10, + refetchOnWindowFocus: false, + onError: (error) => { + showToast(error?.response?.data?.message || error.message || `Failed to fetch ${selectedMaster} Maseter`, "error"); + }, + }); + + return { data, loading: isLoading, error }; }; export default useMaster; -export const useActivitiesMaster = () => - { - const [ activities, setActivites ] = useState( [] ) - const [ loading, setloading ] = useState( false ); - const [ error, setError ] = useState() - const fetchActivities =async () => { - setloading(true); - try { - const response = await MasterRespository.getActivites(); - setActivites(response.data); - cacheData( "ActivityMaster", response.data ); - setloading(false); - } catch (err) { - setError(err); - setloading(false); - } - } - useEffect( () => - { - const cacheddata = getCachedData( "ActivityMaster" ); - if ( !cacheddata ) - { - fetchActivities() - } else - { - setActivites(cacheddata); - } - }, [] ) - - return {activities,loading,error} - } +// ================================Mutation==================================== - export const useWorkCategoriesMaster = () => - { - const [ categories, setCategories ] = useState( [] ) - const [ categoryLoading, setloading ] = useState( false ); - const [ categoryError, setError ] = useState( "" ) - - const fetchCategories =async () => { - const cacheddata = getCachedData("Work Category"); - - if (!cacheddata) { - setloading(true); - try { - const response = await MasterRespository.getWorkCategory(); - setCategories(response.data); - cacheData("Work Category", response.data); - } catch (err) { - setError(err); - console.log(err); - } finally { - setloading(false); - } - } else { - setCategories(cacheddata); - } - } - useEffect( () => - { - fetchCategories() - }, [] ) - - return {categories,categoryLoading,categoryError} -} - -export const useContactCategory = () => +// Job Role----------------------------------- +export const useUpdateJobRole = (onSuccessCallback, onErrorCallback) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ({ id, payload }) => { + const response = await MasterRespository.updateJobRole(id, payload); + return response.data; + }, + onSuccess: (data, variables) => { + showToast("JobRole updated successfully.", "success"); + + queryClient.invalidateQueries({ + queryKey: ["masterData", "Job Role"], + }); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + if (onErrorCallback) onErrorCallback(error); + }, + }); +}; + +export const useCreateJobRole = (onSuccessCallback) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (payload) => { + const response = await MasterRespository.createJobRole(payload); + return response.data; + }, + onSuccess: (data) => { + showToast("JobRole added successfully.", "success"); + + queryClient.invalidateQueries({queryKey:["masterData", "Job Role"]}); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; + +// Application Role------------------------------------------- + +export const useCreateApplicationRole = (onSuccessCallback) => { - const [ contactCategory, setContactCategory ] = useState( [] ) - const [ loading, setLoading ] = useState( false ) - const [ Error, setError ] = useState() - - const fetchConatctCategory = async() => - { - const cache_Category = getCachedData( "Contact Category" ); - if ( !cache_Category ) + const queryClient = useQueryClient(); + + return useMutation( { + mutationFn: async ( payload ) => { - try - { - let resp = await MasterRespository.getContactCategory(); - setContactCategory( resp.data ); - cacheData("Contact Category",resp.data) - } catch ( error ) - { - setError(error) - } - } else + const resp = await MasterRespository.createRole( payload ); + return resp.data; + }, + onSuccess: ( data ) => { - setContactCategory(cache_Category) + queryClient.invalidateQueries( {queryKey:[ "masterData", "Application Role" ]} ) + showToast( "Application Role added successfully", "success" ); + if(onSuccessCallback) onSuccessCallback(data) + }, + onError: ( error ) => + { + showToast(error.message || "Something went wrong", "error"); } - } - - useEffect( () => - { - fetchConatctCategory() - }, [] ) - return { contactCategory,loading,Error} + }) } -export const useContactTags = () => { - const [contactTags, setContactTags] = useState([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - useEffect(() => { - const fetchContactTag = async () => { - const cache_Tags = getCachedData("Contact Tag"); +export const useUpdateApplicationRole = (onSuccessCallback) => +{ + const queryClient = useQueryClient(); - if (!cache_Tags) { - setLoading(true); - try { - const resp = await MasterRespository.getContactTag(); - setContactTags(resp.data); - cacheData("Contact Tag", resp.data); - } catch (err) { - setError(err); - } finally { - setLoading(false); - } - } else { - setContactTags(cache_Tags); + return useMutation({ + mutationFn: async ( {id, payload} ) => + { + const response = await MasterRespository.updateRoles(id,payload); + return response.data; + }, + onSuccess: (data, variables) => { + + queryClient.invalidateQueries({ + queryKey: ["masterData", "Application Role"], + }); + showToast("Application Role updated successfully.", "success"); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +} + +// Activity------------------------------ +export const useCreateActivity = (onSuccessCallback) => +{ + const queryClient = useQueryClient(); + + return useMutation( { + mutationFn: async ( payload ) => + { + const resp = await MasterRespository.createActivity(payload); + return resp.data; + }, + onSuccess: ( data ) => + { + queryClient.invalidateQueries( {queryKey:[ "masterData", "Activity" ]} ) + showToast( "Activity added successfully", "success" ); + if(onSuccessCallback) onSuccessCallback(data) + }, + onError: ( error ) => + { + showToast(error.message || "Something went wrong", "error"); + } + }) +} + +export const useUpdateActivity = (onSuccessCallback) => +{ + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ( {id, payload} ) => + { + const response = await MasterRespository.updateActivity(id,payload); + return response.data; + }, + onSuccess: (data, variables) => { + + queryClient.invalidateQueries({ + queryKey: ["masterData", "Activity"], + }); + showToast("Activity updated successfully.", "success"); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +} + + +//-----Create work Category------------------------------- +export const useCreateWorkCategory = (onSuccessCallback) => +{ + const queryClient = useQueryClient(); + + return useMutation( { + mutationFn: async ( payload ) => + { + const resp = await MasterRespository.createWorkCategory(payload); + return resp.data; + }, + onSuccess: ( data ) => + { + queryClient.invalidateQueries({queryKey: [ "masterData", "Work Category" ]} ) + showToast( "Work Category added successfully", "success" ); + if(onSuccessCallback) onSuccessCallback(data) + }, + onError: ( error ) => + { + showToast(error.message || "Something went wrong", "error"); + } + }) +} + +export const useUpdateWorkCategory = (onSuccessCallback) => +{ + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ( {id, payload} ) => + { + const response = await MasterRespository.updateWorkCategory(id,payload); + return response.data; + }, + onSuccess: (data, variables) => { + + queryClient.invalidateQueries({ + queryKey: ["masterData", "Work Category"], + }); + showToast("Work Category updated successfully.", "success"); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +} + +//-- Contact Category--------------------------- + + +export const useCreateContactCategory = (onSuccessCallback) => +{ + const queryClient = useQueryClient(); + + return useMutation( { + mutationFn: async ( payload ) => + { + const resp = await MasterRespository.createContactCategory(payload); + return resp.data; + }, + onSuccess: ( data ) => + { + queryClient.invalidateQueries( {queryKey:[ "masterData", "Contact Category" ]} ) + showToast( "Contact Category added successfully", "success" ); + if(onSuccessCallback) onSuccessCallback(data) + }, + onError: ( error ) => + { + showToast(error.message || "Something went wrong", "error"); + } + }) +} + + +export const useUpdateContactCategory = (onSuccessCallback) => +{ + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ( {id, payload} ) => + { + const response = await MasterRespository.updateContactCategory(id,payload); + return response.data; + }, + onSuccess: (data, variables) => { + + queryClient.invalidateQueries({ + queryKey: ["masterData", "Contact Category"], + }); + showToast("Contact Category updated successfully.", "success"); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +} + +// ---------Contact Tag------------------- + +export const useCreateContactTag = (onSuccessCallback) => +{ + const queryClient = useQueryClient(); + + return useMutation( { + mutationFn: async ( payload ) => + { + const resp = await MasterRespository.createContactTag(payload); + return resp.data; + }, + onSuccess: ( data ) => + { + queryClient.invalidateQueries( {queryKey:[ "masterData", "Contact Tag" ]} ) + showToast( "Contact Tag added successfully", "success" ); + if(onSuccessCallback) onSuccessCallback(data) + }, + onError: ( error ) => + { + showToast(error.message || "Something went wrong", "error"); + } + }) +} + + +export const useUpdateContactTag = (onSuccessCallback) => +{ + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ( {id, payload} ) => + { + debugger + const response = await MasterRespository.updateContactTag(id,payload); + return response.data; + }, + onSuccess: (data, variables) => { + + queryClient.invalidateQueries({ + queryKey: ["masterData", "Contact Tag"], + }); + showToast("Contact Tag updated successfully.", "success"); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +} + +// -Delete Master -------- +export const useDeleteMasterItem = () => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ( {masterType, item} ) => + { + const deleteFn = MasterRespository[masterType]; + if (!deleteFn) { + throw new Error(`No delete strategy defined for master type: ${masterType}`); } - }; - fetchContactTag(); - }, []); + await deleteFn(item.id); + return { masterType }; + }, - return { contactTags, loading, error }; + onSuccess: ({ masterType }) => { + queryClient.invalidateQueries({ queryKey: ["masterData", masterType] }); + + showToast(`${masterType} deleted successfully.`, "success"); + }, + + onError: (error) => { + const message = + error?.response?.data?.message || error?.message || "Error occurred during deletion"; + showToast(message, "error"); + }, + }); }; \ No newline at end of file diff --git a/src/hooks/useEmployees.js b/src/hooks/useEmployees.js index 67c9f6b8..4839d36c 100644 --- a/src/hooks/useEmployees.js +++ b/src/hooks/useEmployees.js @@ -3,236 +3,274 @@ 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"; +import {queryClient} from "../layouts/AuthLayout"; -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); - } + + +// 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, - }); - }) - .catch((error) => { - setError("Failed to fetch data."); - }); - } else { - setEmployeeList(EmployeeByProject_Cache.data); - } - setLoading(false); - } catch (err) { - setError("Failed to fetch data."); - setLoading(false); - } + const { + data = [], + isLoading, + error, + refetch, + } = useQuery({ + queryKey: ["employeeListByProject", selectedProject], + queryFn: async () => { + const res = await EmployeeRepository.getEmployeeListByproject(selectedProject); + return res.data || res; + }, + enabled: !!selectedProject, + }); + + 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); - } - } else { - setEmployees(Employees_cache.data); - setLoading(false); - } - } else - { - const cacheKey = showInactive - ? "allInactiveEmployeeList" - : "allEmployeeList"; + const queryKey = isAllEmployees + ? ['allEmployees', showInactive] + : ['projectEmployees', projectId]; - 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 queryFn = async () => { + if (isAllEmployees) { + const res = await EmployeeRepository.getAllEmployeeList(showInactive); + return res.data; + } else { + 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, + refetch + } = 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, + refetch }; }; -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); - } - }; +// Mutation------------------------------------------------------------------ - useEffect(() => { - fetchData(); - }, [employeeId]); - return { employee, loading, error }; + +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; + const isAllEmployee = variables.IsAllEmployee; + + // Cache invalidation + queryClient.invalidateQueries( {queryKey:[ 'allEmployees'] }); + // queryClient.invalidateQueries(['employeeProfile', id]); + queryClient.invalidateQueries( {queryKey: [ 'projectEmployees' ]} ); + queryClient.removeQueries( {queryKey: [ "empListByProjectAllocated" ]} ); + + // queryClient.invalidateQueries( {queryKey:[ 'employeeListByProject']} ); + showToast( `Employee ${ id ? 'updated' : 'created' } successfully`, 'success' ); + }, + onError: (error) => { + const msg = error?.response?.data?.message || error.message || 'Something went wrong'; + showToast(msg, '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( {queryKey:[ '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, + }; }; diff --git a/src/hooks/useMasterRole.js b/src/hooks/useMasterRole.js index d0d6cd47..68e94863 100644 --- a/src/hooks/useMasterRole.js +++ b/src/hooks/useMasterRole.js @@ -1,7 +1,7 @@ import { useEffect, useState } from "react"; import { cacheData,getCachedData } from "../slices/apiDataManager"; import { MasterRespository } from "../repositories/MastersRepository"; - +import { useQuery } from "@tanstack/react-query"; export const useMasterRole =()=>{ @@ -43,40 +43,55 @@ export const useMasterRole =()=>{ return {masterRole,loading} } -export const useFeatures =()=> { - const [masterFeatures, setMasterFeatures] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(""); +// export const useFeatures =()=> { +// const [masterFeatures, setMasterFeatures] = useState([]); +// const [loading, setLoading] = useState(true); +// const [error, setError] = useState(""); - const fetchData = async () => { +// const fetchData = async () => { - try { - const features_cache = getCachedData("masterFeatures"); - if (!features_cache) { - MasterRespository.getFeatures() - .then((response) => { - setMasterFeatures(response.data); +// try { +// const features_cache = getCachedData("masterFeatures"); +// if (!features_cache) { +// MasterRespository.getFeatures() +// .then((response) => { +// setMasterFeatures(response.data); - cacheData("features", response.data); - setLoading(false) - }) - .catch((error) => { - setError("Failed to fetch data."); - }); - }else{ - if (!masterFeatures.length) setMasterFeatures(features_cache); - } - } catch (err) { - setError("Failed to fetch data."); - } finally { - setLoading(false); - } - }; +// cacheData("features", response.data); +// setLoading(false) +// }) +// .catch((error) => { +// setError("Failed to fetch data."); +// }); +// }else{ +// if (!masterFeatures.length) setMasterFeatures(features_cache); +// } +// } catch (err) { +// setError("Failed to fetch data."); +// } finally { +// setLoading(false); +// } +// }; - useEffect(()=>{ - fetchData(); - },[]) +// useEffect(()=>{ +// fetchData(); +// },[]) - return{masterFeatures,loading} -} \ No newline at end of file +// return{masterFeatures,loading} +// } + +// -----------------Query- ------------------------- +export const useFeatures = () => { + const {data=[],isLoading,error} = useQuery({ + queryKey: ["masterFeatures"], + queryFn: async () => { + const response = await MasterRespository.getFeatures(); + return response.data; + }, + + } ); + return { + masterFeatures:data,loading:isLoading,error + } +}; \ No newline at end of file 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; diff --git a/src/hooks/useProfile.js b/src/hooks/useProfile.js index c8eeee8c..d9efefd1 100644 --- a/src/hooks/useProfile.js +++ b/src/hooks/useProfile.js @@ -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(""); +// 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 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); - } - } +// const validation = () => { +// if (!hasFetched) { +// hasFetched = true; +// if (!loggedUser) { +// fetchData(); +// } else { +// setProfile(loggedUser); +// } +// } - setProfile(loggedUser); - } +// setProfile(loggedUser); +// } - useEffect(() => { - validation(); - }, [loggedUser]); +// useEffect(() => { +// validation(); +// }, [loggedUser]); - const handler = useCallback( - (data) => { - if(!getCachedData("hasReceived")){ - cacheData("hasReceived", true); - hasFetched = false; - validation(); - } - },[] - ); +// 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 queryClient = useQueryClient(); + + const { + data: profile, + error, + isLoading, + refetch, + } = useQuery({ + queryKey: ["profile"], + queryFn: async () => { + const response = await AuthRepository.profile(); + cacheProfileData(response.data); + return response.data; + }, + initialData: loggedUser || undefined, + enabled: !loggedUser, + staleTime: 10 * 60 * 1000, + }); + + 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, + }; }; diff --git a/src/hooks/useProjects.js b/src/hooks/useProjects.js index 21c8e396..2cc5ee1d 100644 --- a/src/hooks/useProjects.js +++ b/src/hooks/useProjects.js @@ -6,194 +6,538 @@ import { useDispatch, useSelector } from "react-redux"; import { setProjectId } from "../slices/localVariablesSlice"; import EmployeeList from "../components/Directory/EmployeeList"; import eventBus from "../services/eventBus"; +import {Mutation, useMutation, useQuery, useQueryClient} from "@tanstack/react-query"; +import showToast from "../services/toastService"; + +// export const useProjects = () => { +// const loggedUser = useSelector((store) => store.globalVariables.loginUser); +// const [projects, setProjects] = useState([]); +// const [loading, setLoading] = useState(true); +// const [error, setError] = useState(""); + +// const fetchData = async () => { +// const projectIds = loggedUser?.projects || []; + +// const filterProjects = (projectsList) => { +// return projectsList +// .filter((proj) => projectIds.includes(String(proj.id))) +// .sort((a, b) => a?.name?.localeCompare(b.name)); +// }; + +// const projects_cache = getCachedData("projectslist"); + +// if (!projects_cache) { +// setLoading(true); +// try { +// const response = await ProjectRepository.getProjectList(); +// const allProjects = response.data; +// const filtered = filterProjects(allProjects); +// setProjects(filtered); +// cacheData("projectslist", allProjects); +// } catch (err) { +// setError("Failed to fetch data."); +// } finally { +// setLoading(false); +// } +// } else { +// if (!projects.length) { +// const filtered = filterProjects(projects_cache); +// setProjects(filtered); +// setLoading(false); +// } +// } +// }; +// useEffect(() => { +// if (loggedUser) { +// fetchData(); +// } +// }, [loggedUser]); + +// return { projects, loading, error, refetch: fetchData }; +// }; + +// export const useEmployeesByProjectAllocated = (selectedProject) => { +// const [projectEmployees, setEmployeeList] = useState([]); +// const [loading, setLoading] = useState(true); +// const [projects, setProjects] = useState([]); + +// const fetchData = async (projectid) => { +// try { +// let EmployeeByProject_Cache = getCachedData("empListByProjectAllocated"); +// if ( +// !EmployeeByProject_Cache || +// !EmployeeByProject_Cache.projectId === projectid +// ) { +// let response = await ProjectRepository.getProjectAllocation(projectid); +// setEmployeeList(response.data); +// cacheData("empListByProjectAllocated", { +// data: response.data, +// projectId: projectid, +// }); +// setLoading(false); +// } else { +// setEmployeeList(EmployeeByProject_Cache.data); +// setLoading(false); +// } +// } catch (err) { +// setError("Failed to fetch data."); +// setLoading(false); +// } +// }; + +// useEffect(() => { +// if (selectedProject) { +// fetchData(selectedProject); +// } +// }, [selectedProject]); + +// return { projectEmployees, loading, projects }; +// }; + +// export const useProjectDetails = (projectId) => { +// const { profile } = useProfile(); +// const [projects_Details, setProject_Details] = useState(null); +// const [loading, setLoading] = useState(true); +// const [error, setError] = useState(""); + +// const fetchData = async () => { +// setLoading(true); + +// const project_cache = getCachedData("projectInfo"); +// if (!project_cache || project_cache?.projectId != projectId) { +// ProjectRepository.getProjectByprojectId(projectId) +// .then((response) => { +// setProject_Details(response.data); +// cacheData("projectInfo", { +// projectId: projectId, +// data: response.data, +// }); +// setLoading(false); +// }) +// .catch((error) => { +// console.error(error); +// setError("Failed to fetch data."); +// setLoading(false); +// }); +// } else { +// setProject_Details(project_cache.data); +// setLoading(false); +// } +// }; + +// useEffect(() => { +// if (profile && projectId != undefined) { +// fetchData(); +// } +// }, [projectId, profile]); + +// return { projects_Details, loading, error, refetch: fetchData }; +// }; + +// export const useProjectsByEmployee = (employeeId) => { +// const [projectList, setProjectList] = useState([]); +// const [loading, setLoading] = useState(false); +// const [error, setError] = useState(""); + +// const fetchProjects = async (id) => { +// try { +// setLoading(true); +// setError(""); // clear previous error +// const res = await ProjectRepository.getProjectsByEmployee(id); +// setProjectList(res.data); +// cacheData("ProjectsByEmployee", { data: res.data, employeeId: id }); +// setLoading(false); +// } catch (err) { +// setError(err?.message || "Failed to fetch projects"); +// setLoading(false); +// } +// }; + +// useEffect(() => { +// if (!employeeId) return; + +// const cache_project = getCachedData("ProjectsByEmployee"); + +// if (!cache_project?.data || cache_project?.employeeId !== employeeId) { +// fetchProjects(employeeId); +// } else { +// setProjectList(cache_project.data); +// } +// }, [employeeId]); + +// return { +// projectList, +// loading, +// error, +// refetch: fetchProjects, +// }; +// }; + +// export const useProjectName = () => { +// const [loading, setLoading] = useState(true); +// const [projectNames, setProjectName] = useState([]); +// const [Error, setError] = useState(); +// const dispatch = useDispatch(); + +// const fetchData = async () => { +// try { +// let response = await ProjectRepository.projectNameList(); +// setProjectName(response.data); +// cacheData("basicProjectNameList", response.data); +// setLoading(false); +// if(response.data.length === 1){ +// dispatch(setProjectId(response.data[0]?.id)); +// } +// } catch (err) { +// setError("Failed to fetch data."); +// setLoading(false); +// } +// }; +// useEffect(() => { +// fetchData(); +// }, []); + +// return { projectNames, loading, Error, fetchData }; +// }; + +// ------------------------------Query------------------- export const useProjects = () => { const loggedUser = useSelector((store) => store.globalVariables.loginUser); - const [projects, setProjects] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(""); - const fetchData = async () => { - const projectIds = loggedUser?.projects || []; - - const filterProjects = (projectsList) => { - return projectsList - .filter((proj) => projectIds.includes(String(proj.id))) - .sort((a, b) => a?.name?.localeCompare(b.name)); - }; - - const projects_cache = getCachedData("projectslist"); - - if (!projects_cache) { - setLoading(true); - try { - const response = await ProjectRepository.getProjectList(); - const allProjects = response.data; - const filtered = filterProjects(allProjects); - setProjects(filtered); - cacheData("projectslist", allProjects); - } catch (err) { - setError("Failed to fetch data."); - } finally { - setLoading(false); - } - } else { - if (!projects.length) { - const filtered = filterProjects(projects_cache); - setProjects(filtered); - setLoading(false); - } - } - }; - useEffect(() => { - if (loggedUser) { - fetchData(); - } - }, [loggedUser]); - - return { projects, loading, error, refetch: fetchData }; -}; - -export const useEmployeesByProjectAllocated = (selectedProject) => { - const [projectEmployees, setEmployeeList] = useState([]); - const [loading, setLoading] = useState(true); - const [projects, setProjects] = useState([]); - - const fetchData = async (projectid) => { - try { - let EmployeeByProject_Cache = getCachedData("empListByProjectAllocated"); - if ( - !EmployeeByProject_Cache || - !EmployeeByProject_Cache.projectId === projectid - ) { - let response = await ProjectRepository.getProjectAllocation(projectid); - setEmployeeList(response.data); - cacheData("empListByProjectAllocated", { - data: response.data, - projectId: projectid, - }); - setLoading(false); - } else { - setEmployeeList(EmployeeByProject_Cache.data); - setLoading(false); - } - } catch (err) { - setError("Failed to fetch data."); - setLoading(false); - } - }; - - useEffect(() => { - if (selectedProject) { - fetchData(selectedProject); - } - }, [selectedProject]); - - return { projectEmployees, loading, projects }; -}; - -export const useProjectDetails = (projectId) => { - const { profile } = useProfile(); - const [projects_Details, setProject_Details] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(""); - - const fetchData = async () => { - setLoading(true); - - const project_cache = getCachedData("projectInfo"); - if (!project_cache || project_cache?.projectId != projectId) { - ProjectRepository.getProjectByprojectId(projectId) - .then((response) => { - setProject_Details(response.data); - cacheData("projectInfo", { - projectId: projectId, - data: response.data, - }); - setLoading(false); - }) - .catch((error) => { - console.error(error); - setError("Failed to fetch data."); - setLoading(false); - }); - } else { - setProject_Details(project_cache.data); - setLoading(false); - } - }; - - useEffect(() => { - if (profile && projectId != undefined) { - fetchData(); - } - }, [projectId, profile]); - - return { projects_Details, loading, error, refetch: fetchData }; -}; - -export const useProjectsByEmployee = (employeeId) => { - const [projectList, setProjectList] = useState([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(""); - - const fetchProjects = async (id) => { - try { - setLoading(true); - setError(""); // clear previous error - const res = await ProjectRepository.getProjectsByEmployee(id); - setProjectList(res.data); - cacheData("ProjectsByEmployee", { data: res.data, employeeId: id }); - setLoading(false); - } catch (err) { - setError(err?.message || "Failed to fetch projects"); - setLoading(false); - } - }; - - useEffect(() => { - if (!employeeId) return; - - const cache_project = getCachedData("ProjectsByEmployee"); - - if (!cache_project?.data || cache_project?.employeeId !== employeeId) { - fetchProjects(employeeId); - } else { - setProjectList(cache_project.data); - } - }, [employeeId]); + const { + data: projects = [], + isLoading: loading, + error, + refetch, + } = useQuery({ + queryKey: ['ProjectsList'], + queryFn: async () => { + const response = await ProjectRepository.getProjectList(); + return response.data; + }, + enabled: !!loggedUser, + }); return { - projectList, + projects, loading, error, - refetch: fetchProjects, + refetch, }; }; -export const useProjectName = () => { - const [loading, setLoading] = useState(true); - const [projectNames, setProjectName] = useState([]); - const [Error, setError] = useState(); - const dispatch = useDispatch(); - - const fetchData = async () => { - try { - let response = await ProjectRepository.projectNameList(); - setProjectName(response.data); - cacheData("basicProjectNameList", response.data); - setLoading(false); - if(response.data.length === 1){ - dispatch(setProjectId(response.data[0]?.id)); - } - } catch (err) { - setError("Failed to fetch data."); - setLoading(false); +export const useEmployeesByProjectAllocated = (selectedProject) => +{ + const {data = [], isLoading, refetch, error} = useQuery( { + queryKey: ["empListByProjectAllocated", selectedProject ], + queryFn: async () => + { + const res = await ProjectRepository.getProjectAllocation( selectedProject ); + return res.data || res + }, + enabled: !!selectedProject, + onError: ( error ) => + { + showToast(error.message || "Error while Fetching project Allocated Employees", "error"); } - }; - useEffect(() => { - fetchData(); - }, []); + } ) + + return { + projectEmployees: data, + loading:isLoading, + error, + refetch + } +} - return { projectNames, loading, Error, fetchData }; +export const useProjectDetails = ( projectId,isAuto = true ) => +{ + const {data: projects_Details, isLoading, error, refetch} = useQuery( { + queryKey: [ "projectInfo", projectId ], + queryFn: async () => + { + const res = await ProjectRepository.getProjectByprojectId( projectId ); + return res.data || res; + }, + enabled: !!projectId && isAuto, + onError: ( error ) => + { + showToast(error.message || "Error while Fetching project Details", "error"); + } + } ) + return { projects_Details, loading:isLoading, error, refetch }; +} + +export const useProjectsByEmployee = (employeeId) => +{ + const { data:projectNameList =[],isLoading,error,refetch} = useQuery( { + queryKey: [ "ProjectsByEmployee", employeeId ], + queryFn: async () => + { + const res = await ProjectRepository.getProjectsByEmployee( employeeId ); + return res.data || res; + }, + enabled: !!employeeId, + onError: ( error ) => + { + showToast(error.message || "Error while Fetching project Employee", "error"); + } + }) + return {projectList, loading:isLoading,error,refetch } +} + +export const useProjectName = () => +{ + const {data = [],isLoading,error,refetch} = useQuery( { + queryKey: [ "basicProjectNameList" ], + queryFn: async () => + { + const res = await ProjectRepository.projectNameList(); + return res.data || res; + }, + onError: ( error ) => + { + showToast(error.message || "Error while Fetching project Name", "error"); + } + } ) + return {projectNames:data,loading:isLoading,Error:error,refetch} +} + + + +export const useProjectInfra = (projectId) => { + const { + data: projectInfra, + isLoading, + error, + } = useQuery({ + queryKey: ["ProjectInfra", projectId], + queryFn: async () => { + const res = await ProjectRepository.getProjectInfraByproject(projectId); + return res.data; + }, + enabled: !!projectId , + onError: (error) => { + showToast(error.message || "Error while fetching project infra", "error"); + }, + }); + + return { projectInfra, isLoading, error }; }; + + +export const useProjectTasks = (workAreaId,IsExpandedArea=false) => +{ + const { data:ProjectTaskList,isLoading,error } = useQuery( { + queryKey: [ "WorkItems",workAreaId ], + queryFn: async () => + { + const res = await ProjectRepository.getProjectTasksByWorkArea(workAreaId); + return res.data; + }, + enabled: !!workAreaId && !!IsExpandedArea, + onError: ( error ) => + { + showToast(error.message || "Error while Fetching project Tasks", "error"); + } + } ) + return {ProjectTaskList,isLoading,error} +} + + +// -- -------------Mutation------------------------------- + + + +export const useCreateProject = ({ onSuccessCallback }) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (newProject) => { + const res = await ProjectRepository.manageProject(newProject); + return res.data; + }, + onSuccess: (data) => { + // Invalidate the cache + queryClient.invalidateQueries( {queryKey: [ 'ProjectsList' ]} ); + queryClient.invalidateQueries({queryKey:['basicProjectNameList']}); + + // Emit event for consumers (like useProjects or others) + eventBus.emit("project", { + keyword: "Create_Project", + response: data, + }); + + showToast("Project Created successfully.", "success"); + + if (onSuccessCallback) { + onSuccessCallback(data); + } + }, + onError: (error) => { + showToast(error.message || "Error while creating project", "error"); + }, + }); +}; + + +export const useUpdateProject = ({ onSuccessCallback }) => { + const queryClient = useQueryClient(); + const { + mutate, + isPending, + isSuccess, + isError, + } = useMutation({ + mutationFn: async ( {projectId, updatedData} ) => + { + return await ProjectRepository.updateProject(projectId, updatedData); + }, + + onSuccess: ( data, variables ) => + { + const { projectId } = variables; + + queryClient.invalidateQueries({queryKey:["ProjectsList"]}); + queryClient.invalidateQueries( {queryKey: [ "projectInfo", projectId ]} ); + queryClient.invalidateQueries({queryKey:['basicProjectNameList']}); + + eventBus.emit("project", { + keyword: "Update_Project", + response: data, + }); + + showToast("Project updated successfully.", "success"); + + if (onSuccessCallback) { + onSuccessCallback(data); + } + }, + + onError: ( error ) => + { + console.log(error) + showToast(error?.message || "Error while updating project", "error"); + }, + }); + + return { + mutate, + isPending, + isSuccess, + isError, + }; +}; + + +export const useManageProjectInfra = ( {onSuccessCallback} ) => +{ + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async ( {infraObject, projectId} ) => + { + return await ProjectRepository.manageProjectInfra(infraObject); + }, + onSuccess: ( data, variables ) => + { + const { projectId } = variables; + queryClient.invalidateQueries({queryKey:["ProjectInfra", projectId]}); + if (onSuccessCallback) onSuccessCallback(data,variables); + }, + onError: (error) => { + showToast(error.message || "Failed to update Project Infra", "error"); + }, + }); +}; + + +export const useManageProjectAllocation = ({ + onSuccessCallback, + onErrorCallback, +}) => { + const queryClient = useQueryClient(); + + const { + mutate, + isPending, + isSuccess, + isError, + } = useMutation({ + mutationFn: async ( {items} ) => + { + const response = await ProjectRepository.manageProjectAllocation(items); + return response.data; + }, + onSuccess: (data, variables, context) => { + queryClient.invalidateQueries({queryKey:['empListByProjectAllocated']}); + queryClient.removeQueries({queryKey:["projectEmployees"]}) + if (variables?.added) { + showToast('Employee Assigned Successfully', 'success'); + } else { + showToast('Removed Employee Successfully', 'success'); + } + + if (onSuccessCallback) onSuccessCallback(data, context); + }, + onError: (error) => { + const message = + error?.response?.data?.message || error.message || 'Error occurred during API call'; + showToast(message, 'error'); + if (onErrorCallback) onErrorCallback(error); + }, + }); + + return { + mutate, + isPending, + isSuccess, + isError, + }; +}; + +export const useManageTask = ({onSuccessCallback}) => +{ + const queryClient = useQueryClient(); + + return useMutation( { + mutationFn: async ( payload ) => await ProjectRepository.manageProjectTasks( payload ), + onSuccess: ( data, variables ) => + { + queryClient.invalidateQueries({ queryKey: ["WorkItems"] }) + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => + { + const message = + error?.response?.data?.message || error.message || 'Error occurred during API call'; + showToast(message, 'error'); + } + + }) +} + +export const useDeleteProjectTask = (onSuccessCallback) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ( {workItemId, workAreaId} ) => + { + return await ProjectRepository.deleteProjectTask(workItemId); + }, + onSuccess: ( _, variables ) => + { + showToast("Task deleted successfully", "success"); + queryClient.invalidateQueries({queryKey:[ "WorkItems",variables.workAreaId]}); + if (onSuccessCallback) onSuccessCallback(); + }, + onError: (error) => { + showToast( + error?.response?.data?.message || error.message || "Failed to delete task", + "error" + ); + if (onSuccessCallback) onSuccessCallback(); + }, + }); +}; + diff --git a/src/hooks/useTasks.js b/src/hooks/useTasks.js index 04d7715e..1cf531c0 100644 --- a/src/hooks/useTasks.js +++ b/src/hooks/useTasks.js @@ -2,103 +2,192 @@ import { useEffect, useState } from "react"; import { TasksRepository } from "../repositories/TaskRepository"; import { cacheData, getCachedData } from "../slices/apiDataManager"; import {MasterRespository} from "../repositories/MastersRepository"; -// import {formatDate} from "../utils/dateUtils"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import showToast from "../services/toastService"; +import {useSelector} from "react-redux"; + + +// ---------Query--------------------------------- export const useTaskList = (projectId, dateFrom, toDate) => { - const [TaskList, setTaskList] = useState([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); + const enabled = !!projectId && !!dateFrom && !!toDate; - const fetchList = async (projectId, dateFrom, toDate) => { - const taskList_cached = getCachedData("taskList"); - // if (!taskList_cached || taskList_cached?.projectId !== projectId) { - try { - setLoading(true); - const resp = await TasksRepository.getTaskList( - projectId, - dateFrom, - toDate - ); - setTaskList(resp.data); - cacheData("taskList", { projectId: projectId, data: resp.data }); - setLoading(false); - } catch (err) { - setLoading(false); - setError(err); - } - // } else { - // setTaskList(taskList_cached.data); - // } - }; - useEffect( () => - { + const { + data: TaskList = [], + isLoading: loading, + error, + refetch, + } = useQuery({ + queryKey: ["taskList", projectId, dateFrom, toDate], + queryFn: async () => { + const response = await TasksRepository.getTaskList( + projectId, + dateFrom, + toDate + ); + return response.data; + }, + enabled, + + }); - if (projectId && dateFrom && toDate) { - fetchList(projectId, dateFrom, toDate); - } - - }, [projectId, dateFrom, toDate]); + return { TaskList, loading, error, refetch }; +}; - return { TaskList, loading, error, refetch:fetchList}; +export const useTaskById = (TaskId) => { + const { + data: Task = null, + isLoading: loading, + error, + refetch, + } = useQuery({ + queryKey: ["taskDetails", TaskId], + queryFn: async () => { + const res = await TasksRepository.getTaskById(TaskId); + return res.data; + }, + enabled: !!TaskId, + }); + + return { Task, loading, error, refetch }; +}; + +// export const useActivities = () => { +// return useQuery({ +// queryKey: ["activitiesMaster"], +// queryFn: async () => { +// const response = await ActivityRepository.getActivities(); +// return response.data; +// }, + +// }); +// }; + +export const useAuditStatus = () => { + const { + data: status = [], + isLoading: loading, + error, + refetch, + } = useQuery({ + queryKey: ["AuditStatus"], + queryFn: async () => { + const res = await MasterRespository.getAuditStatus(); + return res.data; + }, + + }); + + return { status, loading, error, refetch }; }; -export const useTaskById = (TaskId) => +// -----------------------Mutation------------------------ +const toDate = new Date().toISOString().split('T')[0]; +const dateFrom = new Date(Date.now() - 6 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; + + + +export const useReportTask = ( {onSuccessCallback, onErrorCallback} = {} ) => { - const [Task, setTask] = useState([]); - const [loading, setLoading] = useState(false); - const [ error, setError ] = useState( null ); - - - - const fetchTask = async(TaskId) => - { - try + const queryClient = useQueryClient(); + const { + mutate, + isPending, + isSuccess, + isError, + error, + } = useMutation({ + mutationFn: async ( {reportData,workAreaId} ) => { - let res = await TasksRepository.getTaskById( TaskId ); - setTask( res.data ); - - } catch ( error ) + debugger + return await TasksRepository.reportTask(reportData); + }, + onSuccess: ( data, variables ) => { - setError(err) - } - } - useEffect( () => - { - if ( TaskId ) - { - fetchTask(TaskId) - } - }, [ TaskId ] ) - return { Task,loading} -} + const {workAreaId} = variables; + queryClient.invalidateQueries( {queryKey: [ "taskList" ]} ); + queryClient.invalidateQueries( {queryKey: [ "WorkItems", workAreaId ]} ); + queryClient.invalidateQueries( {queryKey: [ 'ProjectsList' ]} ); + showToast( "Task Reported Successfully.", "success" ); + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + const msg = + error?.response?.data?.message || error.message || "Error occurred during API call"; + showToast( msg, "error" ); + }, + }); -export const useAuditStatus = () => + return { + mutate, + isPending, + isSuccess, + isError, + error, + }; +}; + +export const useSubmitTaskComment = ({ actionAllow, onSuccessCallback }) => { + const queryClient = useQueryClient(); + const { mutate, isPending } = useMutation({ + mutationFn: async ({ data, commentsData }) => { + const payload = { + ...data, + [actionAllow ? "id" : "taskAllocationId"]: commentsData?.id, + ...(actionAllow ? {} : { commentDate: new Date().toISOString() }), + }; + + const response = actionAllow + ? await TasksRepository.auditTask(payload) + : await TasksRepository.taskComments(payload); + + return response.data; + }, + + onSuccess: ( data,variables ) => + { + + const workAreaId = variables?.commentsData?.workItem?.workArea?.id; + queryClient.invalidateQueries({ queryKey: ["taskList"] }); + if (actionAllow) { + showToast( "Review submitted successfully.", "success" ); + + } else + { + showToast("Comment sent successfully.", "success"); + } + + onSuccessCallback?.(data); + }, + + onError: (error) => { + const msg = error?.response?.data?.message || error.message || "Error during API call"; + showToast(msg, "error"); + }, + }); + + return { submitComment: mutate, isPending }; +}; + +export const useCreateTask = ( {onSuccessCallback, onErrorCallback} = {} ) => { - const [ status, setStatus ] = useState( [] ); - const [ error, setError ] = useState( '' ); - const [ loading, setLoading ] = useState( false ) - - const fetchStatus = async() => - { - try + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: async ({payload,workAreaId}) => { + return await TasksRepository.assignTask(payload); + }, + onSuccess: ( _, variables ) => { - const res = await MasterRespository.getAuditStatus() - setStatus( res.data ) - cacheData("AuditStatus",res.data) - } catch ( err ) + queryClient.invalidateQueries( {queryKey: [ "taskList" ]} ); + queryClient.invalidateQueries( {queryKey: [ "WorkItems", variables?.workAreaId ]} ); + showToast( "Task Assigned Successfully.", "success" ); + if (onSuccessCallback) onSuccessCallback(variables); + }, + onError: ( error ) => { - setError(err) - } - } -useEffect(() => { - const cache_status = getCachedData('AuditStatus'); - if (cache_status) { - setStatus(cache_status); - } else { - fetchStatus(); - } -}, []); - - return {status,error,loading} -} \ No newline at end of file + showToast("Something went wrong. Please try again.", "error"); + if (onErrorCallback) onErrorCallback(error); + }, + }); +}; \ No newline at end of file diff --git a/src/layouts/AuthLayout.jsx b/src/layouts/AuthLayout.jsx index 2b2ec80f..2640081b 100644 --- a/src/layouts/AuthLayout.jsx +++ b/src/layouts/AuthLayout.jsx @@ -1,5 +1,17 @@ import React from "react"; -import { Outlet } from "react-router-dom"; +import {Outlet} from "react-router-dom"; +import {QueryClient} from '@tanstack/react-query'; + +export const queryClient = new QueryClient({ + defaultOptions: { + queries: { + staleTime: 5 * 60 * 1000, // 5 min: data considered fresh + refetchOnWindowFocus: true, // refresh on tab switch + refetchOnReconnect: true, // re-fetch if network was lost + retry: false, + }, + }, +}); const AuthLayout = () => { return ( diff --git a/src/pages/Activities/DailyTask.jsx b/src/pages/Activities/DailyTask.jsx index 4d2b476a..dba18d18 100644 --- a/src/pages/Activities/DailyTask.jsx +++ b/src/pages/Activities/DailyTask.jsx @@ -9,10 +9,11 @@ import ReportTaskComments from "../../components/Activities/ReportTaskComments"; import DateRangePicker from "../../components/common/DateRangePicker"; import { useSearchParams } from "react-router-dom"; import moment from "moment"; -import FilterIcon from "../../components/common/FilterIcon"; // Import the FilterIcon component +import FilterIcon from "../../components/common/FilterIcon"; import GlobalModel from "../../components/common/GlobalModel"; import AssignTask from "../../components/Project/AssignTask"; import SubTask from "../../components/Activities/SubTask"; +import {formatNumber} from "../../utils/dateUtils"; const DailyTask = () => { const [searchParams] = useSearchParams(); @@ -20,14 +21,7 @@ const DailyTask = () => { const selectedProject = useSelector( (store) => store.localVariables.projectId ); - const { - projects, - loading: project_loading, - error: projects_Error, - } = useProjects(); - const [initialized, setInitialized] = useState(false); - const dispatch = useDispatch(); const [filters, setFilters] = useState({ selectedBuilding: "", @@ -35,23 +29,7 @@ const DailyTask = () => { selectedActivities: [], }); - useEffect(() => { - if (!project_loading && projects.length > 0 && !initialized) { - if (projectIdFromUrl) { - dispatch(setProjectId(projectIdFromUrl)); - } else if (selectedProject === 1 || selectedProject === undefined) { - dispatch(setProjectId(projects[0].id)); - } - setInitialized(true); - } - }, [ - project_loading, - projects, - projectIdFromUrl, - selectedProject, - initialized, - dispatch, - ]); + const [dateRange, setDateRange] = useState({ startDate: "", endDate: "" }); @@ -61,10 +39,11 @@ const DailyTask = () => { error: task_error, refetch, } = useTaskList( - initialized ? selectedProject : null, - initialized ? dateRange.startDate : null, - initialized ? dateRange.endDate : null - ); + selectedProject || null, + dateRange?.startDate || null, + dateRange?.endDate || null + ); + const [TaskLists, setTaskLists] = useState([]); const [dates, setDates] = useState([]); @@ -83,8 +62,8 @@ const DailyTask = () => { } if (filters.selectedFloors.length > 0) { - filteredTasks = filteredTasks.filter((task) => - filters.selectedFloors.includes( + filteredTasks = filteredTasks?.filter((task) => + filters.selectedFloors?.includes( task?.workItem?.workArea?.floor?.floorName ) ); @@ -103,9 +82,9 @@ const DailyTask = () => { } }, [ TaskList, - filters.selectedBuilding, - filters.selectedFloors, - filters.selectedActivities, + filters?.selectedBuilding, + filters?.selectedFloors, + filters?.selectedActivities, ]); useEffect(() => { @@ -150,43 +129,32 @@ const DailyTask = () => { const handlecloseModal = () => { setIsModalOpen( false ) - refetch(selectedProject, dateRange.startDate, dateRange.endDate); + // refetch(); } - const handleProjectChange = (e) => { - const newProjectId = e.target.value; - dispatch(setProjectId(newProjectId)); - setTaskLists([]); - setFilters({ - selectedBuilding: "", - selectedFloors: [], - selectedActivities: [], - }); - }; const handleCloseAction = (IsSubTask) => { if (IsSubTask) { setIsSubTaskNeeded(true); setIsModalOpenComment(false); } else { - refetch(selectedProject, dateRange.startDate, dateRange.endDate); + // refetch(); setIsModalOpenComment(false); } }; const hanleCloseSubTask = () => { setIsSubTaskNeeded(false); setComment( null ); - refetch(selectedProject, dateRange.startDate, dateRange.endDate); + // refetch(); }; + return ( <> - - {isModalOpen && } @@ -255,7 +223,7 @@ const DailyTask = () => { {/* --- Spinner when tasks are loading --- */} - {(task_loading || project_loading) && ( + {task_loading && ( {" "} @@ -272,7 +240,6 @@ const DailyTask = () => { )} {!task_loading && - !project_loading && TaskLists.length === 0 && ( @@ -337,9 +304,7 @@ const DailyTask = () => {
- {task.plannedTask || "NA"} / - {task.workItem.plannedWork - - task.workItem.completedWork} + {formatNumber(task.plannedTask)} / {formatNumber(task.workItem.plannedWork - task.workItem.completedWork)} {task.completedTask} @@ -413,7 +378,7 @@ const DailyTask = () => { } more`} > - +{task.teamMembers.length - 3} + + {task.teamMembers.length - 3}
)} diff --git a/src/pages/Activities/TaskPlannng.jsx b/src/pages/Activities/TaskPlannng.jsx index d532696e..c2b2f8da 100644 --- a/src/pages/Activities/TaskPlannng.jsx +++ b/src/pages/Activities/TaskPlannng.jsx @@ -1,110 +1,9 @@ -import React, { useState, useEffect } from "react"; -import "../../components/Project/ProjectInfra.css"; - -import ProjectRepository from "../../repositories/ProjectRepository"; +import React from "react"; import Breadcrumb from "../../components/common/Breadcrumb"; import InfraPlanning from "../../components/Activities/InfraPlanning"; -import { cacheData, getCachedData } from "../../slices/apiDataManager"; -import { useProfile } from "../../hooks/useProfile"; -import { useDispatch, useSelector } from "react-redux"; -import { useProjectDetails, useProjects } from "../../hooks/useProjects"; -import { setProjectId } from "../../slices/localVariablesSlice"; -import showToast from "../../services/toastService"; + const TaskPlannng = () => { - const { profile } = useProfile(); - const { - projects, - loading: project_listLoader, - error: projects_error, - } = useProjects(); - const dispatch = useDispatch(); - const selectedProject = useSelector( - (store) => store.localVariables.projectId - ); - - - const [project, setProject] = useState(null); - const [projectDetails, setProjectDetails] = useState(null); - const [activities, setActivities] = useState(null); - - const [loading, setLoading] = useState(true); - const [error, setError] = useState(""); - - const fetchActivities = async () => { - try { - const activities_cache = getCachedData("activitiesMaster"); - - if (!activities_cache) { - ActivityeRepository.getActivities() - .then((response) => { - setActivities(response.data); - cacheData("activitiesMaster", response.data); - }) - .catch((error) => { - setError("Failed to fetch data."); - }); - } else { - setActivities(activities_cache); - } - } catch (err) { - setError("Failed to fetch activities."); - } finally { - // setLoading(false); - } - }; - - const fetchData = async () => { - try { - const project_cache = getCachedData("projectInfo"); - if (!project_cache || !project_cache.projectId == selectedProject) { - ProjectRepository.getProjectByprojectId(selectedProject) - .then((response) => { - setProjectDetails(response); - setProject(response); - cacheData("projectInfo", { - data: response.data, - projectId: selectedProject, - }); - }) - .catch((error) => { - const message = - error.response?.data?.message || - error.message || - "An unexpected error occurred"; - showToast( message, "error" ); - }); - } else { - setProjectDetails(project_cache); - } - } catch (err) { - setError( "Failed to fetch data." ); - const message = - error.response?.data?.message || - error.message || - "An unexpected error occurred"; - showToast( message, "error" ); - } finally { - setLoading(false); - } - }; - - const [activePill, setActivePill] = useState("profile"); - - const handlePillClick = (pillKey) => { - setActivePill(pillKey); - }; - - const handleDataChange = (data) => { - fetchData(); - }; - - useEffect(() => { - if (projects.length != 0 && selectedProject) { - fetchData(); - fetchActivities(); - } - }, [selectedProject]); return ( <> @@ -115,17 +14,7 @@ const TaskPlannng = () => { { label: "Daily Task Planning" } ]} > - {project_listLoader &&

Loading..

} - {!project_listLoader && projects.length === 0 && ( -

No Project Found.

- )} - {!project_listLoader && projects.length > 0 && ( - - )} +
); diff --git a/src/pages/employee/EmployeeList.jsx b/src/pages/employee/EmployeeList.jsx index 8066a2e2..ef470979 100644 --- a/src/pages/employee/EmployeeList.jsx +++ b/src/pages/employee/EmployeeList.jsx @@ -5,10 +5,10 @@ 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 { useProjects } from "../../hooks/useProjects"; // Keep if you use projects elsewhere -import { useProfile } from "../../hooks/useProfile"; // Keep if you use profile elsewhere -import { hasUserPermission } from "../../utils/authUtils"; // Keep if you use this elsewhere +import { useEmployeesAllOrByProjectId, useSuspendEmployee } from "../../hooks/useEmployees"; +import { useProjects } from "../../hooks/useProjects"; +import { useProfile } from "../../hooks/useProfile"; +import { hasUserPermission } from "../../utils/authUtils"; import { ITEMS_PER_PAGE, MANAGE_EMPLOYEES } from "../../utils/constants"; import { clearCacheKey } from "../../slices/apiDataManager"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; @@ -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( @@ -38,14 +39,15 @@ const EmployeeList = () => { const { employees, loading, setLoading, error, recallEmployeeData } = useEmployeesAllOrByProjectId( - showAllEmployees ? null : selectedProjectId, // Use selectedProjectId here + showAllEmployees ? null : selectedProjectId, showInactive ); 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 [searchText, setSearchText] = useState(""); const [filteredData, setFilteredData] = useState([]); @@ -53,135 +55,131 @@ 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(); - /** - * Applies the search filter to a given array of employee data. - * @param {Array} data - The array of employee objects to filter. - * @param {string} text - The search text. - * @returns {Array} The filtered array. - */ + const applySearchFilter = (data, text) => { - if (!text) { - return data; - } - const lowercasedText = text.toLowerCase().trim(); // Ensure search text is trimmed and lowercase + if (!text) { + return data; + } - return data.filter((item) => { - // **IMPROVED FULL NAME CONSTRUCTION** - const firstName = item.firstName || ""; - const middleName = item.middleName || ""; - const lastName = item.lastName || ""; + const lowercasedText = text.toLowerCase().trim(); - // Join parts, then trim any excess spaces if a middle name is missing - const fullName = `${firstName} ${middleName} ${lastName}`.toLowerCase().trim().replace(/\s+/g, ' '); + return data.filter((item) => { + const firstName = item.firstName || ""; + const middleName = item.middleName || ""; + const lastName = item.lastName || ""; - const email = item.email ? item.email.toLowerCase() : ""; - const phoneNumber = item.phoneNumber ? item.phoneNumber.toLowerCase() : ""; - const jobRole = item.jobRole ? item.jobRole.toLowerCase() : ""; + const fullName = `${firstName} ${middleName} ${lastName}` + .toLowerCase() + .trim() + .replace(/\s+/g, " "); + + const email = item.email?.toLowerCase() || ""; + const phoneNumber = item.phoneNumber?.toLowerCase() || ""; + const jobRole = item.jobRole?.toLowerCase() || ""; + + return ( + fullName.includes(lowercasedText) || + email.includes(lowercasedText) || + phoneNumber.includes(lowercasedText) || + jobRole.includes(lowercasedText) + ); + }); +}; - return ( - fullName.includes(lowercasedText) || - email.includes(lowercasedText) || - phoneNumber.includes(lowercasedText) || - jobRole.includes(lowercasedText) - ); - }); - }; const handleSearch = (e) => { const value = e.target.value; setSearchText(value); setCurrentPage(1); }; +useEffect(() => { + const filtered = applySearchFilter(employeeList, searchText); + setFilteredData(filtered); +}, [searchText, employeeList]); - useEffect(() => { - setCurrentPage(1); - if (!loading && Array.isArray(employees)) { - const sorted = [...employees].sort((a, b) => { - const nameA = `${a.firstName || ""}${a.middleName || ""}${a.lastName || ""}`.toLowerCase(); - const nameB = `${b.firstName || ""}${b.middleName || ""}${b.lastName || ""}`.toLowerCase(); - return nameA?.localeCompare(nameB); - }); - setEmployeeList(sorted); - const results = applySearchFilter(sorted, searchText); - setFilteredData(results); - } else if (!loading && !employees) { - setEmployeeList([]); - setFilteredData([]); - } - }, [loading, employees, showAllEmployees, searchText, selectedProjectId]); // Add selectedProjectId to dependencies - - const displayData = filteredData; - 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 openModal = () => { + const displayData = searchText ? filteredData : employeeList; + const { currentPage, totalPages, currentItems, paginate,setCurrentPage } = usePagination( + displayData, + ITEMS_PER_PAGE + ); + const openModal = () => { setIsCreateModalOpen(true); - }; + }; + + // const closeModal = () => { + // setIsCreateModalOpen(false); + + // const modalElement = document.getElementById("managerole-modal"); + // if (modalElement && !showModal) { + // modalElement.classList.remove("show"); + // modalElement.style.display = "none"; + // document.body.classList.remove("modal-open"); + // document.querySelector(".modal-backdrop")?.remove(); + // } + // setShowModal(false); + // clearCacheKey("employeeProfile"); + // recallEmployeeData(showInactive, showAllEmployees ? null : selectedProjectId); // Use selectedProjectId here + // }; + // const handleShow = () => setShowModal(true); + // const handleClose = () => setShowModal( false ); + +useEffect(() => { + if (!loading && Array.isArray(employees)) { + const sorted = [...employees].sort((a, b) => { + const nameA = `${a.firstName || ""}${a.middleName || ""}${a.lastName || ""}`.toLowerCase(); + const nameB = `${b.firstName || ""}${b.middleName || ""}${b.lastName || ""}`.toLowerCase(); + return nameA?.localeCompare(nameB); + }); + + setEmployeeList((prevList) => { + const prevJSON = JSON.stringify(prevList); + const nextJSON = JSON.stringify(sorted); + if (prevJSON !== nextJSON) { + return sorted; + } + return prevList; + }); + + setFilteredData((prev) => { + const prevJSON = JSON.stringify(prev); + const nextJSON = JSON.stringify(sorted); + if (prevJSON !== nextJSON) { + return sorted; + } + return prev; + }); + + // set currentPage to 1 only if needed + setCurrentPage((prevPage) => (prevPage !== 1 ? 1 : prevPage)); + } +}, [loading, employees, selectedProjectId, showAllEmployees]); - const closeModal = () => { - setIsCreateModalOpen(false); - const modalElement = document.getElementById("managerole-modal"); - if (modalElement && !showModal) { - modalElement.classList.remove("show"); - modalElement.style.display = "none"; - document.body.classList.remove("modal-open"); - document.querySelector(".modal-backdrop")?.remove(); // Use optional chaining for safety - } - setShowModal(false); - clearCacheKey("employeeProfile"); - recallEmployeeData(showInactive, showAllEmployees ? null : selectedProjectId); // Use selectedProjectId here - }; - const handleShow = () => setShowModal(true); - 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"); - // Recall data based on current filter states after deletion to refresh the table - recallEmployeeData(showInactive, showAllEmployees ? null : selectedProjectId); // Use selectedProjectId here - 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); }; - useEffect(() => { - if (modelConfig !== null) { - openModal(); - } - }, [modelConfig, isCreateModalOpen]); + // useEffect(() => { + // if (modelConfig !== null) { + // openModal(); + // } + // }, [modelConfig, isCreateModalOpen]); const tableRef = useRef(null); const handleExport = (type) => { @@ -215,9 +213,6 @@ const handleAllEmployeesToggle = (e) => { setShowInactive(false); setShowAllEmployees(isChecked); - if (!isChecked) { - setSelectedProject(selectedProjectId || ""); - } }; const handleEmployeeModel = (id) => { @@ -253,34 +248,18 @@ const handleAllEmployeesToggle = (e) => { return ( <> - {isCreateModalOpen && ( - + {EmpForManageRole && ( + setEmpForManageRole( null )}> + setEmpForManageRole(null)} /> + )} - {/* {showModal && (
-
-
- -
-
-
)} */} {showModal && ( setShowModal(false)}> setShowModal(false)} + onClosed={() => setShowModal( false )} + IsAllEmployee={showAllEmployees} /> )} @@ -594,91 +573,90 @@ const handleAllEmployeesToggle = (e) => { - - {moment(item.joiningDate)?.format("DD-MMM-YYYY")} - - - {/* Assuming 'isActive' property exists to determine status */} - {item.isActive ? ( - - Active - - ) : ( - - Inactive - - )} - - {Manage_Employee && ( - -
- -
- - - {!item.isSystem && ( - <> - - - - )} -
-
+ + {moment(item.joiningDate)?.format("DD-MMM-YYYY")} - )} - - ))} + + {showInactive ? ( + + Inactive + + ) : ( + + Active + + )} + + {Manage_Employee && ( + +
+ +
+ + + {!item.isSystem && ( + <> + + + + )} +
+
+ + )} + + ))}
{/* Pagination */} - {!loading && displayData.length > itemsPerPage && ( + {!loading && displayData.length > ITEMS_PER_PAGE && (