From 6baa2896c2f336654d9401c25a14581e321bb6d5 Mon Sep 17 00:00:00 2001 From: pramod mahajan Date: Mon, 15 Sep 2025 16:27:06 +0530 Subject: [PATCH 1/7] 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 2/7] 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 3/7] 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 = ( + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ +