From 6baa2896c2f336654d9401c25a14581e321bb6d5 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Mon, 15 Sep 2025 16:27:06 +0530 Subject: [PATCH 01/65] 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 From e0c7eee1fd65e4795906d0e23bf370dcb9a84e82 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Mon, 15 Sep 2025 18:25:12 +0530 Subject: [PATCH 02/65] 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, + }, }); From d944d3a389c9d1548d1cbed45e0836cabc3981b9 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Mon, 15 Sep 2025 19:56:45 +0530 Subject: [PATCH 03/65] 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"), From af5519fd6005e98cc43d085fa889e299b58163e8 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 14:53:40 +0530 Subject: [PATCH 24/65] 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 && (
From ea219b717696cf618678abaa53789f73ea1f074d Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 15:03:25 +0530 Subject: [PATCH 25/65] 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 = { From e154bac64a0ddadb36fc1377af6d8d1a5b726dc1 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 15:54:29 +0530 Subject: [PATCH 27/65] 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 && ( From 7d17422681e73d55e1720203bcd569ce5a733470 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 16:02:36 +0530 Subject: [PATCH 28/65] 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/65] 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
)} From e9d8b6daea9f1b0cdf4ad976f4d5f3f7f4ad768d Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 16:43:44 +0530 Subject: [PATCH 31/65] 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 --- */}
From 164b82e1c79f0a3372e3a858dad71960bf785649 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 17:00:02 +0530 Subject: [PATCH 32/65] 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/65] 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) */}
From 00d6774e06c95111b3e1710db62d19d02d4c679f Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 19:26:46 +0530 Subject: [PATCH 35/65] 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 && (
From 27b62c858df737cb29933ff26f404576d294d6b8 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 19:50:50 +0530 Subject: [PATCH 36/65] 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 From 9223f7a1768ea61544224d76bce87212d2965fc7 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 19 Sep 2025 20:03:36 +0530 Subject: [PATCH 37/65] 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
+ )} +
+
); }; From 005fdb3490df5af1e81c0e9e83be4d8e31ba1893 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Fri, 19 Sep 2025 23:46:06 +0530 Subject: [PATCH 38/65] 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}} +
+ +
+ +