From 6baa2896c2f336654d9401c25a14581e321bb6d5 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Mon, 15 Sep 2025 16:27:06 +0530 Subject: [PATCH 01/74] initially setup --- src/components/common/Modal.jsx | 70 ++++++++++++++ src/hooks/useOrganization.js | 0 src/pages/Organization/OrganizationModal.jsx | 0 src/pages/Organization/OrganizationPage.jsx | 0 src/slices/apiSlice/attedanceLogsSlice.js | 93 ------------------- src/slices/apiSlice/attendanceAllSlice.js | 38 -------- .../apiSlice/employeeAttendanceSlice.js | 56 ----------- 7 files changed, 70 insertions(+), 187 deletions(-) create mode 100644 src/components/common/Modal.jsx create mode 100644 src/hooks/useOrganization.js create mode 100644 src/pages/Organization/OrganizationModal.jsx create mode 100644 src/pages/Organization/OrganizationPage.jsx delete mode 100644 src/slices/apiSlice/attedanceLogsSlice.js delete mode 100644 src/slices/apiSlice/attendanceAllSlice.js delete mode 100644 src/slices/apiSlice/employeeAttendanceSlice.js diff --git a/src/components/common/Modal.jsx b/src/components/common/Modal.jsx new file mode 100644 index 00000000..67866c50 --- /dev/null +++ b/src/components/common/Modal.jsx @@ -0,0 +1,70 @@ +import XIcon from "@/assets/XIcons"; +import { useCallback } from "react"; +import Button from "./Button"; + +const Modal = ({ + isOpen, + onClose, + onSubmit, + title, + body, + footer, + actionLabel, + disabled, +}) => { + const handleClose = useCallback(() => { + if (disabled) return; + onClose(); + }, [disabled, onClose]); + + const handleSubmit = useCallback(() => { + if (disabled) return; + onSubmit(); + }, [disabled, onSubmit]); + + if (!isOpen) return null; + + return ( +
+
+
+ {/* Header */} +
+
{title}
+ +
+ + {/* Body */} +
{body}
+ + {/* Footer */} +
+
+
+
+
+ ); +}; + +export default Modal; diff --git a/src/hooks/useOrganization.js b/src/hooks/useOrganization.js new file mode 100644 index 00000000..e69de29b diff --git a/src/pages/Organization/OrganizationModal.jsx b/src/pages/Organization/OrganizationModal.jsx new file mode 100644 index 00000000..e69de29b diff --git a/src/pages/Organization/OrganizationPage.jsx b/src/pages/Organization/OrganizationPage.jsx new file mode 100644 index 00000000..e69de29b diff --git a/src/slices/apiSlice/attedanceLogsSlice.js b/src/slices/apiSlice/attedanceLogsSlice.js deleted file mode 100644 index 249d5445..00000000 --- a/src/slices/apiSlice/attedanceLogsSlice.js +++ /dev/null @@ -1,93 +0,0 @@ -import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; -import AttendanceRepository from '../../repositories/AttendanceRepository'; -import {clearCacheKey} from '../apiDataManager'; - -// Fetch attendance data -export const fetchAttendanceData = createAsyncThunk( - 'attendanceLogs/fetchAttendanceData', - async ( {projectId, fromDate, toDate}, thunkAPI ) => - { - try { - const response = await AttendanceRepository.getAttendanceFilteredByDate(projectId, fromDate, toDate); - return response?.data?.filter((log) => log.checkInTime !== null && log.activity !== 0); - } catch (error) { - return thunkAPI.rejectWithValue(error.message); - } - } -); - - -export const markAttendance = createAsyncThunk( - 'attendanceLogs/markAttendance', // Updated action type prefix - async ( formData, thunkAPI ) => - - { - try { - let newRecordAttendance = { - Id: formData.id || null, - comment: formData.description, - employeeID: formData.employeeId, - projectID: formData.projectId, - date: new Date().toISOString(), - markTime: formData.markTime, - latitude: formData.latitude.toString(), - longitude: formData.longitude.toString(), - action: formData.action, - image: null, - }; - - const response = await AttendanceRepository.markAttendance( newRecordAttendance ); - return response.data; - } catch ( error ) - { - const message = error?.response?.data?.message || error.message || "Error Occured During Api Call"; - return thunkAPI.rejectWithValue(message); - } - } -); - -// Attendance Logs Slice -const attendanceLogsSlice = createSlice({ - name: 'attendanceLogs', // Updated slice name - initialState: { - data: [], - loading: false, - error: null, - }, - reducers: { - setAttendanceData: (state, action) => { - state.data = action.payload; - }, - }, - extraReducers: (builder) => { - builder - // Fetch attendance data - .addCase(fetchAttendanceData.pending, (state) => { - state.loading = true; - }) - .addCase(fetchAttendanceData.fulfilled, (state, action) => { - state.loading = false; - state.data = action.payload; - }) - .addCase(fetchAttendanceData.rejected, (state, action) => { - state.loading = false; - state.error = action.payload; - }) - - // Mark attendance - log attenace data - .addCase(markAttendance.fulfilled, (state, action) => { - const updatedRecord = action.payload; - const index = state.data.findIndex(item => item.id === updatedRecord.id); - - if (index !== -1) { - state.data[index] = { ...state.data[index], ...updatedRecord }; - } else { - state.data.push(updatedRecord); - } - }); - - }, -}); - -export const { setAttendanceData } = attendanceLogsSlice.actions; -export default attendanceLogsSlice.reducer; diff --git a/src/slices/apiSlice/attendanceAllSlice.js b/src/slices/apiSlice/attendanceAllSlice.js deleted file mode 100644 index 1e9acdd2..00000000 --- a/src/slices/apiSlice/attendanceAllSlice.js +++ /dev/null @@ -1,38 +0,0 @@ -import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; -import AttendanceRepository from '../../repositories/AttendanceRepository'; -import {clearCacheKey} from '../apiDataManager'; - -export const markCurrentAttendance = createAsyncThunk( - 'attendanceCurrentDate/markAttendance', - async ( formData, {getState, dispatch, rejectWithValue} ) => - { - - const { projectId } = getState().localVariables - try - { - - // Create the new attendance record - const newRecordAttendance = { - Id: formData.id || null, - comment: formData.description, - employeeID: formData.employeeId, - projectId: projectId, - date: new Date().toISOString(), - markTime: formData.markTime, - latitude: formData.latitude.toString(), - longitude: formData.longitude.toString(), - action: formData.action, - image: null, - }; - - const response = await AttendanceRepository.markAttendance(newRecordAttendance); - const markedAttendance = response.data - clearCacheKey("AttendanceLogs") - return markedAttendance; - - } catch (error) { - console.error('Error marking attendance:', error); - return rejectWithValue(error.message); // Reject with error message - } - } - ); \ No newline at end of file diff --git a/src/slices/apiSlice/employeeAttendanceSlice.js b/src/slices/apiSlice/employeeAttendanceSlice.js deleted file mode 100644 index 290883c7..00000000 --- a/src/slices/apiSlice/employeeAttendanceSlice.js +++ /dev/null @@ -1,56 +0,0 @@ -import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'; -import AttendanceRepository from '../../repositories/AttendanceRepository'; -import { markAttendance } from './attedanceLogsSlice'; - -export const fetchEmployeeAttendanceData = createAsyncThunk( - 'employeeAttendance/fetchEmployeeAttendanceData', - async ( {employeeId, fromDate, toDate}, thunkAPI ) => - { - try { - const response = await AttendanceRepository.getAttendanceByEmployee( employeeId, fromDate, toDate ); - // return response?.data?.filter((log) => log.checkInTime !== null && log.activity !== 0); - return response.data - } catch (error) { - return thunkAPI.rejectWithValue(error.message); - } - } -); - - -const employeeAttendancesSlice = createSlice({ - name: 'employeeAttendance', // Updated slice name - initialState: { - data: [], - loading: false, - error: null, - }, - reducers: { - setEmployeeAttendanceData: (state, action) => { - state.data = action.payload; - }, - }, - extraReducers: (builder) => { - builder - // Fetch attendance data - .addCase(fetchEmployeeAttendanceData.pending, (state) => { - state.loading = true; - }) - .addCase(fetchEmployeeAttendanceData.fulfilled, (state, action) => { - state.loading = false; - state.data = action.payload; - }) - - - .addCase(fetchEmployeeAttendanceData.rejected, (state, action) => { - state.loading = false; - state.error = action.payload; - }) - - - - - }, - }); - - export const { setEmployeeAttendanceData } = employeeAttendancesSlice.actions; - export default employeeAttendancesSlice.reducer; \ No newline at end of file -- 2.43.0 From e0c7eee1fd65e4795906d0e23bf370dcb9a84e82 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Mon, 15 Sep 2025 18:25:12 +0530 Subject: [PATCH 02/74] removed unused files --- src/components/Activities/AttendcesLogs.jsx | 1 - src/components/Activities/CheckCheckOutForm.jsx | 1 - .../Activities/RegularizationActions.jsx | 2 -- src/components/Employee/EmpAttendance.jsx | 1 - src/slices/localVariablesSlice.jsx | 16 +++++++++++++++- src/store/store.jsx | 5 +---- 6 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/components/Activities/AttendcesLogs.jsx b/src/components/Activities/AttendcesLogs.jsx index faf4bdc5..9aced215 100644 --- a/src/components/Activities/AttendcesLogs.jsx +++ b/src/components/Activities/AttendcesLogs.jsx @@ -4,7 +4,6 @@ import Avatar from "../common/Avatar"; import { convertShortTime } from "../../utils/dateUtils"; import RenderAttendanceStatus from "./RenderAttendanceStatus"; import { useSelector, useDispatch } from "react-redux"; -import { fetchAttendanceData } from "../../slices/apiSlice/attedanceLogsSlice"; import DateRangePicker from "../common/DateRangePicker"; import { clearCacheKey, getCachedData, useSelectedProject } from "../../slices/apiDataManager"; import eventBus from "../../services/eventBus"; diff --git a/src/components/Activities/CheckCheckOutForm.jsx b/src/components/Activities/CheckCheckOutForm.jsx index ca47dd8c..40eb0a75 100644 --- a/src/components/Activities/CheckCheckOutForm.jsx +++ b/src/components/Activities/CheckCheckOutForm.jsx @@ -5,7 +5,6 @@ import { zodResolver } from "@hookform/resolvers/zod"; import TimePicker from "../common/TimePicker"; import { usePositionTracker } from "../../hooks/usePositionTracker"; import { useDispatch, useSelector } from "react-redux"; -import { markAttendance } from "../../slices/apiSlice/attedanceLogsSlice"; import showToast from "../../services/toastService"; import { checkIfCurrentDate } from "../../utils/dateUtils"; import { useMarkAttendance } from "../../hooks/useAttendance"; diff --git a/src/components/Activities/RegularizationActions.jsx b/src/components/Activities/RegularizationActions.jsx index 1fcb3485..4e94c685 100644 --- a/src/components/Activities/RegularizationActions.jsx +++ b/src/components/Activities/RegularizationActions.jsx @@ -1,9 +1,7 @@ import React, { act, useEffect, useState } from 'react' import useAttendanceStatus, { ACTIONS } from '../../hooks/useAttendanceStatus'; -// import AttendanceRepository from '../../repositories/AttendanceRepository'; import { useDispatch, useSelector } from 'react-redux'; import { usePositionTracker } from '../../hooks/usePositionTracker'; -import {markCurrentAttendance} from '../../slices/apiSlice/attendanceAllSlice'; import {cacheData, getCachedData, useSelectedProject} from '../../slices/apiDataManager'; import showToast from '../../services/toastService'; import { useMarkAttendance } from '../../hooks/useAttendance'; diff --git a/src/components/Employee/EmpAttendance.jsx b/src/components/Employee/EmpAttendance.jsx index c441b826..548471d8 100644 --- a/src/components/Employee/EmpAttendance.jsx +++ b/src/components/Employee/EmpAttendance.jsx @@ -2,7 +2,6 @@ import React, { useState, useEffect } from "react"; import moment from "moment"; import DateRangePicker, { DateRangePicker1 } from "../common/DateRangePicker"; import { useDispatch, useSelector } from "react-redux"; -import { fetchEmployeeAttendanceData } from "../../slices/apiSlice/employeeAttendanceSlice"; import usePagination from "../../hooks/usePagination"; import Avatar from "../common/Avatar"; import { convertShortTime } from "../../utils/dateUtils"; diff --git a/src/slices/localVariablesSlice.jsx b/src/slices/localVariablesSlice.jsx index 0b0a8405..5cc86af1 100644 --- a/src/slices/localVariablesSlice.jsx +++ b/src/slices/localVariablesSlice.jsx @@ -10,7 +10,11 @@ const localVariablesSlice = createSlice({ endDate: null, }, projectId: null, - reload:false + reload:false, + + OrganizationModal:{ + isOpen:false + } }, reducers: { @@ -32,6 +36,16 @@ const localVariablesSlice = createSlice({ setDefaultDateRange: (state, action) => { state.defaultDateRange = action.payload; }, + + openOrgModal: (state) => { + state.OrganizationModal.isOpen = true; + }, + closeOrgModal: (state) => { + state.OrganizationModal.isOpen = false; + }, + toggleOrgModal: (state) => { + state.OrganizationModal.isOpen = !state.OrganizationModal.isOpen; + }, }, }); diff --git a/src/store/store.jsx b/src/store/store.jsx index e1d9c03a..fca9836c 100644 --- a/src/store/store.jsx +++ b/src/store/store.jsx @@ -2,15 +2,12 @@ import { configureStore } from "@reduxjs/toolkit"; import apiCacheReducer from "../slices/apiCacheSlice"; import globalVariablesReducer from "../slices/globalVariablesSlice"; import localVariableRducer from "../slices/localVariablesSlice" -import attendanceReducer from "../slices/apiSlice/attedanceLogsSlice" -import employeeAttendanceReducer from "../slices/apiSlice/employeeAttendanceSlice" export const store = configureStore({ reducer: { apiCache: apiCacheReducer, globalVariables: globalVariablesReducer, localVariables:localVariableRducer, - attendanceLogs: attendanceReducer, - employeeAttendance: employeeAttendanceReducer, + }, }); -- 2.43.0 From d944d3a389c9d1548d1cbed45e0836cabc3981b9 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Mon, 15 Sep 2025 19:56:45 +0530 Subject: [PATCH 03/74] setup organization modal, it seprated form another becuase this modal can open anywhere at one hook --- src/App.tsx | 2 + src/ModalContext.jsx | 112 ------------------ src/ModalProvider.jsx | 14 +++ .../Organization/ManageOrganization.jsx | 76 ++++++++++++ .../Organization/OrganizationSchema.js | 32 +++++ src/components/common/Modal.jsx | 37 ++---- src/hooks/useOrganization.js | 16 +++ src/main.tsx | 5 - src/pages/Organization/OrganizationModal.jsx | 0 src/pages/Organization/OrganizationPage.jsx | 43 +++++++ src/router/AppRoutes.jsx | 5 +- src/slices/localVariablesSlice.jsx | 2 +- 12 files changed, 199 insertions(+), 145 deletions(-) delete mode 100644 src/ModalContext.jsx create mode 100644 src/ModalProvider.jsx create mode 100644 src/components/Organization/ManageOrganization.jsx create mode 100644 src/components/Organization/OrganizationSchema.js delete mode 100644 src/pages/Organization/OrganizationModal.jsx diff --git a/src/App.tsx b/src/App.tsx index be7a72ba..db452672 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -4,6 +4,7 @@ import { ToastContainer } from "react-toastify"; import { QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { queryClient } from "./layouts/AuthLayout"; +import ModalProvider from "./ModalProvider"; @@ -11,6 +12,7 @@ const App = () => { return (
+ diff --git a/src/ModalContext.jsx b/src/ModalContext.jsx deleted file mode 100644 index 72607465..00000000 --- a/src/ModalContext.jsx +++ /dev/null @@ -1,112 +0,0 @@ -import React, { - createContext, - useContext, - useState, - useEffect, - useRef, -} from "react"; - -const ModalContext = createContext(); - -export const useModal = () => useContext(ModalContext); - -// ModalProvider to manage modal state and expose functionality to the rest of the app -export const ModalProvider = ({ children }) => { - const [isOpen, setIsOpen] = useState(false); - const [modalContent, setModalContent] = useState(null); - const [onSubmit, setOnSubmit] = useState(null); - const [modalSize, setModalSize] = useState("lg"); - - // Ref to track the modal content element - const modalRef = useRef(null); - - const openModal = (content, onSubmitCallback, size = "lg") => { - setModalContent(content); // Set modal content dynamically - setOnSubmit(() => onSubmitCallback); // Set the submit handler dynamically - setIsOpen(true); // Open the modal - setModalSize(size); // Set the modal size - }; - - // Function to close the modal - const closeModal = () => { - setIsOpen(false); // Close the modal - setModalContent(null); // Clear modal content - setOnSubmit(null); // Clear the submit callback - setModalSize("lg"); // Reset modal size - }; - - useEffect(() => { - const handleEscape = (event) => { - if (event.key === "Escape") { - closeModal(); - } - }; - document.addEventListener("keydown", handleEscape); - return () => { - document.removeEventListener("keydown", handleEscape); - }; - }, []); - - useEffect(() => { - const handleClickOutside = (event) => { - if (modalRef.current && !modalRef.current.contains(event.target)) { - closeModal(); - } - }; - document.addEventListener("mousedown", handleClickOutside); - return () => { - document.removeEventListener("mousedown", handleClickOutside); - }; - }, []); - - return ( - - {children} - - {isOpen && ( -
-
-
{modalContent}
-
-
- )} -
- ); -}; - -const overlayStyles = { - position: "fixed", - top: 0, - left: 0, - right: 0, - bottom: 0, - backgroundColor: "rgba(0, 0, 0, 0.5)", - display: "flex", - justifyContent: "center", - alignItems: "center", - zIndex: 1050, -}; - -const modalStyles = { - backgroundColor: "white", - padding: "20px", - borderRadius: "5px", - boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)", - width: "90%", - maxWidth: "800px", -}; diff --git a/src/ModalProvider.jsx b/src/ModalProvider.jsx new file mode 100644 index 00000000..f098ed0f --- /dev/null +++ b/src/ModalProvider.jsx @@ -0,0 +1,14 @@ +import React from 'react' +import Modal from './components/common/Modal' +import ManageOrganization from './components/Organization/ManageOrganization' + +const ModalProvider = () => { + return ( + <> + + + + ) +} + +export default ModalProvider \ No newline at end of file diff --git a/src/components/Organization/ManageOrganization.jsx b/src/components/Organization/ManageOrganization.jsx new file mode 100644 index 00000000..748f85f7 --- /dev/null +++ b/src/components/Organization/ManageOrganization.jsx @@ -0,0 +1,76 @@ +import { zodResolver } from "@hookform/resolvers/zod"; +import React from "react"; +import { FormProvider, useForm } from "react-hook-form"; +import { + defaultOrganizationValues, + organizationSchema, +} from "./OrganizationSchema"; +import Modal from "../common/Modal"; +import { useOrganization } from "../../hooks/useDirectory"; +import { useOrganizationModal } from "../../hooks/useOrganization"; +import Label from "../common/Label"; + +const ManageOrganization = () => { + const orgModal = useOrganizationModal(); + const method = useForm({ + resolver: zodResolver(organizationSchema), + defaultValues: defaultOrganizationValues, + }); + + const { handleSubmit, watch, register } = method; + + const onSubmit = () => {}; + + const contentBody = ( + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + {errors.description && ( +

{errors.description.message}

+ )} +
+ +
+ + +
+
+ ); +}; + +export default ManageServices; diff --git a/src/components/master/Services/ServicesSchema.js b/src/components/master/Services/ServicesSchema.js new file mode 100644 index 00000000..ceaa8bf5 --- /dev/null +++ b/src/components/master/Services/ServicesSchema.js @@ -0,0 +1,9 @@ +import { z } from "zod"; + +const schema = z.object({ + name: z.string().min(1, { message: "Service Name is required" }), + description: z + .string() + .min(1, { message: "Description is required" }) + .max(255, { message: "Description cannot exceed 255 characters" }), +}); \ No newline at end of file diff --git a/src/hooks/masterHook/useMaster.js b/src/hooks/masterHook/useMaster.js index a31a7c27..cf93ca6c 100644 --- a/src/hooks/masterHook/useMaster.js +++ b/src/hooks/masterHook/useMaster.js @@ -236,6 +236,8 @@ const fetchMasterData = async (masterType) => { return (await MasterRespository.getJobRole()).data; case "Activity": return (await MasterRespository.getActivites()).data; + case "Services": + return (await MasterRespository.getService()).data; case "Work Category": return (await MasterRespository.getWorkCategory()).data; case "Contact Category": @@ -672,6 +674,7 @@ export const useCreatePaymentMode = (onSuccessCallback)=>{ } }) } + export const useUpdatePaymentMode = (onSuccessCallback)=>{ const queryClient = useQueryClient(); @@ -694,6 +697,81 @@ export const useUpdatePaymentMode = (onSuccessCallback)=>{ }) } + +// Services------------------------------- + +// export const useCreateService = (onSuccessCallback) => { +// const queryClient = useQueryClient(); + +// return useMutation({ +// mutationFn: async (payload) => { +// const resp = await MasterRespository.createService(payload); +// return resp.data; // full API response +// }, +// onSuccess: (data) => { +// // Invalidate & refetch service list +// queryClient.invalidateQueries({ queryKey: ["masterData", "Services"] }); + +// showToast(data?.message || "Service added successfully", "success"); + +// if (onSuccessCallback) onSuccessCallback(data?.data); // pass back new service object +// }, +// onError: (error) => { +// showToast(error.message || "Something went wrong", "error"); +// }, +// }); +// }; + +export const useCreateService = (onSuccessCallback) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (payload) => { + debugger; + const resp = await MasterRespository.createService(payload); + debugger; + return resp.data; + }, + onSuccess: (data) => { + debugger; + queryClient.invalidateQueries({ queryKey: ["masterData", "Services"] }); + + showToast(data?.message || "Service added successfully", "success"); + + if (onSuccessCallback) onSuccessCallback(data?.data); + }, + onError: (error) => { + debugger; + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; + + +export const useUpdateService = (onSuccessCallback) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ({ id, payload }) => { + const response = await MasterRespository.updateService(id, payload); + return response; // full response since it already has { success, message, data } + }, + onSuccess: (data, variables) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Services"], + }); + + showToast(data.message || "Service updated successfully.", "success"); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error?.message || "Something went wrong", "error"); + }, + }); +}; + + // -------------------Expense Status---------------------------------- export const useCreateExpenseStatus =(onSuccessCallback)=>{ const queryClient = useQueryClient(); diff --git a/src/pages/master/MasterPage.jsx b/src/pages/master/MasterPage.jsx index 1640f2ba..b187efd1 100644 --- a/src/pages/master/MasterPage.jsx +++ b/src/pages/master/MasterPage.jsx @@ -91,7 +91,7 @@ const MasterPage = () => { {modalConfig && ( api.get("api/master/activities"), createActivity: (data) => api.post("api/master/activity", data), + +//Services + getService: () => api.get("api/master/service/list"), + createService: (data) => api.post("api/master/service/create", data), + updateService: (id, data) => api.put(`api/master/service/edit/${id}`, data), + "Services": (id) => api.delete(`/api/master/service/delete/${id}`), + updateActivity: (id, data) => api.post(`api/master/activity/edit/${id}`, data), getIndustries: () => api.get("api/master/industries"), -- 2.43.0 From af5519fd6005e98cc43d085fa889e299b58163e8 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 14:53:40 +0530 Subject: [PATCH 24/74] Adding Dropdown and Organization Column in Teams --- src/components/Project/Teams.jsx | 65 +++++++++++++++++++------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/src/components/Project/Teams.jsx b/src/components/Project/Teams.jsx index 3a8d78cf..e39a4b13 100644 --- a/src/components/Project/Teams.jsx +++ b/src/components/Project/Teams.jsx @@ -21,8 +21,6 @@ import { import { useSelectedProject } from "../../slices/apiDataManager"; const Teams = () => { - // const {projectId} = useParams() - // const projectId = useSelector((store)=>store.localVariables.projectId) const projectId = useSelectedProject(); const dispatch = useDispatch(); @@ -136,7 +134,6 @@ const Teams = () => { useEffect(() => { if (projectEmployees) { setEmployees(projectEmployees); - //setFilteredEmployees(projectEmployees?.filter((emp) => emp.isActive)); const filtered = projectEmployees.filter((emp) => emp.isActive); setFilteredEmployees(filtered); } @@ -179,13 +176,6 @@ const Teams = () => { const handleFilterEmployee = (e) => { const filterValue = e.target.value; - // if (filterValue === "true") { - // setActiveEmployee(true); - // setFilteredEmployees(employees.filter((emp) => emp.isActive)); - // } else { - // setFilteredEmployees(employees.filter((emp) => !emp.isActive)); - // setActiveEmployee(false); - // } setActiveEmployee(filterValue === "true"); setSearchTerm(""); }; @@ -274,6 +264,27 @@ const Teams = () => { onChange={handleSearch} />
+ {/* Services-Dropdown */} + +
+ +
{
+ + +
+ + {item.organizationName || "N/A"} + - {" "} - {moment(item.allocationDate).format( - "DD-MMM-YYYY" - )}{" "} + {moment(item.allocationDate).format("DD-MMM-YYYY")} {!activeEmployee && ( {item.reAllocationDate - ? moment(item.reAllocationDate).format( - "DD-MMM-YYYY" - ) + ? moment(item.reAllocationDate).format("DD-MMM-YYYY") : "Present"} )} @@ -373,7 +385,7 @@ const Teams = () => { - {item.isActive && ( + {item.isActive ? ( + ) : ( + Not in project )} - {!item.isActive && Not in project} ))} + )} {!employeeLodaing && filteredEmployees.length === 0 && (
-- 2.43.0 From ea219b717696cf618678abaa53789f73ea1f074d Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 15:03:25 +0530 Subject: [PATCH 25/74] Adding Services Dropdown in Infrastructure. --- src/components/Project/ProjectInfra.jsx | 124 ++++++++++++++---------- 1 file changed, 72 insertions(+), 52 deletions(-) diff --git a/src/components/Project/ProjectInfra.jsx b/src/components/Project/ProjectInfra.jsx index 38c05567..c99b08c9 100644 --- a/src/components/Project/ProjectInfra.jsx +++ b/src/components/Project/ProjectInfra.jsx @@ -21,18 +21,17 @@ import { useProjectDetails, useProjectInfra } from "../../hooks/useProjects"; import { useDispatch, useSelector } from "react-redux"; import { refreshData } from "../../slices/localVariablesSlice"; import eventBus from "../../services/eventBus"; -import {useParams} from "react-router-dom"; +import { useParams } from "react-router-dom"; import GlobalModel from "../common/GlobalModel"; -const ProjectInfra = ( {data, onDataChange, eachSiteEngineer} ) => -{ +const ProjectInfra = ({ data, onDataChange, eachSiteEngineer }) => { // const projectId = useSelector((store)=>store.localVariables.projectId) const projectId = useSelectedProject(); const reloadedData = useSelector((store) => store.localVariables.reload); - const [ expandedBuildings, setExpandedBuildings ] = useState( [] ); - const {projectInfra,isLoading,error} = useProjectInfra(projectId) + const [expandedBuildings, setExpandedBuildings] = useState([]); + const { projectInfra, isLoading, error } = useProjectInfra(projectId) const { projects_Details, refetch, loading } = useProjectDetails(data?.id); - const [ project, setProject ] = useState( projects_Details ); + const [project, setProject] = useState(projects_Details); const ManageInfra = useHasUserPermission(MANAGE_PROJECT_INFRA); const ManageTask = useHasUserPermission(MANAGE_TASK) const [showModalFloor, setshowModalFloor] = useState(false); @@ -58,29 +57,29 @@ const ProjectInfra = ( {data, onDataChange, eachSiteEngineer} ) => return ( <> - {showModalBuilding && setshowModalBuilding( false )}> + {showModalBuilding && setshowModalBuilding(false)}> setshowModalBuilding( false )} + onClose={() => setshowModalBuilding(false)} /> - } - {showModalFloor && setshowModalFloor(false)}> + } + {showModalFloor && setshowModalFloor(false)}> setshowModalFloor(false)} - /> + project={projectInfra} + onClose={() => setshowModalFloor(false)} + /> } - {showModalWorkArea && setshowModalWorkArea(false)} > - setshowModalWorkArea(false)} - /> + {showModalWorkArea && setshowModalWorkArea(false)} > + setshowModalWorkArea(false)} + /> } - {showModalTask && ( setshowModalTask(false)}> + {showModalTask && ( setshowModalTask(false)}> setshowModalTask(false)} - /> + project={projectInfra} + onClose={() => setshowModalTask(false)} + /> )}
@@ -88,38 +87,59 @@ const ProjectInfra = ( {data, onDataChange, eachSiteEngineer} ) =>
- {ManageInfra && (<> - - - )} - + +
+ + {/* Buttons Section (aligned to right) */} +
+ {ManageInfra && ( + <> + + + )} + {(ManageTask || ManageInfra) && ( +
+
+
+
+ ))} +
+ + {orgModal.orgData && ( +

+ Don't have required organization, Please find using{" "} + setStep(2)} + > + SPRID + +

+ )}
- {/* ======== org list ======*/} - {/*
-
setStep(2)} - > - - Sample Organization 1 -
-
*/} +
+ {!projectOrganizations && ( + + )} -
+
+
+ + + ))} -
+
+ - +
+
+ +
+ {Organization.address} +
+
+
+ +
+
+ +
    + {masterService.data && + masterService.data?.map((serv) => ( +
  • + + {serv.name} +
  • + ))} +
+
+ +
+ + +
)} @@ -309,48 +469,3 @@ const ManageOrganization = ({ }; export default ManageOrganization; - -//
-//
-//
-// -//
- -//
-//
-//
-//
Icing sweet gummies
-// 15 minutes -//
-// In Meeting -//
-//
-//
-// -//
-//
-//
-//
- -// {/* Icon item */} -//
-//
-// -//
- -//
-//
-//
-//
Icing sweet gummies
-// 15 minutes -//
-// In Meeting -//
-//
-//
-// -//
-//
-//
-//
-//
diff --git a/src/components/Organization/ManageOrganization1.jsx b/src/components/Organization/ManageOrganization1.jsx new file mode 100644 index 00000000..4ba25c4f --- /dev/null +++ b/src/components/Organization/ManageOrganization1.jsx @@ -0,0 +1,193 @@ +const ManageOrganization1 = ({ + projectOrganizations = [], + organizationId = null, +}) => { + const [step, setStep] = useState(1); // default = scenario decision + const orgModal = useOrganizationModal(); + const { data: services, isLoading } = useServices(); + + const method = useForm({ + resolver: zodResolver(organizationSchema), + defaultValues: defaultOrganizationValues, + }); + + const { + handleSubmit, + register, + reset, + formState: { errors }, + } = method; + + const { mutate: CreateOrganization, isPending } = useCreateOrganization( + () => { + reset(defaultOrganizationValues); + orgModal.onClose(); + setStep(1); // reset to first step + } + ); + + // 🔹 Decide first step when modal opens + useEffect(() => { + if (orgModal.isOpen) { + if (organizationId) { + setStep(3); // update flow → show org details directly + } else if (projectOrganizations && projectOrganizations.length > 0) { + setStep(1); // Scenario 1 → from current tenant list + } else { + setStep(2); // Scenario 2 → search with SPRID + } + } + }, [orgModal.isOpen, organizationId, projectOrganizations]); + + const onSubmit = (OrgPayload) => { + CreateOrganization(OrgPayload); + }; + + const RenderTitle = useMemo(() => { + if (organizationId) return "Update Organization"; + if (step === 1) return "Add Organization"; // current tenant + if (step === 2) return "Find Organization"; // search with SPRID + if (step === 3) return "Organization Details"; + if (step === 4) return "Create Organization"; + return "Manage Organization"; + }, [step, organizationId]); + + const contentBody = ( +
+ {/* ---------- STEP 1: From Current Tenant Organizations ---------- */} + {step === 1 && ( +
+
+ {projectOrganizations.map((org, idx) => ( +
setStep(3)} + > + + {org} +
+ ))} +
+ +
+ + +
+
+ )} + + {/* ---------- STEP 2: Search by Service Provider ID ---------- */} + {step === 2 && ( +
+
+ + +
+ + {/* Example SPR results */} +
+
setStep(3)} + > + + Sample Organization (SPRID) +
+
+ +
+ + +
+
+ )} + + {/* ---------- STEP 3: Organization Details ---------- */} + {step === 3 && ( +
+

+ Show organization details here (from SPR or tenant list). User + selects services and clicks Add. +

+
+ +
    +
  • + + Service 1 +
  • +
  • + + Service 2 +
  • +
+
+
+ + +
+
+ )} + + {/* ---------- STEP 4: Create New Organization ---------- */} + {step === 4 && ( + +
+ {/* same form as your code, unchanged */} + {/* ... */} +
+
+ )} +
+ ); + + return ( + + ); +}; + +export default ManageOrganization; \ No newline at end of file diff --git a/src/components/Project/ProjectOrganizations.jsx b/src/components/Project/ProjectOrganizations.jsx index c7093542..fd30568e 100644 --- a/src/components/Project/ProjectOrganizations.jsx +++ b/src/components/Project/ProjectOrganizations.jsx @@ -7,7 +7,8 @@ const ProjectOrganizations = () => { const selectedProject = useSelectedProject() return (
-
+
+
+

diff --git a/src/hooks/useOrganization.js b/src/hooks/useOrganization.js index 2fa6ea00..34e249ff 100644 --- a/src/hooks/useOrganization.js +++ b/src/hooks/useOrganization.js @@ -24,6 +24,15 @@ export const useOrganizationModal = () => { }; }; +export const useOrganizationBySPRID =(sprid)=>{ + return useQuery({ + queryKey:["organization by",sprid], + queryFn:async()=>await OrganizationRepository.getOrganizationBySPRID(sprid), + enabled:!!sprid + }) +} + + export const useOrganizationsList = ( pageSize, pageNumber, diff --git a/src/hooks/useProjects.js b/src/hooks/useProjects.js index 5650f0fa..b411ef33 100644 --- a/src/hooks/useProjects.js +++ b/src/hooks/useProjects.js @@ -268,6 +268,18 @@ export const useProjectLevelEmployeePermission = (employeeId, projectId) => { }); }; + +export const useProjectAssignedServices =(projectId)=>{ + return useQuery({ + queryKey: ["projectAssignedServices", projectId], + queryFn: async () => { + const resp = await ProjectRepository.getProjectAssignedServices(projectId); + return resp.data; + }, + enabled:!!projectId, + }); +} + // -- -------------Mutation------------------------------- export const useCreateProject = ({ onSuccessCallback }) => { diff --git a/src/pages/Directory/ContactsPage.jsx b/src/pages/Directory/ContactsPage.jsx index 40759abe..670b3ef9 100644 --- a/src/pages/Directory/ContactsPage.jsx +++ b/src/pages/Directory/ContactsPage.jsx @@ -98,7 +98,7 @@ const ContactsPage = ({ projectId, searchText, onExport }) => { Pagination={ } diff --git a/src/repositories/OrganizationRespository.jsx b/src/repositories/OrganizationRespository.jsx index ccde9714..36f41006 100644 --- a/src/repositories/OrganizationRespository.jsx +++ b/src/repositories/OrganizationRespository.jsx @@ -10,6 +10,8 @@ const OrganizationRepository = { ); }, + getOrganizationBySPRID :()=>api.get(`/api/Organization/list?sprid=${sprid}`), + assignOrganizationToProject:(data)=>api.post(`/api/Organization/assign/project`,data) }; diff --git a/src/repositories/ProjectRepository.jsx b/src/repositories/ProjectRepository.jsx index fc1c648d..af5c6e67 100644 --- a/src/repositories/ProjectRepository.jsx +++ b/src/repositories/ProjectRepository.jsx @@ -45,7 +45,12 @@ const ProjectRepository = { getProjectLevelModules:()=>api.get(`/api/Project/get/proejct-level/modules`), getProjectLevelEmployeePermissions:(employeeId,projectId)=>api.get(`/api/Project/get/project-level-permission/employee/${employeeId}/project/${projectId}`), updateProjectLevelEmployeePermission:(data)=>api.post(`/api/Project/assign/project-level-permission`,data), - getAllProjectLevelPermission:(projectId)=>api.get(`/api/Project/get/all/project-level-permission/${projectId}`) + getAllProjectLevelPermission:(projectId)=>api.get(`/api/Project/get/all/project-level-permission/${projectId}`), + + + // Services + + getProjectAssignedServices:(projectId)=>api.get(`/api/Project/get/assigned/services/${projectId}`) }; export const TasksRepository = { -- 2.43.0 From e154bac64a0ddadb36fc1377af6d8d1a5b726dc1 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 15:54:29 +0530 Subject: [PATCH 27/74] Calling api for services dropdwon. --- src/components/Project/ProjectInfra.jsx | 31 +++++++++++++------------ 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/src/components/Project/ProjectInfra.jsx b/src/components/Project/ProjectInfra.jsx index c99b08c9..38821a6a 100644 --- a/src/components/Project/ProjectInfra.jsx +++ b/src/components/Project/ProjectInfra.jsx @@ -17,7 +17,7 @@ import { getCachedData, useSelectedProject, } from "../../slices/apiDataManager"; -import { useProjectDetails, useProjectInfra } from "../../hooks/useProjects"; +import { useProjectAssignedServices, useProjectDetails, useProjectInfra } from "../../hooks/useProjects"; import { useDispatch, useSelector } from "react-redux"; import { refreshData } from "../../slices/localVariablesSlice"; import eventBus from "../../services/eventBus"; @@ -39,18 +39,17 @@ const ProjectInfra = ({ data, onDataChange, eachSiteEngineer }) => { const [showModalTask, setshowModalTask] = useState(false); const [showModalBuilding, setshowModalBuilding] = useState(false); const dispatch = useDispatch(); + const { data: assignedServices, isLoading: servicesLoading } = useProjectAssignedServices(projectId); + + const [selectedService, setSelectedService] = useState(""); + const handleServiceChange = (e) => { + setSelectedService(e.target.value); + }; useEffect(() => { setProject(projectInfra); }, [data, projects_Details]); - // useEffect(() => { - // if (reloadedData) { - // refetch(); - // dispatch(refreshData(false)); - // } - // }, [reloadedData]); - const signalRHandler = (response) => { setProject(response); } @@ -96,17 +95,19 @@ const ProjectInfra = ({ data, onDataChange, eachSiteEngineer }) => { aria-controls="DataTables_Table_0" className="form-select form-select-sm" aria-label="Select Service" - defaultValue="Fire-Fitting" - // onChange={handleServiceChange} + value={selectedService} + onChange={handleServiceChange} > - - - - + + {servicesLoading && } + {assignedServices?.map((service) => ( + + ))}

- {/* Buttons Section (aligned to right) */}
{ManageInfra && ( -- 2.43.0 From 7d17422681e73d55e1720203bcd569ce5a733470 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 16:02:36 +0530 Subject: [PATCH 28/74] Calling Api for Services dropdown. --- src/components/Project/Teams.jsx | 50 ++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/components/Project/Teams.jsx b/src/components/Project/Teams.jsx index e39a4b13..fcac139e 100644 --- a/src/components/Project/Teams.jsx +++ b/src/components/Project/Teams.jsx @@ -17,6 +17,7 @@ import eventBus from "../../services/eventBus"; import { useEmployeesByProjectAllocated, useManageProjectAllocation, + useProjectAssignedServices, } from "../../hooks/useProjects"; import { useSelectedProject } from "../../slices/apiDataManager"; @@ -35,6 +36,13 @@ const Teams = () => { const [activeEmployee, setActiveEmployee] = useState(true); const [deleteEmployee, setDeleteEmplyee] = useState(null); const [searchTerm, setSearchTerm] = useState(""); // State for search term + const { data: assignedServices, isLoading: servicesLoading } = useProjectAssignedServices(projectId); + + const [selectedService, setSelectedService] = useState(""); + + const handleServiceChange = (e) => { + setSelectedService(e.target.value); + }; const navigate = useNavigate(); @@ -266,25 +274,29 @@ const Teams = () => {
{/* Services-Dropdown */} -
- -
+
+ +
Date: Fri, 19 Sep 2025 16:13:09 +0530 Subject: [PATCH 29/74] Adding Dropdown in Create Task Popup. --- .../Project/Infrastructure/TaskModel.jsx | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/src/components/Project/Infrastructure/TaskModel.jsx b/src/components/Project/Infrastructure/TaskModel.jsx index f0bb5c35..e7c1438d 100644 --- a/src/components/Project/Infrastructure/TaskModel.jsx +++ b/src/components/Project/Infrastructure/TaskModel.jsx @@ -6,9 +6,10 @@ import { useActivitiesMaster, useWorkCategoriesMaster, } from "../../../hooks/masterHook/useMaster"; -import { useManageTask } from "../../../hooks/useProjects"; +import { useManageTask, useProjectAssignedServices } from "../../../hooks/useProjects"; import showToast from "../../../services/toastService"; import Label from "../../common/Label"; +import { useSelectedProject } from "../../../slices/apiDataManager"; const taskSchema = z.object({ buildingID: z.string().min(1, "Building is required"), @@ -37,6 +38,15 @@ const TaskModel = ({ project, onSubmit, onClose }) => { const { activities, loading: activityLoading } = useActivitiesMaster(); const { categories, categoryLoading } = useWorkCategoriesMaster(); + const projectId = useSelectedProject(); + + const { data: assignedServices, isLoading: servicesLoading } = useProjectAssignedServices(projectId); + + const [selectedService, setSelectedService] = useState(""); + + const handleServiceChange = (e) => { + setSelectedService(e.target.value); + }; const { register, handleSubmit, @@ -96,10 +106,12 @@ const TaskModel = ({ project, onSubmit, onClose }) => { }, [categories]); const onSubmitForm = async (data) => { - const payload = [data]; - CreateTask({payload:payload,buildingId: data.buildingID, + const payload = [data]; + CreateTask({ + payload: payload, buildingId: data.buildingID, floorId: data.floorId, - workAreaId: data.workAreaId, PreviousPlannedWork:0,previousCompletedWork:0}); + workAreaId: data.workAreaId, PreviousPlannedWork: 0, previousCompletedWork: 0 + }); }; return ( @@ -107,6 +119,27 @@ const TaskModel = ({ project, onSubmit, onClose }) => {
Manage Task
+
+ + + {errors.buildingID && ( +

{errors.buildingID.message}

+ )} +
+ {servicesLoading && } + {assignedServices?.map((service) => ( + + ))} + +
+ + {/* 🔹 InfraPlanning only when project is selected */} {selectedProject ? ( - + ) : (
Please Select Project
)} -- 2.43.0 From e9d8b6daea9f1b0cdf4ad976f4d5f3f7f4ad768d Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 16:43:44 +0530 Subject: [PATCH 31/74] Adding Dropdown and API call in Daily Progress Report. --- src/pages/Activities/DailyTask.jsx | 58 +++++++++++++++++++++++++----- 1 file changed, 49 insertions(+), 9 deletions(-) diff --git a/src/pages/Activities/DailyTask.jsx b/src/pages/Activities/DailyTask.jsx index fc51f756..87bc52e2 100644 --- a/src/pages/Activities/DailyTask.jsx +++ b/src/pages/Activities/DailyTask.jsx @@ -1,7 +1,7 @@ import React, { useEffect, useMemo, useState } from "react"; import { useDispatch } from "react-redux"; import { useTaskList } from "../../hooks/useTasks"; -import { useProjectName } from "../../hooks/useProjects"; +import { useProjectAssignedServices, useProjectName } from "../../hooks/useProjects"; import { setProjectId } from "../../slices/localVariablesSlice"; import Breadcrumb from "../../components/common/Breadcrumb"; import DateRangePicker from "../../components/common/DateRangePicker"; @@ -24,6 +24,14 @@ const DailyTask = () => { const ApprovedTaskRights = useHasUserPermission(APPROVE_TASK); const ReportTaskRights = useHasUserPermission(ASSIGN_REPORT_TASK); + const { data: assignedServices, isLoading: servicesLoading } = useProjectAssignedServices(selectedProject); + + const [selectedService, setSelectedService] = useState(""); + + const handleServiceChange = (e) => { + setSelectedService(e.target.value); + }; + const [filters, setFilters] = useState({ selectedBuilding: "", selectedFloors: [], @@ -38,7 +46,6 @@ const DailyTask = () => { dateRange?.endDate || null ); - // Ensure project is set useEffect(() => { if (!selectedProject && projectNames.length > 0) { debugger @@ -46,7 +53,6 @@ const DailyTask = () => { } }, [selectedProject, projectNames, dispatch]); - // 🔹 Reset filters when project changes useEffect(() => { setFilters({ selectedBuilding: "", @@ -55,7 +61,6 @@ const DailyTask = () => { }); }, [selectedProject]); - // Memoized filtering const filteredTasks = useMemo(() => { if (!TaskList) return []; return TaskList.filter((task) => { @@ -69,7 +74,6 @@ const DailyTask = () => { }); }, [TaskList, filters]); - // Memoized dates const groupedTasks = useMemo(() => { const groups = {}; filteredTasks.forEach((task) => { @@ -82,13 +86,11 @@ const DailyTask = () => { .map((date) => ({ date, tasks: groups[date] })); }, [filteredTasks]); - // --- Modal State const [modal, setModal] = useState({ type: null, data: null }); const openModal = (type, data = null) => setModal({ type, data }); const closeModal = () => setModal({ type: null, data: null }); - // --- Render helpers const renderTeamMembers = (task, refIndex) => (
{ return ( <> - {/* --- Modals --- */} {modal.type === "report" && ( @@ -165,7 +166,7 @@ const DailyTask = () => {
{!selectedProject && (
Please Select Project
)} {/* --- Filters --- */} -
+ {/*
{ currentSelectedActivities={filters.selectedActivities} selectedProject={selectedProject} /> +
*/} + +
+ +
+ + +
+ +
+ +
+ + {/* --- Table --- */}
-- 2.43.0 From 164b82e1c79f0a3372e3a858dad71960bf785649 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 17:00:02 +0530 Subject: [PATCH 32/74] Add an Organization column in the Attendance grid across all tabs. --- src/components/Activities/Attendance.jsx | 10 +++++++++- src/components/Activities/AttendcesLogs.jsx | 5 +++-- src/components/Activities/Regularization.jsx | 8 ++++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/components/Activities/Attendance.jsx b/src/components/Activities/Attendance.jsx index 6d751b12..3bd83f9b 100644 --- a/src/components/Activities/Attendance.jsx +++ b/src/components/Activities/Attendance.jsx @@ -142,6 +142,7 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => { + + + - @@ -221,6 +228,7 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => {
Name RoleOrganization Check-In @@ -190,6 +191,8 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => { {item.jobRoleName}{item.organizationName || "--"} {item.checkInTime ? convertShortTime(item.checkInTime) @@ -213,7 +216,11 @@ const Attendance = ({ getRole, handleModalData, searchTerm }) => { ))} {!attendance && (
+ No employees assigned to the project!
+ {!loading && finalFilteredData.length > ITEMS_PER_PAGE && (
*/} ))} + ) : (
Date: Fri, 19 Sep 2025 19:13:02 +0530 Subject: [PATCH 33/74] Adding condition if single or no project assigned then dropdown is not shown --- src/components/Project/Teams.jsx | 87 ++++++++++++++++++-------------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/src/components/Project/Teams.jsx b/src/components/Project/Teams.jsx index fcac139e..afde352a 100644 --- a/src/components/Project/Teams.jsx +++ b/src/components/Project/Teams.jsx @@ -37,6 +37,7 @@ const Teams = () => { const [deleteEmployee, setDeleteEmplyee] = useState(null); const [searchTerm, setSearchTerm] = useState(""); // State for search term const { data: assignedServices, isLoading: servicesLoading } = useProjectAssignedServices(projectId); + const handleToggleActive = e => setActiveEmployee(e.target.checked); const [selectedService, setSelectedService] = useState(""); @@ -262,22 +263,10 @@ const Teams = () => {
-
- -
- {/* Services-Dropdown */} - -
+
+ {servicesLoading ? ( + Loading... + ) : assignedServices?.length > 1 ? ( -
-
-
-
- + {assignedServices?.length === 1 + ? assignedServices[0].name + : "No service available"} +
+ )}
- +
+ +
+ +
+
+
+ + +
{/* Buttons Section (aligned to right) */}
-- 2.43.0 From 00d6774e06c95111b3e1710db62d19d02d4c679f Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 19:26:46 +0530 Subject: [PATCH 35/74] Change the position of Services in Create Task popup in Infrastructure. --- .../Project/Infrastructure/TaskModel.jsx | 49 +++++++++++-------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/src/components/Project/Infrastructure/TaskModel.jsx b/src/components/Project/Infrastructure/TaskModel.jsx index e7c1438d..9c65fa6f 100644 --- a/src/components/Project/Infrastructure/TaskModel.jsx +++ b/src/components/Project/Infrastructure/TaskModel.jsx @@ -119,27 +119,6 @@ const TaskModel = ({ project, onSubmit, onClose }) => {
Manage Task
-
- - - {errors.buildingID && ( -

{errors.buildingID.message}

- )} -
+ {servicesLoading && } + {assignedServices?.map((service) => ( + + ))} + + {errors.buildingID && ( +

{errors.buildingID.message}

+ )} +
+ )} + + {/* Activity Selection */} {selectedWorkArea && (
@@ -225,6 +231,7 @@ const TaskModel = ({ project, onSubmit, onClose }) => {
)} + {selectedWorkArea && (
-- 2.43.0 From 27b62c858df737cb29933ff26f404576d294d6b8 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 19:50:50 +0530 Subject: [PATCH 36/74] Change the position of Datepicker and Dropdown box. --- src/pages/Activities/DailyTask.jsx | 86 +++++++++++++++++------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/src/pages/Activities/DailyTask.jsx b/src/pages/Activities/DailyTask.jsx index 87bc52e2..b935b0a6 100644 --- a/src/pages/Activities/DailyTask.jsx +++ b/src/pages/Activities/DailyTask.jsx @@ -165,28 +165,48 @@ const DailyTask = () => {
{!selectedProject && (
Please Select Project
)} - {/* --- Filters --- */} - {/*
- - -
*/}
-
- + {/* --- Left: Service Dropdown + Filter Icon --- */} +
+
+ {servicesLoading ? ( + Loading... + ) : assignedServices?.length > 1 ? ( + + ) : ( +
+ {assignedServices?.length === 1 + ? assignedServices[0].name + : "No service available"} +
+ )} +
+ { />
-
- + {/* --- Right: DateRangePicker --- */} +
+
- - - {/* --- Table --- */}
@@ -288,4 +298,4 @@ const DailyTask = () => { ); }; -export default DailyTask; +export default DailyTask; \ No newline at end of file -- 2.43.0 From 9223f7a1768ea61544224d76bce87212d2965fc7 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 20:03:36 +0530 Subject: [PATCH 37/74] Adding Card in Daily Progress Report. --- src/components/Activities/InfraPlanning.jsx | 4 +- src/components/Project/ProjectInfra.jsx | 2 +- src/pages/Activities/TaskPlannng.jsx | 70 ++++++++++++++------- 3 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/components/Activities/InfraPlanning.jsx b/src/components/Activities/InfraPlanning.jsx index dc237c63..0e9c9590 100644 --- a/src/components/Activities/InfraPlanning.jsx +++ b/src/components/Activities/InfraPlanning.jsx @@ -55,7 +55,7 @@ const InfraPlanning = () => { if (isFetched && (!projectInfra || projectInfra.length === 0)) { return ( -
+

No Result Found

); @@ -63,11 +63,9 @@ const InfraPlanning = () => { return (
-
-
diff --git a/src/components/Project/ProjectInfra.jsx b/src/components/Project/ProjectInfra.jsx index 38c05567..a0a137cf 100644 --- a/src/components/Project/ProjectInfra.jsx +++ b/src/components/Project/ProjectInfra.jsx @@ -129,7 +129,7 @@ const ProjectInfra = ( {data, onDataChange, eachSiteEngineer} ) =>
{isLoading &&

Loading....

} {projectInfra && projectInfra?.length > 0 && ( - { const selectedProject = useSelectedProject(); const dispatch = useDispatch(); @@ -35,30 +36,53 @@ const TaskPlannng = () => { ]} /> - {/* 🔹 Service Dropdown */} -
- -
+
+
+ {/* Service Dropdown */} +
+ {assignedServices?.length > 1 ? ( + + ) : ( +
+ {assignedServices?.length === 1 + ? assignedServices[0].name + : "No service available"} +
+ )} +
- {/* 🔹 InfraPlanning only when project is selected */} - {selectedProject ? ( - - ) : ( -
Please Select Project
- )} + + {/* Infra Planning Component */} + {selectedProject ? ( + + ) : ( +
Please Select Project
+ )} +
+
); }; -- 2.43.0 From 005fdb3490df5af1e81c0e9e83be4d8e31ba1893 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Fri, 19 Sep 2025 23:46:06 +0530 Subject: [PATCH 38/74] added assigned org to project --- src/ModalProvider.jsx | 11 +- src/components/Organization/AssignOrg.jsx | 211 +++++++++++++++++- src/components/Organization/ManagOrg.jsx | 142 ++++++++++++ .../Organization/ManageOrganization.jsx | 118 +--------- src/components/Organization/OrgPicker.jsx | 110 +++++++++ src/components/Organization/OrgPicker2.jsx | 145 ++++++++++++ .../Organization/OrganizationModal.jsx | 130 +++++++++++ .../Organization/OrganizationSchema.js | 25 +++ .../Organization/OrganizationSkeleton.jsx | 39 ++++ .../Project/ProjectOrganizations.jsx | 4 +- src/hooks/masterHook/useMaster.js | 14 +- src/hooks/useOrganization.js | 66 +++++- src/pages/Organization/OrganizationPage.jsx | 5 +- src/repositories/MastersRepository.jsx | 5 +- src/repositories/OrganizationRespository.jsx | 2 +- src/slices/localVariablesSlice.jsx | 33 ++- 16 files changed, 910 insertions(+), 150 deletions(-) create mode 100644 src/components/Organization/ManagOrg.jsx create mode 100644 src/components/Organization/OrgPicker.jsx create mode 100644 src/components/Organization/OrgPicker2.jsx create mode 100644 src/components/Organization/OrganizationModal.jsx create mode 100644 src/components/Organization/OrganizationSkeleton.jsx diff --git a/src/ModalProvider.jsx b/src/ModalProvider.jsx index a68465f7..d0d72a6e 100644 --- a/src/ModalProvider.jsx +++ b/src/ModalProvider.jsx @@ -1,11 +1,12 @@ -import React from 'react' -import ManageOrganization from './components/Organization/ManageOrganization' +import React, { useEffect } from 'react' +// import ManageOrganization from './components/Organization/ManageOrganization' import { useOrganizationModal } from './hooks/useOrganization'; +import OrganizationModal from './components/Organization/OrganizationModal'; const ModalProvider = () => { - const { isOpen } = useOrganizationModal(); - - return <>{isOpen && }; + const { isOpen,onClose } = useOrganizationModal(); + + return <>{isOpen && }; }; diff --git a/src/components/Organization/AssignOrg.jsx b/src/components/Organization/AssignOrg.jsx index 0fde3168..c773bc88 100644 --- a/src/components/Organization/AssignOrg.jsx +++ b/src/components/Organization/AssignOrg.jsx @@ -1,9 +1,208 @@ -import React from 'react' +import React, { useMemo, useState } from "react"; +import { useProjectAssignedServices } from "../../hooks/useProjects"; +import { useSelectedProject } from "../../slices/apiDataManager"; +import { + useOrganizationType, + useServices, +} from "../../hooks/masterHook/useMaster"; +import Label from "../common/Label"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { assignedOrgToProject } from "./OrganizationSchema"; +import { + useAssignOrgToProject, + useOrganizationModal, +} from "../../hooks/useOrganization"; -const AssignOrg = () => { +const AssignOrg = ({ setStep }) => { + const { isOpen, orgData, startStep, onOpen, onClose, prevStep } = + useOrganizationModal(); + const selectedProject = useSelectedProject(); + const { data: masterService, isLoading: isMasterserviceLoading } = + useServices(); + const { data: projectServices, isLoading } = + useProjectAssignedServices(selectedProject); + const { data: orgType, isLoading: orgLoading } = useOrganizationType(); + + const { mutate: AssignToProject, isPending } = useAssignOrgToProject( + () => {} + ); + + const mergedServices = useMemo(() => { + if (!masterService || !projectServices) return []; + + const combined = [...masterService?.data, ...projectServices]; + + const unique = combined.filter( + (item, index, self) => index === self.findIndex((s) => s.id === item.id) + ); + + return unique; + }, [masterService, projectServices]); + + const { + register, + setValue, + handleSubmit, + formState: { errors }, + } = useForm({ + resolver: zodResolver(assignedOrgToProject), + }); + + const onSubmit = (formData) => { + const payload = { + ...formData, + projectId: selectedProject, + organizationId: orgData.id, + parentOrganizationId: null, + }; + AssignToProject(payload); + }; + const handleEdit = () => { + onOpen({ startStep: 4 , orgData:orgData}); + }; + if (isMasterserviceLoading || isLoading) + return
Loading....
; return ( -
AssignOrg
- ) -} +
+
+
+
{orgData.name}
+
+ +
+
+
-export default AssignOrg \ No newline at end of file +
+
+ +
{orgData.name}
+
+
+
+
+ +
{orgData.contactNumber}
+
+
+
+
+ +
{orgData.email}
+
+
+
+
+ +
{orgData.sprid}
+
+
+ +
+
+ +
{orgData.address}
+
+
+ +
+
+
+ + + {errors.organizationTypeId && ( + + {errors.organizationTypeId.message} + + )} +
+ +
+ + {mergedServices?.map((service) => ( +
+ + +
+ ))} + {errors.serviceIds && ( +
+ {errors.serviceIds.message} +
+ )} +
+ + {/* Buttons */} +
+ + +
+ +
+
+ ); +}; + +export default AssignOrg; diff --git a/src/components/Organization/ManagOrg.jsx b/src/components/Organization/ManagOrg.jsx new file mode 100644 index 00000000..a4da2b48 --- /dev/null +++ b/src/components/Organization/ManagOrg.jsx @@ -0,0 +1,142 @@ +import React, { useEffect } from "react"; +import { FormProvider, useForm } from "react-hook-form"; +import { + useCreateOrganization, + useOrganizationModal, + useUpdateOrganization, +} from "../../hooks/useOrganization"; +import { + defaultOrganizationValues, + organizationSchema, +} from "./OrganizationSchema"; +import Label from "../common/Label"; +import { useGlobalServices } from "../../hooks/masterHook/useMaster"; +import { zodResolver } from "@hookform/resolvers/zod"; +import SelectMultiple from "../common/SelectMultiple"; + +const ManagOrg = () => { + const { data: service, isLoading } = useGlobalServices(); + const { isOpen, orgData, startStep, onOpen, onClose, prevStep } = + useOrganizationModal(); + + const method = useForm({ + resolver: zodResolver(organizationSchema), + defaultValues: defaultOrganizationValues, + }); + + const { + handleSubmit, + register, + reset, + formState: { errors }, + } = method; + + // Create & Update mutations + const { mutate: createOrganization, isPending: isCreating } = useCreateOrganization(() => { + reset(defaultOrganizationValues); + onOpen({ startStep: 1 }); + onClose(); + }); + + const { mutate: updateOrganization, isPending: isUpdating } = useUpdateOrganization(() => { + reset(defaultOrganizationValues); + onOpen({ startStep: 1 }); + onClose(); + }); + + // Prefill form if editing + useEffect(() => { + if (orgData) { + console.log(orgData) + reset({ + name: orgData.name || "", + contactPerson: orgData.contactPerson || "", + contactNumber: orgData.contactNumber || "", + email: orgData.email || "", + serviceIds: orgData.services?.map(s => s.id) || [], + address: orgData.address || "", + }); + } + }, [orgData, reset]); + + const onSubmit = (payload) => { + if (orgData?.id) { + updateOrganization({ id: orgData.id, ...payload }); + } else { + createOrganization(payload); + } + }; + + return ( + +
+
+ + + {errors.name && {errors.name.message}} +
+ +
+ + + {errors.contactPerson && {errors.contactPerson.message}} +
+ +
+ + + {errors.contactNumber && {errors.contactNumber.message}} +
+ +
+ + + {errors.email && {errors.email.message}} +
+ +
+ + {errors.serviceIds && {errors.serviceIds.message}} +
+ +
+ + + + {errors.description && ( +

{errors.description.message}

+ )} +
+ +
+ + +
+ + ); +}; + +export default ManageGroup; \ No newline at end of file diff --git a/src/components/master/Services/ServicesGroups.jsx b/src/components/master/Services/ServicesGroups.jsx new file mode 100644 index 00000000..a554ea6a --- /dev/null +++ b/src/components/master/Services/ServicesGroups.jsx @@ -0,0 +1,133 @@ +import { useState } from "react"; +import { + useActivitiesByGroups, + useGroups, +} from "../../../hooks/masterHook/useMaster"; +import ManageGroup from "./ManageGroup"; + +const ServiceGroups = ({ service }) => { + const [openService, setOpenService] = useState(true); + const [activeGroupId, setActiveGroupId] = useState(null); // track selected group + const [isManageGroup,setManageGroup] = useState({isOpen:false,group:true}) + + const { data: groups, isLoading } = useGroups(service?.id); + const { data: activities, isLoading: actLoading } = + useActivitiesByGroups(activeGroupId); + + if (isLoading) return
Loading groups...
; + + return ( +
+

Manage Service

+
+
+ {/* Service Header */} +
+

{service.name}

+ setOpenService(!openService)} + className="text-end cursor-pointer" + data-bs-toggle="collapse" + data-bs-target="#accordionOne" + aria-expanded={openService} + aria-controls="accordionOne" + > + + +
+ + {/* Groups Section */} +
+
+
+ {groups?.data?.map((group) => { + const isOpen = activeGroupId === group.id; + + return ( +
+
+

{group.name}

+
+ +
+ setManageGroup({isOpen:true,group:null})}> + + +
+ setActiveGroupId(isOpen ? null : group.id) + } + className="text-end cursor-pointer" + data-bs-toggle="collapse" + data-bs-target={`#accordionGroup${group.id}`} + aria-expanded={isOpen} + aria-controls={`accordionGroup${group.id}`} + > + +
+
+ {isManageGroup.isOpen ? setManageGroup({isOpen:false,group:null})}/> : ( +
+
+ {isOpen && actLoading &&

Loading activities...

} + {isOpen && activities?.data?.length > 0 ? ( +
    + {activities.data.map((activity) => ( +
    +
  • + {activity.name} +
  • {" "} +
    + + + +
    +
    + ))} +
+ ) : ( + isOpen &&

No activities found

+ )} +
+
+ ) } + + +
+ ); + })} +
+
+
+
+
+ ); +}; + +export default ServiceGroups; diff --git a/src/components/master/Services/ServicesSchema.js b/src/components/master/Services/ServicesSchema.js index ceaa8bf5..72f28e50 100644 --- a/src/components/master/Services/ServicesSchema.js +++ b/src/components/master/Services/ServicesSchema.js @@ -6,4 +6,12 @@ const schema = z.object({ .string() .min(1, { message: "Description is required" }) .max(255, { message: "Description cannot exceed 255 characters" }), +}); + +export const ActivityGroupSchema = z.object({ + name: z.string().min(1, { message: "Group Name is required" }), + description: z + .string() + .min(1, { message: "Description is required" }) + .max(255, { message: "Description cannot exceed 255 characters" }), }); \ No newline at end of file diff --git a/src/hooks/masterHook/useMaster.js b/src/hooks/masterHook/useMaster.js index 6e589efe..7846fa77 100644 --- a/src/hooks/masterHook/useMaster.js +++ b/src/hooks/masterHook/useMaster.js @@ -1,52 +1,75 @@ -import {useState,useEffect, useCallback} from "react" +import { useState, useEffect, useCallback } from "react"; import { MasterRespository } from "../../repositories/MastersRepository"; -import { cacheData,getCachedData } from "../../slices/apiDataManager"; +import { cacheData, getCachedData } from "../../slices/apiDataManager"; import { useSelector } from "react-redux"; -import {useMutation, useQueries, useQuery, useQueryClient} from "@tanstack/react-query"; +import { + useMutation, + useQueries, + useQuery, + useQueryClient, +} from "@tanstack/react-query"; import showToast from "../../services/toastService"; - - - - -export const useServices = ()=>{ +export const useServices = () => { return useQuery({ - queryKey:["services"], - queryFn:async()=> await MasterRespository.getMasterServices() - }) -} -export const useGlobalServices = ()=>{ - return useQuery({ - queryKey:["globalServices"], - queryFn:async()=> await MasterRespository.getGlobalServices() - }) -} + queryKey: ["services"], + queryFn: async () => await MasterRespository.getMasterServices(), + }); +}; -export const useMasterMenu = ()=>{ +export const useGroups = (serviceId) => { + return useQuery({ + queryFn: ["groups", serviceId], + queryFn: async () => await MasterRespository.getActivityGrops(serviceId), + }) +}; +export const useActivitiesByGroups = (groupId) => { + return useQuery({ + queryFn: ["activties", groupId], + queryFn: async () => await MasterRespository.getActivityGrops(groupId), + }) +}; +export const useGlobalServices = () => { return useQuery({ - queryKey:["MasterMenu"], - queryFn:async()=> { + queryKey: ["globalServices"], + queryFn: async () => await MasterRespository.getGlobalServices(), + }); +}; + +export const useMasterMenu = () => { + return useQuery({ + queryKey: ["MasterMenu"], + queryFn: async () => { const resp = await MasterRespository.getMasterMenus(); - return resp.data - } - }) -} + return resp.data; + }, + }); +}; -export const useActivitiesMaster = () => -{ - const { data:activities=[],isLoading:loading,error} = useQuery( { - queryKey: [ "ActivityMaster" ], - queryFn: async() => - { + + +export const useActivitiesMaster = () => { + const { + data: activities = [], + isLoading: loading, + error, + } = useQuery({ + queryKey: ["ActivityMaster"], + queryFn: async () => { const response = await MasterRespository.getActivites(); - return response.data + return response.data; }, - onError: (error) => { - showToast(error?.response?.data?.message || error.message || "Failed to fetch ActivityMasters", "error"); + onError: (error) => { + showToast( + error?.response?.data?.message || + error.message || + "Failed to fetch ActivityMasters", + "error" + ); }, - } ) - return {activities,loading,error} -} + }); + return { activities, loading, error }; +}; export const useWorkCategoriesMaster = () => { const { data: categories = [], @@ -71,22 +94,28 @@ export const useWorkCategoriesMaster = () => { return { categories, categoryLoading, categoryError }; }; - -export const useContactCategory = () => -{ - const {data:contactCategory=[],isLoading:loading,error:Error } = useQuery( { - queryKey: [ "Contact Category" ], - queryFn: async () => - { +export const useContactCategory = () => { + const { + data: contactCategory = [], + isLoading: loading, + error: Error, + } = useQuery({ + queryKey: ["Contact Category"], + queryFn: async () => { let resp = await MasterRespository.getContactCategory(); - return resp.data + return resp.data; }, - onError: (error) => { - showToast(error?.response?.data?.message || error.message || "Failed to fetch Contact categories", "error"); + onError: (error) => { + showToast( + error?.response?.data?.message || + error.message || + "Failed to fetch Contact categories", + "error" + ); }, - } ) - return { contactCategory,loading,Error} -} + }); + return { contactCategory, loading, Error }; +}; export const useContactTags = () => { const { @@ -112,16 +141,15 @@ export const useContactTags = () => { return { contactTags, loading, error }; }; - -export const useExpenseType =()=>{ -const { +export const useExpenseType = () => { + const { data: ExpenseTypes = [], isLoading: loading, error, } = useQuery({ queryKey: ["Expense Type"], queryFn: async () => { - const res = await MasterRespository.getExpenseType() + const res = await MasterRespository.getExpenseType(); return res.data; }, onError: (error) => { @@ -135,16 +163,16 @@ const { }); return { ExpenseTypes, loading, error }; -} -export const usePaymentMode =()=>{ -const { +}; +export const usePaymentMode = () => { + const { data: PaymentModes = [], isLoading: loading, error, } = useQuery({ queryKey: ["Payment Mode"], queryFn: async () => { - const res = await MasterRespository.getPaymentMode() + const res = await MasterRespository.getPaymentMode(); return res.data; }, onError: (error) => { @@ -158,16 +186,16 @@ const { }); return { PaymentModes, loading, error }; -} -export const useExpenseStatus =()=>{ -const { +}; +export const useExpenseStatus = () => { + const { data: ExpenseStatus = [], isLoading: loading, error, } = useQuery({ queryKey: ["Expense Status"], queryFn: async () => { - const res = await MasterRespository.getExpenseStatus() + const res = await MasterRespository.getExpenseStatus(); return res.data; }, onError: (error) => { @@ -181,20 +209,20 @@ const { }); return { ExpenseStatus, loading, error }; -} -export const useDocumentTypes =(category)=>{ -const { +}; +export const useDocumentTypes = (category) => { + const { data: DocumentTypes = [], error, isError, - isLoading + isLoading, } = useQuery({ - queryKey: ["Document Type",category], + queryKey: ["Document Type", category], queryFn: async () => { - const res = await MasterRespository.getDocumentTypes(category) + const res = await MasterRespository.getDocumentTypes(category); return res.data; }, - enabled:!!category, + enabled: !!category, onError: (error) => { showToast( error?.response?.data?.message || @@ -206,20 +234,20 @@ const { }); return { DocumentTypes, isError, isLoading, error }; -} -export const useDocumentCategories =(EntityType)=>{ -const { +}; +export const useDocumentCategories = (EntityType) => { + const { data: DocumentCategories = [], error, isError, - isLoading + isLoading, } = useQuery({ - queryKey: ["Document Category",EntityType], + queryKey: ["Document Category", EntityType], queryFn: async () => { - const res = await MasterRespository.getDocumentCategories(EntityType) + const res = await MasterRespository.getDocumentCategories(EntityType); return res.data; }, - enabled:!!EntityType, + enabled: !!EntityType, onError: (error) => { showToast( error?.response?.data?.message || @@ -231,13 +259,13 @@ const { }); return { DocumentCategories, isError, isLoading, error }; -} -export const useOrganizationType =()=>{ +}; +export const useOrganizationType = () => { return useQuery({ - queryKey:["orgType"], - queryFn:async()=>await MasterRespository.getOrganizationType() - }) -} + queryKey: ["orgType"], + queryFn: async () => await MasterRespository.getOrganizationType(), + }); +}; // ===Application Masters Query================================================= const fetchMasterData = async (masterType) => { @@ -248,7 +276,7 @@ const fetchMasterData = async (masterType) => { return (await MasterRespository.getJobRole()).data; case "Activity": return (await MasterRespository.getActivites()).data; - case "Services": + case "Services": return (await MasterRespository.getService()).data; case "Work Category": return (await MasterRespository.getWorkCategory()).data; @@ -293,8 +321,13 @@ const fetchMasterData = async (masterType) => { }; const useMaster = () => { - const selectedMaster = useSelector((store) => store.localVariables.selectedMaster); - const queryFn = useCallback(() => fetchMasterData(selectedMaster), [selectedMaster]); + const selectedMaster = useSelector( + (store) => store.localVariables.selectedMaster + ); + const queryFn = useCallback( + () => fetchMasterData(selectedMaster), + [selectedMaster] + ); const { data = [], isLoading, @@ -303,11 +336,16 @@ const useMaster = () => { queryKey: ["masterData", selectedMaster], queryFn, enabled: !!selectedMaster, - staleTime: 1000 * 60 * 10, + staleTime: 1000 * 60 * 10, refetchOnWindowFocus: false, onError: (error) => { - showToast(error?.response?.data?.message || error.message || `Failed to fetch ${selectedMaster} Maseter`, "error"); - }, + showToast( + error?.response?.data?.message || + error.message || + `Failed to fetch ${selectedMaster} Maseter`, + "error" + ); + }, }); return { data, loading: isLoading, error }; @@ -353,7 +391,7 @@ export const useCreateJobRole = (onSuccessCallback) => { onSuccess: (data) => { showToast("JobRole added successfully.", "success"); - queryClient.invalidateQueries({queryKey:["masterData", "Job Role"]}); + queryClient.invalidateQueries({ queryKey: ["masterData", "Job Role"] }); if (onSuccessCallback) onSuccessCallback(data); }, @@ -365,350 +403,315 @@ export const useCreateJobRole = (onSuccessCallback) => { // Application Role------------------------------------------- -export const useCreateApplicationRole = (onSuccessCallback) => -{ +export const useCreateApplicationRole = (onSuccessCallback) => { const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { - const resp = await MasterRespository.createRole( payload ); + return useMutation({ + mutationFn: async (payload) => { + const resp = await MasterRespository.createRole(payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Application Role" ]} ) - showToast( "Application Role added successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + 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"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; -export const useUpdateApplicationRole = (onSuccessCallback) => -{ - const queryClient = useQueryClient(); +export const useUpdateApplicationRole = (onSuccessCallback) => { + const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ( {id, payload} ) => - { - const response = await MasterRespository.updateRoles(id,payload); + 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) => -{ +export const useCreateActivity = (onSuccessCallback) => { const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { + 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) + 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"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; -export const useUpdateActivity = (onSuccessCallback) => -{ - const queryClient = useQueryClient(); +export const useUpdateActivity = (onSuccessCallback) => { + const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ( {id, payload} ) => - { - const response = await MasterRespository.updateActivity(id,payload); + 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) => -{ +export const useCreateWorkCategory = (onSuccessCallback) => { const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { + 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) + 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"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; -export const useUpdateWorkCategory = (onSuccessCallback) => -{ - const queryClient = useQueryClient(); +export const useUpdateWorkCategory = (onSuccessCallback) => { + const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ( {id, payload} ) => - { - const response = await MasterRespository.updateWorkCategory(id,payload); + 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) => -{ +export const useCreateContactCategory = (onSuccessCallback) => { const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { + 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) + 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"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; - -export const useUpdateContactCategory = (onSuccessCallback) => -{ - const queryClient = useQueryClient(); +export const useUpdateContactCategory = (onSuccessCallback) => { + const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ( {id, payload} ) => - { - const response = await MasterRespository.updateContactCategory(id,payload); + 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) => -{ +export const useCreateContactTag = (onSuccessCallback) => { const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { + 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) + 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"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; - -export const useUpdateContactTag = (onSuccessCallback) => -{ - const queryClient = useQueryClient(); +export const useUpdateContactTag = (onSuccessCallback) => { + const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ( {id, payload} ) => - { - debugger - const response = await MasterRespository.updateContactTag(id,payload); + 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"); }, }); -} +}; // ----------------------Expense Type------------------ -export const useCreateExpenseType = (onSuccessCallback)=>{ - const queryClient = useQueryClient(); +export const useCreateExpenseType = (onSuccessCallback) => { + const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { + return useMutation({ + mutationFn: async (payload) => { const resp = await MasterRespository.createExpenseType(payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Expense Type" ]} ) - showToast( "Expense Type added successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Expense Type"], + }); + showToast("Expense Type added successfully", "success"); + if (onSuccessCallback) onSuccessCallback(data); }, - onError: ( error ) => - { - showToast(error.message || "Something went wrong", "error"); - } - }) -} -export const useUpdateExpenseType = (onSuccessCallback) => -{ - const queryClient = useQueryClient(); + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; +export const useUpdateExpenseType = (onSuccessCallback) => { + const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ( {id, payload} ) => - { - const response = await MasterRespository.updateExpenseType(id,payload); + mutationFn: async ({ id, payload }) => { + const response = await MasterRespository.updateExpenseType(id, payload); return response.data; }, onSuccess: (data, variables) => { - queryClient.invalidateQueries({ queryKey: ["masterData", "Expense Type"], }); showToast("Expense Type updated successfully.", "success"); - + if (onSuccessCallback) onSuccessCallback(data); }, onError: (error) => { showToast(error.message || "Something went wrong", "error"); }, }); -} +}; // -----------------Payment Mode ------------- -export const useCreatePaymentMode = (onSuccessCallback)=>{ - const queryClient = useQueryClient(); +export const useCreatePaymentMode = (onSuccessCallback) => { + const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { + return useMutation({ + mutationFn: async (payload) => { const resp = await MasterRespository.createPaymentMode(payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Payment Mode" ]} ) - showToast( "Payment Mode added successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Payment Mode"], + }); + showToast("Payment Mode added successfully", "success"); + if (onSuccessCallback) onSuccessCallback(data); }, - onError: ( error ) => - { - showToast(error.message || "Something went wrong", "error"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; -export const useUpdatePaymentMode = (onSuccessCallback)=>{ - const queryClient = useQueryClient(); +export const useUpdatePaymentMode = (onSuccessCallback) => { + const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( {id,payload} ) => - { - const resp = await MasterRespository.updatePaymentMode(id,payload); + return useMutation({ + mutationFn: async ({ id, payload }) => { + const resp = await MasterRespository.updatePaymentMode(id, payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Payment Mode" ]} ) - showToast( "Payment Mode Updated successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Payment Mode"], + }); + showToast("Payment Mode Updated successfully", "success"); + if (onSuccessCallback) onSuccessCallback(data); }, - onError: ( error ) => - { - showToast(error.message || "Something went wrong", "error"); - } - }) -} - + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; // Services------------------------------- @@ -739,27 +742,26 @@ export const useCreateService = (onSuccessCallback) => { return useMutation({ mutationFn: async (payload) => { - debugger; + debugger; const resp = await MasterRespository.createService(payload); - debugger; + debugger; return resp.data; }, onSuccess: (data) => { - debugger; + debugger; queryClient.invalidateQueries({ queryKey: ["masterData", "Services"] }); showToast(data?.message || "Service added successfully", "success"); - if (onSuccessCallback) onSuccessCallback(data?.data); + if (onSuccessCallback) onSuccessCallback(data?.data); }, onError: (error) => { - debugger; + debugger; showToast(error.message || "Something went wrong", "error"); }, }); }; - export const useUpdateService = (onSuccessCallback) => { const queryClient = useQueryClient(); @@ -783,154 +785,169 @@ export const useUpdateService = (onSuccessCallback) => { }); }; +export const useCreateActivityGroup =()=>{ + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (payload) => { + const response = await MasterRespository.createActivityGroup(payload) + return response; + }, + onSuccess: (data, variables) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Services"], + }); + + showToast(data.message || "Activity Group created successfully.", "success"); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error?.message || "Something went wrong", "error"); + }, + }); +} // -------------------Expense Status---------------------------------- -export const useCreateExpenseStatus =(onSuccessCallback)=>{ - const queryClient = useQueryClient(); +export const useCreateExpenseStatus = (onSuccessCallback) => { + const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { + return useMutation({ + mutationFn: async (payload) => { const resp = await MasterRespository.createExpenseStatus(payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Expense Status" ]} ) - showToast( "Expense Status added successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Expense Status"], + }); + showToast("Expense Status added successfully", "success"); + if (onSuccessCallback) onSuccessCallback(data); }, - onError: ( error ) => - { - showToast(error.message || "Something went wrong", "error"); - } - }) -} -export const useUpdateExpenseStatus = (onSuccessCallback)=>{ - const queryClient = useQueryClient(); + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; +export const useUpdateExpenseStatus = (onSuccessCallback) => { + const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( {id,payload} ) => - { - const resp = await MasterRespository.updateExepnseStatus(id,payload); + return useMutation({ + mutationFn: async ({ id, payload }) => { + const resp = await MasterRespository.updateExepnseStatus(id, payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Expense Status" ]} ) - showToast( "Expense Status Updated successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Expense Status"], + }); + showToast("Expense Status Updated successfully", "success"); + if (onSuccessCallback) onSuccessCallback(data); }, - onError: ( error ) => - { - showToast(error.message || "Something went wrong", "error"); - } - }) -} - - + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; // --------------------Document-Category-------------------------------- -export const useCreateDocumentCatgory =(onSuccessCallback)=>{ - const queryClient = useQueryClient(); +export const useCreateDocumentCatgory = (onSuccessCallback) => { + const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { + return useMutation({ + mutationFn: async (payload) => { const resp = await MasterRespository.createDocumenyCategory(payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Document Category" ]} ) - queryClient.invalidateQueries( {queryKey:[ "Document Category" ]} ) - showToast( "Document Category added successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Document Category"], + }); + queryClient.invalidateQueries({ queryKey: ["Document Category"] }); + showToast("Document Category added successfully", "success"); + if (onSuccessCallback) onSuccessCallback(data); }, - onError: ( error ) => - { - showToast(error.message || "Something went wrong", "error"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; -export const useUpdateDocumentCategory =(onSuccessCallback)=>{ - const queryClient = useQueryClient(); +export const useUpdateDocumentCategory = (onSuccessCallback) => { + const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( {id,payload} ) => - { - const resp = await MasterRespository.updateDocumentCategory(id,payload); + return useMutation({ + mutationFn: async ({ id, payload }) => { + const resp = await MasterRespository.updateDocumentCategory(id, payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Document Category" ]} ) - queryClient.invalidateQueries( {queryKey:[ "Document Category" ]} ) - showToast( "Document Category Updated successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Document Category"], + }); + queryClient.invalidateQueries({ queryKey: ["Document Category"] }); + showToast("Document Category Updated successfully", "success"); + if (onSuccessCallback) onSuccessCallback(data); }, - onError: ( error ) => - { - showToast(error.message || "Something went wrong", "error"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; // ------------------------------Document-Type----------------------------------- -export const useCreateDocumentType =(onSuccessCallback)=>{ - const queryClient = useQueryClient(); +export const useCreateDocumentType = (onSuccessCallback) => { + const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( payload ) => - { + return useMutation({ + mutationFn: async (payload) => { const resp = await MasterRespository.createDocumentType(payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Document Type" ]} ) - showToast( "Document Type added successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Document Type"], + }); + showToast("Document Type added successfully", "success"); + if (onSuccessCallback) onSuccessCallback(data); }, - onError: ( error ) => - { - showToast(error.message || "Something went wrong", "error"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; -export const useUpdateDocumentType =(onSuccessCallback)=>{ - const queryClient = useQueryClient(); +export const useUpdateDocumentType = (onSuccessCallback) => { + const queryClient = useQueryClient(); - return useMutation( { - mutationFn: async ( {id,payload} ) => - { - const resp = await MasterRespository.updateDocumentType(id,payload); + return useMutation({ + mutationFn: async ({ id, payload }) => { + const resp = await MasterRespository.updateDocumentType(id, payload); return resp.data; }, - onSuccess: ( data ) => - { - queryClient.invalidateQueries( {queryKey:[ "masterData", "Document Type" ]} ) - showToast( "Document Type Updated successfully", "success" ); - if(onSuccessCallback) onSuccessCallback(data) + onSuccess: (data) => { + queryClient.invalidateQueries({ + queryKey: ["masterData", "Document Type"], + }); + showToast("Document Type Updated successfully", "success"); + if (onSuccessCallback) onSuccessCallback(data); }, - onError: ( error ) => - { - showToast(error.message || "Something went wrong", "error"); - } - }) -} + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; // -Delete Master -------- export const useDeleteMasterItem = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ( {masterType, item} ) => - { + mutationFn: async ({ masterType, item }) => { const deleteFn = MasterRespository[masterType]; if (!deleteFn) { - throw new Error(`No delete strategy defined for master type: ${masterType}`); + throw new Error( + `No delete strategy defined for master type: ${masterType}` + ); } await deleteFn(item.id); @@ -945,8 +962,10 @@ export const useDeleteMasterItem = () => { onError: (error) => { const message = - error?.response?.data?.message || error?.message || "Error occurred during deletion"; + error?.response?.data?.message || + error?.message || + "Error occurred during deletion"; showToast(message, "error"); }, }); -}; \ No newline at end of file +}; diff --git a/src/pages/master/MasterTable.jsx b/src/pages/master/MasterTable.jsx index b2285842..8facfdb7 100644 --- a/src/pages/master/MasterTable.jsx +++ b/src/pages/master/MasterTable.jsx @@ -158,6 +158,21 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => { ) : ( <> + {selectedMaster === "Services" && ( + + )} +
{ + onClick={() => { dispatch(setProjectId(projectInfo.id)) navigate(`/projects/details`) }} @@ -168,7 +169,7 @@ const ProjectListView = ({ projectData, recall }) => { navigate(`/projects/details`)} + onClick={handleViewProject} > View details -- 2.43.0 From d87dae47990bd7484122608ac9f457d8732a5ec5 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Tue, 23 Sep 2025 16:35:48 +0530 Subject: [PATCH 68/74] In ExpensePanel add new Toggle button. --- .../Expenses/ExpenseFilterPanel.jsx | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/src/components/Expenses/ExpenseFilterPanel.jsx b/src/components/Expenses/ExpenseFilterPanel.jsx index 5e415821..f93f66ba 100644 --- a/src/components/Expenses/ExpenseFilterPanel.jsx +++ b/src/components/Expenses/ExpenseFilterPanel.jsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState,useMemo } from "react"; +import React, { useEffect, useState, useMemo } from "react"; import { FormProvider, useForm, Controller } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { defaultFilter, SearchSchema } from "./ExpenseSchema"; @@ -17,7 +17,7 @@ import { useLocation } from "react-router-dom"; const ExpenseFilterPanel = ({ onApply, handleGroupBy }) => { const selectedProjectId = useSelector((store) => store.localVariables.projectId); - const { data, isLoading,isError,error,isFetching , isFetched} = useExpenseFilter(); + const { data, isLoading, isError, error, isFetching, isFetched } = useExpenseFilter(); const groupByList = useMemo(() => { return [ @@ -27,11 +27,10 @@ const ExpenseFilterPanel = ({ onApply, handleGroupBy }) => { { id: "project", name: "Project" }, { id: "paymentMode", name: "Payment Mode" }, { id: "expensesType", name: "Expense Type" }, - { id: "createdAt", name: "Submitted Date" } + { id: "createdAt", name: "Submitted Date" } ].sort((a, b) => a.name.localeCompare(b.name)); }, []); - const [selectedGroup, setSelectedGroup] = useState(groupByList[0]); const [resetKey, setResetKey] = useState(0); @@ -40,7 +39,7 @@ const ExpenseFilterPanel = ({ onApply, handleGroupBy }) => { defaultValues: defaultFilter, }); - const { control, register, handleSubmit, reset, watch } = methods; + const { control, handleSubmit, reset, setValue, watch } = methods; const isTransactionDate = watch("isTransactionDate"); const closePanel = () => { @@ -78,7 +77,7 @@ const ExpenseFilterPanel = ({ onApply, handleGroupBy }) => { }, [location]); if (isLoading || isFetching) return ; - if(isError && isFetched) return
Something went wrong Here- {error.message}
+ if (isError && isFetched) return
Something went wrong Here- {error.message}
return ( <> @@ -86,18 +85,29 @@ const ExpenseFilterPanel = ({ onApply, handleGroupBy }) => {
- -
- + +
+ +
-
{
- + -
- +// {/* ✅ Date Picker Aligned Left with Padding */} +//
+//
+// +//
+//
- {/* Tabs */} -
    -
  • - -
  • -
  • - -
  • -
+// {/* Tabs */} +//
    +//
  • +// +//
  • +//
  • +// +//
  • +//
-
- {activeTab === "all" && ( -
-
- {isLoading ? ( -

Loading activity data...

- ) : isError ? ( -

No data available.

- ) : ( - ActivityData && ( - <> -
- Allocated Task -
-

- {ActivityData.totalCompletedWork?.toLocaleString()}/ - {ActivityData.totalPlannedWork?.toLocaleString()} -

- Completed / Assigned -
- -
- - ) - )} -
+//
+// {activeTab === "all" && ( +//
+//
+// {isLoading ? ( +//

Loading activity data...

+// ) : isError ? ( +//

No data available.

+// ) : ( +// ActivityData && ( +// <> +//
+// Allocated Task +//
+//

+// {ActivityData.totalCompletedWork?.toLocaleString()}/ +// {ActivityData.totalPlannedWork?.toLocaleString()} +//

+// Completed / Assigned +//
+// +//
+// +// ) +// )} +//
-
- {!isLoading && !isError && ActivityData && ( - <> -
- Activities -
-

- {ActivityData.totalCompletedWork?.toLocaleString()}/ - {ActivityData.totalPlannedWork?.toLocaleString()} -

- Pending / Assigned -
- -
- - )} -
-
- )} +//
+// {!isLoading && !isError && ActivityData && ( +// <> +//
+// Activities +//
+//

+// {ActivityData.totalCompletedWork?.toLocaleString()}/ +// {ActivityData.totalPlannedWork?.toLocaleString()} +//

+// Pending / Assigned +//
+// +//
+// +// )} +//
+//
+// )} - {activeTab === "logs" && ( -
- - - - - - - - - {[{ - activity: "Code Review / Remote", - assignedToday: 3, - completed: 2 - }].map((log, index) => ( - - - - - ))} - -
Activity / LocationAssigned / Completed
{log.activity}{log.assignedToday} / {log.completed}
-
- )} -
-
- ); -}; +// {activeTab === "logs" && ( +//
+// +// +// +// +// +// +// +// +// {[{ +// activity: "Code Review / Remote", +// assignedToday: 3, +// completed: 2 +// }].map((log, index) => ( +// +// +// +// +// ))} +// +//
Activity / LocationAssigned / Completed
{log.activity}{log.assignedToday} / {log.completed}
+//
+// )} +// +// +// ); +// }; -export default Activity; +// export default Activity; diff --git a/src/components/master/CreateActivity.jsx b/src/components/master/CreateActivity.jsx index d707593d..1db2bb79 100644 --- a/src/components/master/CreateActivity.jsx +++ b/src/components/master/CreateActivity.jsx @@ -24,7 +24,7 @@ const schema = z.object({ .optional(), }); -const CreateActivity = ({ onClose }) => { +const CreateActivity = ({ activity = null, whichGroup = null, close }) => { const maxDescriptionLength = 255; const { mutate: createActivity, isPending: isLoading } = useCreateActivity(() => onClose?.()); @@ -86,25 +86,19 @@ const CreateActivity = ({ onClose }) => { const onSubmit = (formData) => { createActivity(formData); }; - // const onSubmit = (data) => { - // setIsLoading(true); - - // MasterRespository.createActivity(data) - // .then( ( resp ) => - // { - - // const cachedData = getCachedData("Activity"); - // const updatedData = [ ...cachedData, resp?.data ]; - // cacheData("Activity", updatedData); - // showToast("Activity Successfully Added.", "success"); - // setIsLoading(false); - // handleClose() - // }) - // .catch((error) => { - // showToast(error.message, "error"); - // setIsLoading(false); - // }); - // }; + + useEffect(()=>{ + if (activity) { + reset({ + activityName: activity.activityName || '', + unitOfMeasurement: activity.unitOfMeasurement || '', + checkList: activity.checkList?.map((check) => ({ + description: check.description || '', + isMandatory: check.isMandatory || false, + })) || [{ description: '', isMandatory: false }], + }); + } + },[activity,reset]) const handleClose = useCallback(() => { reset(); onClose(); diff --git a/src/components/master/EditActivity.jsx b/src/components/master/EditActivity.jsx index 43816f4c..15e85255 100644 --- a/src/components/master/EditActivity.jsx +++ b/src/components/master/EditActivity.jsx @@ -24,7 +24,7 @@ const schema = z.object({ }); -const UpdateActivity = ({ activityData, onClose }) => { +const UpdateActivity = ({ activity = null, whichService = null, close }) => { const { mutate: updateActivity, isPending: isLoading } = useUpdateActivity(() => onClose?.()); const { @@ -40,10 +40,10 @@ const UpdateActivity = ({ activityData, onClose }) => { } = useForm({ resolver: zodResolver(schema), defaultValues: { - id: activityData?.id, - activityName: activityData?.activityName, - unitOfMeasurement: activityData?.unitOfMeasurement, - checkList: activityData?.checkLists || [], + id: activity?.id, + activityName: activity?.activityName, + unitOfMeasurement: activity?.unitOfMeasurement, + checkList: activity?.checkLists || [], }, }); @@ -53,15 +53,15 @@ const UpdateActivity = ({ activityData, onClose }) => { }); useEffect(() => { - if (activityData) { + if (activity) { reset({ - id: activityData.id, - activityName: activityData.activityName, - unitOfMeasurement: activityData.unitOfMeasurement, - checkList: activityData.checkLists || [], + id: activity.id, + activityName: activity.activityName, + unitOfMeasurement: activity.unitOfMeasurement, + checkList: activity.checkLists || [], }); } - }, [activityData, reset]); + }, [activity, reset]); const addChecklistItem = () => { const values = getValues("checkList"); @@ -91,36 +91,10 @@ const UpdateActivity = ({ activityData, onClose }) => { }; const onSubmit = (formData) => { - const payload = { ...formData, id: activityData.id }; - updateActivity({ id: activityData.id, payload }); + const payload = { ...formData, id: activity.id }; + updateActivity({ id: activity.id, payload }); }; - // 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") - - // 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 ) - - // showToast("error.message", "error"); - // } - // }; useEffect(() => { const tooltipTriggerList = Array.from(document.querySelectorAll('[data-bs-toggle="tooltip"]')); @@ -129,7 +103,6 @@ const UpdateActivity = ({ activityData, onClose }) => { return ( - {/*
Update Activity
*/}
{/* Activity Name */}
diff --git a/src/components/master/Services/ManageActivity.jsx b/src/components/master/Services/ManageActivity.jsx new file mode 100644 index 00000000..e3d0fa2c --- /dev/null +++ b/src/components/master/Services/ManageActivity.jsx @@ -0,0 +1,274 @@ +import React, { useState, useEffect, useCallback } from "react"; +import { useFieldArray, useForm } from "react-hook-form"; +import { z } from "zod"; +import { zodResolver } from "@hookform/resolvers/zod"; + +import { + useCreateActivity, + useUpdateActivity, +} from "../../../hooks/masterHook/useMaster"; +import Label from "../../common/Label"; + +const schema = z.object({ + activityName: z.string().min(1, { message: "Activity Name is required" }), + unitOfMeasurement: z + .string() + .min(1, { message: "Unit of Measurement is required" }), + checkList: z + .array( + z.object({ + description: z + .string() + .min(1, { message: "descriptionlist item cannot be empty" }), + isMandatory: z.boolean().default(false), + id: z.any().default(null), + }) + ) + .optional(), +}); + +const ManageActivity = ({ activity = null, whichGroup = null, close }) => { + const maxDescriptionLength = 255; + const { mutate: createActivity, isPending: isLoading } = useCreateActivity( + () => close?.() + ); + const { mutate: UpdateActivity, isPending: isUpdating } = useUpdateActivity( + () => close?.() + ); + + const { + register, + handleSubmit, + control, + setValue, + clearErrors, + setError, + getValues, + reset, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + defaultValues: { + activityName: "", + unitOfMeasurement: "", + checkList: [], + }, + }); + + const { + fields: checkListItems, + append, + remove, + } = useFieldArray({ + control, + name: "checkList", + }); + + const addChecklistItem = useCallback(() => { + 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 }); + }, [checkListItems, getValues, append, setError, clearErrors]); + + const removeChecklistItem = useCallback( + (index) => { + remove(index); + }, + [remove] + ); + + const handleChecklistChange = useCallback( + (index, value) => { + setValue(`checkList.${index}`, value); + }, + [setValue] + ); + + const onSubmit = (formData) => { + let payload = { + ...formData, + activityGroupId: whichGroup, + }; + if (activity) { + UpdateActivity({ id: activity.id, payload: payload }); + } else { + createActivity(payload); + } + }; + + useEffect(() => { + if (activity) { + reset({ + activityName: activity.activityName || "", + unitOfMeasurement: activity.unitOfMeasurement || "", + checkList: activity.checkLists?.map((check) => ({ + id: check.id || null, // Use the ID provided in the checklist + description: check.description || "", + isMandatory: check.isMandatory || false, + })) || [{ description: "", isMandatory: false }], // Default to an empty checklist item + }); + } + }, [activity, reset]); + const handleClose = useCallback(() => { + reset(); + close(); + }, [reset, close]); + + useEffect(() => { + const tooltipTriggerList = Array.from( + document.querySelectorAll('[data-bs-toggle="tooltip"]') + ); + tooltipTriggerList.forEach((el) => new bootstrap.Tooltip(el)); + }, []); + let isPending = isLoading || isUpdating; + return ( + + {/*
Create Activity
*/} +
+
+ + + {errors.activityName && ( +

{errors.activityName.message}

+ )} +
+ +
+ + + {errors.unitOfMeasurement && ( +

{errors.unitOfMeasurement.message}

+ )} +
+ +
+

+ {checkListItems.length > 0 ? "Check List" : "Add Check List"} +

+ {checkListItems.length > 0 && ( + + + + + + + + + + {checkListItems.map((item, index) => ( + + + + + + ))} + +
+ Name + + Is Mandatory + Action
+ + + handleChecklistChange(index, e.target.value) + } + /> + {errors.checkList?.[index]?.description && ( + + {errors.checkList[index]?.description?.message} + + )} + + + + +
+ )} + +
+ +
+ + +
+
+ + ); +}; + +export default ManageActivity; diff --git a/src/components/master/Services/ManageGroup.jsx b/src/components/master/Services/ManageGroup.jsx index 1a31f2f7..56ec49f5 100644 --- a/src/components/master/Services/ManageGroup.jsx +++ b/src/components/master/Services/ManageGroup.jsx @@ -1,24 +1,57 @@ import { useForm } from "react-hook-form"; -import { useCreateActivityGroup } from "../../../hooks/masterHook/useMaster"; +import { + useCreateActivityGroup, + useUpdateActivityGroup, +} from "../../../hooks/masterHook/useMaster"; import { zodResolver } from "@hookform/resolvers/zod"; import { ActivityGroupSchema } from "./ServicesSchema"; import Label from "../../common/Label"; +import { useEffect } from "react"; -const ManageGroup = ({ group = null, close }) => { +const ManageGroup = ({ group = null, whichService = null, close }) => { const { register, handleSubmit, + reset, formState: { errors }, } = useForm({ resolver: zodResolver(ActivityGroupSchema), defaultValues: { name: "", description: "" }, }); - const { mutate: createGroup, isPending } = useCreateActivityGroup(); + const { mutate: createGroup, isPending: isCreating } = useCreateActivityGroup( + () => close() + ); + const { mutate: UpdateGroup, isPending: isUpdating } = useUpdateActivityGroup( + () => close() + ); - const onSubmit = (payload) => { - console.log(payload); - // createGroup + useEffect(() => { + if (group) { + reset({ + name: group.name || " ", + description: group.description || "", + }); + } + }, [group, reset]); + const onSubmit = (formdata) => { + if (group) { + let payload = { + ...formdata, + serviceId: whichService, + id: group.id, + }; + UpdateGroup({ id: group.id, payload: payload }); + } else { + let payload = { + ...formdata, + serviceId: whichService, + }; + + createGroup(payload); + } }; + + let isPending = isCreating || isUpdating; return (
@@ -28,9 +61,13 @@ const ManageGroup = ({ group = null, close }) => { - {errors.name &&

{errors.name.message}

} + {errors.name && ( +

{errors.name.message}

+ )}
diff --git a/src/hooks/masterHook/useMaster.js b/src/hooks/masterHook/useMaster.js index 7846fa77..9afee253 100644 --- a/src/hooks/masterHook/useMaster.js +++ b/src/hooks/masterHook/useMaster.js @@ -18,16 +18,20 @@ export const useServices = () => { }; export const useGroups = (serviceId) => { - return useQuery({ - queryFn: ["groups", serviceId], + return useQuery({ + queryKey: ["groups", serviceId], queryFn: async () => await MasterRespository.getActivityGrops(serviceId), - }) + enabled: !!serviceId, + }); }; export const useActivitiesByGroups = (groupId) => { - return useQuery({ - queryFn: ["activties", groupId], - queryFn: async () => await MasterRespository.getActivityGrops(groupId), - }) + return useQuery({ + queryKey: ["activties", groupId], + queryFn: async () => await MasterRespository.getActivitesByGroup(groupId), + + enabled: !!groupId, + + }); }; export const useGlobalServices = () => { return useQuery({ @@ -46,8 +50,6 @@ export const useMasterMenu = () => { }); }; - - export const useActivitiesMaster = () => { const { data: activities = [], @@ -446,47 +448,7 @@ export const useUpdateApplicationRole = (onSuccessCallback) => { }); }; -// 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) => { @@ -785,20 +747,23 @@ export const useUpdateService = (onSuccessCallback) => { }); }; -export const useCreateActivityGroup =()=>{ - const queryClient = useQueryClient(); +export const useCreateActivityGroup = (onSuccessCallback) => { + const queryClient = useQueryClient(); return useMutation({ mutationFn: async (payload) => { - const response = await MasterRespository.createActivityGroup(payload) + const response = await MasterRespository.createActivityGroup(payload); return response; }, onSuccess: (data, variables) => { queryClient.invalidateQueries({ - queryKey: ["masterData", "Services"], + queryKey: ["groups"], }); - showToast(data.message || "Activity Group created successfully.", "success"); + showToast( + data.message || "Activity Group created successfully.", + "success" + ); if (onSuccessCallback) onSuccessCallback(data); }, @@ -806,7 +771,73 @@ export const useCreateActivityGroup =()=>{ showToast(error?.message || "Something went wrong", "error"); }, }); -} +}; +export const useUpdateActivityGroup = (onSuccessCallback) => { + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async ({id,payload}) => { + const response = await MasterRespository.updateActivityGrop(id,payload); + return response; + }, + onSuccess: (data, variables) => { + queryClient.invalidateQueries({ + queryKey: ["groups"], + }); + + showToast( + data.message || "Activity Group 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: ["activties"] }); + 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: ["activties"], + }); + showToast("Activity updated successfully.", "success"); + + if (onSuccessCallback) onSuccessCallback(data); + }, + onError: (error) => { + showToast(error.message || "Something went wrong", "error"); + }, + }); +}; // -------------------Expense Status---------------------------------- export const useCreateExpenseStatus = (onSuccessCallback) => { @@ -969,3 +1000,48 @@ export const useDeleteMasterItem = () => { }, }); }; + + +export const useDeleteServiceGroup =()=>{ + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (id)=>await MasterRespository.deleteActivityGroup(id), + onSuccess: ({_,variable}) => { + + queryClient.invalidateQueries({ queryKey: ["groups"] }); + + showToast(`Group deleted successfully.`, "success"); + }, + + onError: (error) => { + const message = + error?.response?.data?.message || + error?.message || + "Error occurred during deletion"; + showToast(message, "error"); + }, + }); +} +export const useDeleteActivity =()=>{ + const queryClient = useQueryClient(); + + return useMutation({ + mutationFn: async (id)=>await MasterRespository.deleteActivity(id), + onSuccess: ({_,variable}) => { + + + queryClient.invalidateQueries({ queryKey: ["activties"] }); + + showToast(`Acivity deleted successfully.`, "success"); + }, + + onError: (error) => { + const message = + error?.response?.data?.message || + error?.message || + "Error occurred during deletion"; + showToast(message, "error"); + }, + }); +} diff --git a/src/pages/master/MasterPage.jsx b/src/pages/master/MasterPage.jsx index b187efd1..323e3442 100644 --- a/src/pages/master/MasterPage.jsx +++ b/src/pages/master/MasterPage.jsx @@ -1,4 +1,4 @@ -import React, { useState, useMemo, useEffect } from "react"; +import React, { useState, useMemo, useEffect, createContext, useContext } from "react"; import { useDispatch, useSelector } from "react-redux"; import { useQueryClient } from "@tanstack/react-query"; import Breadcrumb from "../../components/common/Breadcrumb"; @@ -6,7 +6,9 @@ import MasterModal from "../../components/master/MasterModal"; import ConfirmModal from "../../components/common/ConfirmModal"; import MasterTable from "./MasterTable"; import useMaster, { + useDeleteActivity, useDeleteMasterItem, + useDeleteServiceGroup, useMasterMenu, } from "../../hooks/masterHook/useMaster"; import { changeMaster } from "../../slices/localVariablesSlice"; @@ -14,6 +16,16 @@ import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { MANAGE_MASTER } from "../../utils/constants"; import GlobalModel from "../../components/common/GlobalModel"; + +export const MasterContext = createContext(); +export const useMasterContext = () => { + const context = useContext(MasterContext); + if (!context) { + throw new Error("useMasterContext must be used within an MasterProvider"); + } + return context; +}; + const MasterPage = () => { const dispatch = useDispatch(); const queryClient = useQueryClient(); @@ -34,6 +46,9 @@ const MasterPage = () => { isError: isMasterError, } = useMaster(); const { mutate: DeleteMaster, isPending: isDeleting } = useDeleteMasterItem(); + const [isDeleletingServiceItem,setDeleletingServiceItem] = useState({isOpen:false,ItemId:null,whichItem:null}) + const {mutate:DeleteSericeGroup,isPending:deletingGroup} =useDeleteServiceGroup() + const {mutate:DeleteAcivity,isPending:deletingActivity} = useDeleteActivity() const [modalConfig, setModalConfig] = useState(null); const [deleteData, setDeleteData] = useState(null); @@ -73,6 +88,18 @@ const MasterPage = () => { ); }; + + const handleDeleteServiceItem =()=>{ + if(!isDeleletingServiceItem.ItemId) return + if(isDeleletingServiceItem.whichItem == "activiy"){ + DeleteAcivity(isDeleletingServiceItem.ItemId,{onSuccess:()=>setDeleletingServiceItem({isOpen:false,ItemId:null,whichItem:null})}) + }else{ + DeleteSericeGroup(isDeleletingServiceItem.ItemId,{onSuccess:()=>setDeleletingServiceItem({isOpen:false,ItemId:null,whichItem:null})}) + } + + + } + if (menuErrorFlag || isMasterError) return (
@@ -87,7 +114,7 @@ const MasterPage = () => { ); return ( - <> + {modalConfig && ( { /> )} + { onSubmit={handleDeleteSubmit} onClose={() => setDeleteData(null)} /> + + setDeleletingServiceItem({isOpen:false,ItemId:null,whichItem:null})} + />
{
- + ); }; diff --git a/src/repositories/MastersRepository.jsx b/src/repositories/MastersRepository.jsx index 00778dc1..3e9fac8f 100644 --- a/src/repositories/MastersRepository.jsx +++ b/src/repositories/MastersRepository.jsx @@ -32,11 +32,11 @@ export const MasterRespository = { getActivites: () => api.get("api/master/activities"), createActivity: (data) => api.post("api/master/activity", data), -//Services + //Services getService: () => api.get("api/master/service/list"), createService: (data) => api.post("api/master/service/create", data), updateService: (id, data) => api.put(`api/master/service/edit/${id}`, data), - "Services": (id) => api.delete(`/api/master/service/delete/${id}`), + Services: (id) => api.delete(`/api/master/service/delete/${id}`), updateActivity: (id, data) => api.post(`api/master/activity/edit/${id}`, data), @@ -114,15 +114,20 @@ export const MasterRespository = { updateDocumentType: (id, data) => api.put(`/api/Master/document-type/edit/${id}`, data), + getGlobalServices: () => api.get("/api/Master/global-service/list"), + getMasterServices: () => api.get("/api/Master/service/list"), + getActivityGrops: (serviceId) => + api.get(`/api/Master/activity-group/list?serviceId=${serviceId}`), + createActivityGroup: (data) => + api.post(`/api/Master/activity-group/create`, data), + updateActivityGrop: (serviceId, data) => + api.put(`/api/Master/activity-group/edit/${serviceId}`, data), + getActivitesByGroup: (activityGroupId) => + api.get(`api/master/activities?activityGroupId=${activityGroupId}`), + deleteActivityGroup:(id)=>api.delete(`/api/Master/activity-group/delete/${id}`), - getGlobalServices:()=>api.get("/api/Master/global-service/list"), - getMasterServices:()=>api.get("/api/Master/service/list"), - getActivityGrops:(serviceId)=>api.get(`/api/Master/activity-group/list?serviceId=${serviceId}`), - createActivityGroup:(data)=>api.post(`/api/Master/activity-group/create`), - getActivitesByGroup: (serviceId) => api.get(`api/master/activities/activityGroupId=${activityGroupId}`), + deleteActivity:(id)=>api.delete(`/api/Master/activity/delete/${id}`), - - - getOrganizationType:()=>api.get('/api/Master/organization-type/list') + getOrganizationType: () => api.get("/api/Master/organization-type/list"), }; -- 2.43.0 From 4e315aafcf4b5710f937862dc73b1cc0443899a4 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 24 Sep 2025 12:49:00 +0530 Subject: [PATCH 70/74] added small ui changed like table b-padding, button size and fixd delete activity and group --- src/components/Organization/AssignOrg.jsx | 2 +- .../Organization/OrgPickerFromSPId.jsx | 15 +++-- .../Organization/OrgPickerfromTenant.jsx | 57 ++++++++++++------- .../Organization/OrganizationModal.jsx | 2 +- .../Organization/OrganizationsList.jsx | 2 +- .../ProjectAssignedOrgs.jsx | 18 ++++-- .../Project/ProjectOrganizations.jsx | 4 +- .../master/Services/ManageActivity.jsx | 51 ++++++++--------- .../master/Services/ManageGroup.jsx | 2 +- .../master/Services/ServicesGroups.jsx | 12 ++-- src/hooks/masterHook/useMaster.js | 19 ++++--- src/pages/Organization/OrganizationPage.jsx | 2 +- src/pages/master/MasterPage.jsx | 3 +- 13 files changed, 106 insertions(+), 83 deletions(-) diff --git a/src/components/Organization/AssignOrg.jsx b/src/components/Organization/AssignOrg.jsx index 270fac0d..c460de9b 100644 --- a/src/components/Organization/AssignOrg.jsx +++ b/src/components/Organization/AssignOrg.jsx @@ -248,7 +248,7 @@ const AssignOrg = ({ setStep }) => { ? "Please wait..." : flowType === "default" ? "Assign Organization" - : "Add"} + : "Assign Project"}
diff --git a/src/components/Organization/OrgPickerFromSPId.jsx b/src/components/Organization/OrgPickerFromSPId.jsx index e0bdced0..0a46778c 100644 --- a/src/components/Organization/OrgPickerFromSPId.jsx +++ b/src/components/Organization/OrgPickerFromSPId.jsx @@ -84,10 +84,7 @@ const OrgPickerFromSPId = ({ title, placeholder }) => { height={50} /> -
onOpen({ startStep: 3, orgData: org })} - > +
{org.name}
{ Address:
{org.address}
+
+ {" "} + +
))} diff --git a/src/components/Organization/OrgPickerfromTenant.jsx b/src/components/Organization/OrgPickerfromTenant.jsx index 5471df2b..7d39fa60 100644 --- a/src/components/Organization/OrgPickerfromTenant.jsx +++ b/src/components/Organization/OrgPickerfromTenant.jsx @@ -85,7 +85,7 @@ const OrgPickerfromTenant = ({ title }) => { {isLoading ? (
Loading....
) : data && data?.data?.length > 0 ? ( -
+
@@ -99,28 +99,41 @@ const OrgPickerfromTenant = ({ title }) => { - - {Array.isArray(data.data) && data.data.length > 0 - ? data.data.map((row, i) => ( - - {contactList.map((col) => ( - - ))} - - - )) - : null} -
- {col.getValue(row)} - - -
+ +
+ + + {Array.isArray(data.data) && data.data.length > 0 + ? data.data.map((row, i) => ( + + {contactList.map((col) => ( + + ))} + + + )) + : null} + +
+ {col.getValue(row)} + +
+ +
+
+
) : null}
diff --git a/src/components/Organization/OrganizationModal.jsx b/src/components/Organization/OrganizationModal.jsx index da742427..7361c41f 100644 --- a/src/components/Organization/OrganizationModal.jsx +++ b/src/components/Organization/OrganizationModal.jsx @@ -60,7 +60,7 @@ const OrganizationModal = () => { if (startStep === 1) { return orgData && orgData !== null ? "Add Organization" - : "Choose Organization1"; + : "Choose Organization"; } if (startStep === 2) { diff --git a/src/components/Organization/OrganizationsList.jsx b/src/components/Organization/OrganizationsList.jsx index d5243e87..b7ea28e5 100644 --- a/src/components/Organization/OrganizationsList.jsx +++ b/src/components/Organization/OrganizationsList.jsx @@ -93,7 +93,7 @@ const OrganizationsList = ({searchText}) => { if (isError) return
{error?.message || "Something went wrong"}
; return ( -
+
diff --git a/src/components/Project/ProjectOrganization/ProjectAssignedOrgs.jsx b/src/components/Project/ProjectOrganization/ProjectAssignedOrgs.jsx index 4625a30b..53a2365a 100644 --- a/src/components/Project/ProjectOrganization/ProjectAssignedOrgs.jsx +++ b/src/components/Project/ProjectOrganization/ProjectAssignedOrgs.jsx @@ -7,7 +7,7 @@ const ProjectAssignedOrgs = () => { const { data, isLoading, isError, error } = useProjectAssignedOrganizations(selectedProject); - const contactList = [ + const orgList = [ { key: "name", label: "Organization Name", @@ -23,6 +23,16 @@ const ProjectAssignedOrgs = () => { ), align: "text-start", + }, + { + key: "service", + label: "Service Name", + getValue: (org) => ( +
+ N/A +
+ ), + align: "text-start", }, { key: "sprid", @@ -61,7 +71,7 @@ const ProjectAssignedOrgs = () => {
- {contactList.map((col) => ( + {orgList.map((col) => ( @@ -72,7 +82,7 @@ const ProjectAssignedOrgs = () => { {Array.isArray(data) && data.length > 0 ? ( data.map((row, i) => ( - {contactList.map((col) => ( + {orgList.map((col) => ( @@ -82,7 +92,7 @@ const ProjectAssignedOrgs = () => { ) : (
{col.label}
{col.getValue(row)}
Not Assigned yet diff --git a/src/components/Project/ProjectOrganizations.jsx b/src/components/Project/ProjectOrganizations.jsx index d18a9375..b5a91fa6 100644 --- a/src/components/Project/ProjectOrganizations.jsx +++ b/src/components/Project/ProjectOrganizations.jsx @@ -7,12 +7,12 @@ const ProjectOrganizations = () => { const { onOpen, startStep, flowType } = useOrganizationModal(); const selectedProject = useSelectedProject(); return ( -
+
+ ):(

Not Yet Added

)} +
-
diff --git a/src/components/master/Services/ManageGroup.jsx b/src/components/master/Services/ManageGroup.jsx index 56ec49f5..04342777 100644 --- a/src/components/master/Services/ManageGroup.jsx +++ b/src/components/master/Services/ManageGroup.jsx @@ -53,7 +53,7 @@ const ManageGroup = ({ group = null, whichService = null, close }) => { let isPending = isCreating || isUpdating; return ( - +