From c0ac2295d05b390aba23a82484ea31d3b1c507e7 Mon Sep 17 00:00:00 2001 From: Vikas Nale Date: Mon, 12 May 2025 10:35:23 +0530 Subject: [PATCH 01/13] Remove warnings ref: https://reactrouter.com/6.30.0/upgrading/future#v7_starttransition --- src/router/AppRoutes.jsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/router/AppRoutes.jsx b/src/router/AppRoutes.jsx index ad38bc2d..6fbeefa0 100644 --- a/src/router/AppRoutes.jsx +++ b/src/router/AppRoutes.jsx @@ -51,7 +51,7 @@ const router = createBrowserRouter( }, { element: , - errorElement:, + errorElement: , children: [ { element: , @@ -90,6 +90,10 @@ const router = createBrowserRouter( future: { v7_relativeSplatPath: true, v7_startTransition: true, + v7_fetcherPersist: true, + v7_normalizeFormMethod: true, + v7_partialHydration: true, + v7_skipActionErrorRevalidation: true, }, } ); From b39effe4b012f26473d1de2b1af1b8a8c97594da Mon Sep 17 00:00:00 2001 From: "ashutosh.nehete" Date: Mon, 12 May 2025 13:11:29 +0530 Subject: [PATCH 02/13] Added a Work Category dropdown in task create/update forms and a new column to display the category in Project Infrastructure and Daily Task Planning views. --- .../Infrastructure/EditActivityModal.jsx | 86 +++++++++--- .../Project/Infrastructure/TaskModel.jsx | 125 +++++++++++++----- .../Project/Infrastructure/WorkArea.jsx | 3 + .../Project/Infrastructure/WorkItem.jsx | 9 ++ src/hooks/masterHook/useMaster.js | 35 ++++- 5 files changed, 210 insertions(+), 48 deletions(-) diff --git a/src/components/Project/Infrastructure/EditActivityModal.jsx b/src/components/Project/Infrastructure/EditActivityModal.jsx index e8927ae3..43724307 100644 --- a/src/components/Project/Infrastructure/EditActivityModal.jsx +++ b/src/components/Project/Infrastructure/EditActivityModal.jsx @@ -3,7 +3,7 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; -import { useActivitiesMaster } from "../../../hooks/masterHook/useMaster"; +import { useActivitiesMaster, useWorkCategoriesMaster } from "../../../hooks/masterHook/useMaster"; import { useProjectDetails } from "../../../hooks/useProjects"; import { useDispatch, useSelector } from "react-redux"; import ProjectRepository from "../../../repositories/ProjectRepository"; @@ -18,6 +18,7 @@ import showToast from "../../../services/toastService"; const taskSchema = z .object({ activityID: z.string().min(1, "Activity is required"), + workCategoryId: z.string().min(1, "Work Category is required"), plannedWork: z.number().min(1, "Planned Work must be greater than 0"), completedWork: z.number().min(0, "Completed Work must be greater than 0"), }) @@ -43,17 +44,21 @@ const EditActivityModal = ({ ); const defaultModel = { activityID: 0, + workCategoryId: 0, plannedWork: 0, completedWork: 0, }; - const {projects_Details, refetch} = useProjectDetails( selectedProject ); - const [ActivityUnit,setActivityUnit]= useState("") + const { projects_Details, refetch } = useProjectDetails(selectedProject); + const [ActivityUnit, setActivityUnit] = useState(""); const { activities, loading, error } = useActivitiesMaster(); + const { categories, categoryLoading, categoryError } = + useWorkCategoriesMaster(); const [formData, setFormData] = useState(defaultModel); const [selectedActivity, setSelectedActivity] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [activityData, setActivityData] = useState([]); + const [categoryData, setCategoryData] = useState([]); const dispatch = useDispatch(); const { @@ -70,12 +75,19 @@ const EditActivityModal = ({ }); const handleActivityChange = (e) => { - const selectedId = Number(e.target.value); + const selectedId = String(e.target.value); const selected = activityData.find((a) => a.id === selectedId); setSelectedActivity(selected || null); setValue("activityID", selectedId); }; + const handleCategoryChange = (e) => { + const selectedId = String(e.target.value); + const category = categoryData.find((b) => b.id === selectedId); + setSelectedCategory(category || null); + setValue("workCategoryId", selectedId); + }; + const onSubmitForm = async (data) => { const updatedProject = { ...projects_Details }; const finalData = { @@ -141,14 +153,14 @@ const EditActivityModal = ({ data: newProject, }); resetForm(); - dispatch( refreshData( true ) ); - showToast("Activity Updated Successfully","success") + dispatch(refreshData(true)); + showToast("Activity Updated Successfully", "success"); onClose(); } }) .catch((error) => { - showToast(error.message, "error"); + showToast(error?.response?.data?.message || error.message, "error"); }); }; @@ -161,6 +173,8 @@ const EditActivityModal = ({ useEffect(() => { reset({ activityID: workItem?.workItem?.activityId || workItem?.activityId || 0, + workCategoryId: + workItem?.workItem?.workCategoryId || workItem?.workCategoryId || 0, plannedWork: workItem?.workItem?.plannedWork || workItem?.plannedWork || 0, completedWork: @@ -171,14 +185,13 @@ const EditActivityModal = ({ const ISselectedActivity = watch("activityID"); useEffect(() => { - if( ISselectedActivity ){ + if (ISselectedActivity) { const selected = activities.find((a) => a.id === ISselectedActivity); - setSelectedActivity( selected || null ); - setActivityUnit(selected?.unitOfMeasurement) - } - }, [ ISselectedActivity,activities] ); - - + setSelectedActivity(selected || null); + setActivityUnit(selected?.unitOfMeasurement); + } + }, [ISselectedActivity, activities]); + return (
@@ -273,6 +286,45 @@ const EditActivityModal = ({ )}
+ {/* Select Category */} +
+ + + + {errors.workCategoryId && ( +

{errors.workCategoryId.message}

+ )} +
+ {/* Planned Work */} {/* {ISselectedActivity && ( */}
@@ -327,7 +379,11 @@ const EditActivityModal = ({ {/* )} */}
-
@@ -250,15 +258,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => { name="FirstName" {...register("firstName")} className="form-control form-control-sm" - id="FirstName" + id="firstName" placeholder="First Name" /> - {errors.FirstName && ( + {errors.firstName && (
- {errors.FirstName.message} + {errors.firstName.message}
)}
{" "} @@ -269,15 +277,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => { type="text" {...register("middleName")} className="form-control form-control-sm" - id="MiddleName" + id="middleName" placeholder="Middle Name" /> - {errors.MiddleName && ( + {errors.middleName && (
- {errors.MiddleName.message} + {errors.middleName.message}
)}
@@ -287,15 +295,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => { type="text" {...register("lastName")} className="form-control form-control-sm" - id="LastName" + id="lastName" placeholder="Last Name" /> - {errors.LastName && ( + {errors.lastName && (
- {errors.LastName.message} + {errors.lastName.message}
)}
@@ -305,7 +313,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
Email
{ aria-describedby="Email" disabled={!!currentEmployee?.email} /> - {errors.Email && ( + {errors.email && (
- {errors.Email.message} + {errors.email.message}
)} @@ -327,19 +335,19 @@ const ManageEmployee = ({ employeeId, onClosed }) => { - {errors.PhoneNumber && ( + {errors.phoneNumber && (
- {errors.PhoneNumber.message} + {errors.phoneNumber.message}
)} @@ -353,7 +361,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => { - {errors.Gender && ( + {errors.gender && (
- {errors.Gender.message} + {errors.gender.message}
)} @@ -381,15 +389,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => { className="form-control form-control-sm" type="date" {...register("birthDate")} - id="BirthDate" + id="birthDate" /> - {errors.BirthDate && ( + {errors.birthDate && (
- {errors.BirthDate.message} + {errors.birthDate.message}
)} @@ -401,15 +409,15 @@ const ManageEmployee = ({ employeeId, onClosed }) => { className="form-control form-control-sm" type="date" {...register("joiningDate")} - id="JoiningDate" + id="joiningDate" /> - {errors.JoiningDate && ( + {errors.joiningDate && (
- {errors.JoiningDate.message} + {errors.joiningDate.message}
)} @@ -419,7 +427,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
Current Address
@@ -438,12 +446,12 @@ const ManageEmployee = ({ employeeId, onClosed }) => { {500 - currentAddressLength} characters left
- {errors.CurrentAddress && ( + {errors.currentAddress && (
- {errors.CurrentAddress.message} + {errors.currentAddress.message}
)} @@ -453,7 +461,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
@@ -470,12 +478,12 @@ const ManageEmployee = ({ employeeId, onClosed }) => { {500 - permanentAddressLength} characters left
- {errors.PermanentAddress && ( + {errors.permanentAddress && (
- {errors.PermanentAddress.message} + {errors.permanentAddress.message}
)} @@ -493,7 +501,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => { - {errors.JobRoleId && ( + {errors.jobRoleId && (
- {errors.JobRoleId.message} + {errors.jobRoleId.message}
)} @@ -523,16 +531,16 @@ const ManageEmployee = ({ employeeId, onClosed }) => { type="text" {...register("emergencyContactPerson")} className="form-control form-control-sm" - id="EmergencyContactPerson" + id="emergencyContactPerson" maxLength={50} placeholder="Contact Person" /> - {errors.EmergencyContactPerson && ( + {errors.emergencyContactPerson && (
- {errors.EmergencyContactPerson.message} + {errors.emergencyContactPerson.message}
)} @@ -544,17 +552,17 @@ const ManageEmployee = ({ employeeId, onClosed }) => { type="text" {...register("emergencyPhoneNumber")} className="form-control form-control-sm phone-mask" - id="EmergencyPhoneNumber" + id="emergencyPhoneNumber" placeholder="Phone Number" inputMode="numeric" maxLength={10} /> - {errors.EmergencyPhoneNumber && ( + {errors.emergencyPhoneNumber && (
- {errors.EmergencyPhoneNumber.message} + {errors.emergencyPhoneNumber.message}
)} @@ -567,14 +575,14 @@ const ManageEmployee = ({ employeeId, onClosed }) => { type="text" {...register("aadharNumber")} className="form-control form-control-sm" - id="AadharNumber" + id="aadharNumber" placeholder="AADHAR Number" maxLength={12} inputMode="numeric" /> - {errors.AadharNumber && ( + {errors.aadharNumber && (
- {errors.AadharNumber.message} + {errors.aadharNumber.message}
)} @@ -585,16 +593,16 @@ const ManageEmployee = ({ employeeId, onClosed }) => { type="text" {...register("panNumber")} className="form-control form-control-sm" - id="PanNumber" + id="panNumber" placeholder="PAN Number" maxLength={10} /> - {errors.PanNumber && ( + {errors.panNumber && (
- {errors.PanNumber.message} + {errors.panNumber.message}
)} diff --git a/src/hooks/useEmployees.js b/src/hooks/useEmployees.js index 5aec3cf2..7a70c365 100644 --- a/src/hooks/useEmployees.js +++ b/src/hooks/useEmployees.js @@ -209,9 +209,15 @@ export const useEmployeesAllOrByProjectId = (projectId, showInactive) => { export const useEmployeeProfile = (employeeId) => { const [loading, setLoading] = useState(true); const [error, setError] = useState(); - const [employee, setEmployees] = useState(); + const [employee, setEmployees] = useState(null); const fetchData = async () => { + if (!employeeId) { + // Reset the state if no employeeId (e.g., opening for 'add' mode) + setEmployees(null); + setLoading(false); + return; + } const Employee_cache = getCachedData("employeeProfile"); if (!Employee_cache || Employee_cache.employeeId !== employeeId) { EmployeeRepository.getEmployeeProfile(employeeId) @@ -231,9 +237,7 @@ export const useEmployeeProfile = (employeeId) => { }; useEffect(() => { - if (employeeId) { - fetchData(employeeId); - } + fetchData(); }, [employeeId]); return { employee, loading, error }; diff --git a/src/pages/employee/EmployeeList.jsx b/src/pages/employee/EmployeeList.jsx index c0b75275..f31cff37 100644 --- a/src/pages/employee/EmployeeList.jsx +++ b/src/pages/employee/EmployeeList.jsx @@ -43,7 +43,7 @@ const EmployeeList = () => { const [searchText, setSearchText] = useState(""); const [filteredData, setFilteredData] = useState([]); const [showModal, setShowModal] = useState(false); - const [selectedEmployeeId, setSelecedEmployeeId] = useState(); + const [selectedEmployeeId, setSelecedEmployeeId] = useState(null); const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false); const [selectedEmpFordelete, setSelectedEmpFordelete] = useState(null); const [employeeLodaing, setemployeeLodaing] = useState(false); @@ -111,6 +111,8 @@ const EmployeeList = () => { document.querySelector(".modal-backdrop").remove(); } setShowModal(false); + clearCacheKey("employeeProfile"); + recallEmployeeData(showInactive); }; const handleShow = () => setShowModal(true); const handleClose = () => setShowModal(false); @@ -193,7 +195,7 @@ const EmployeeList = () => { {isCreateModalOpen && ( )} -
{ />
- + )} {IsDeleteModalOpen && (
Date: Mon, 12 May 2025 13:11:29 +0530 Subject: [PATCH 09/13] Added a Work Category dropdown in task create/update forms and a new column to display the category in Project Infrastructure and Daily Task Planning views. --- .../Infrastructure/EditActivityModal.jsx | 76 +++++++++-- .../Project/Infrastructure/TaskModel.jsx | 125 +++++++++++++----- .../Project/Infrastructure/WorkArea.jsx | 3 + .../Project/Infrastructure/WorkItem.jsx | 9 ++ src/hooks/masterHook/useMaster.js | 35 ++++- 5 files changed, 203 insertions(+), 45 deletions(-) diff --git a/src/components/Project/Infrastructure/EditActivityModal.jsx b/src/components/Project/Infrastructure/EditActivityModal.jsx index 60c5403c..e539df96 100644 --- a/src/components/Project/Infrastructure/EditActivityModal.jsx +++ b/src/components/Project/Infrastructure/EditActivityModal.jsx @@ -3,7 +3,7 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; -import { useActivitiesMaster } from "../../../hooks/masterHook/useMaster"; +import { useActivitiesMaster, useWorkCategoriesMaster } from "../../../hooks/masterHook/useMaster"; import { useProjectDetails } from "../../../hooks/useProjects"; import { useDispatch, useSelector } from "react-redux"; import ProjectRepository from "../../../repositories/ProjectRepository"; @@ -18,6 +18,7 @@ import showToast from "../../../services/toastService"; const taskSchema = z .object({ activityID: z.string().min(1, "Activity is required"), + workCategoryId: z.string().min(1, "Work Category is required"), plannedWork: z.number().min(1, "Planned Work must be greater than 0"), completedWork: z.number().min(0, "Completed Work must be greater than 0"), }) @@ -43,17 +44,21 @@ const EditActivityModal = ({ ); const defaultModel = { activityID: 0, + workCategoryId: 0, plannedWork: 0, completedWork: 0, }; - const {projects_Details, refetch} = useProjectDetails( selectedProject ); - const [ActivityUnit,setActivityUnit]= useState("") + const { projects_Details, refetch } = useProjectDetails(selectedProject); + const [ActivityUnit, setActivityUnit] = useState(""); const { activities, loading, error } = useActivitiesMaster(); + const { categories, categoryLoading, categoryError } = + useWorkCategoriesMaster(); const [formData, setFormData] = useState(defaultModel); const [selectedActivity, setSelectedActivity] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [activityData, setActivityData] = useState([]); + const [categoryData, setCategoryData] = useState([]); const dispatch = useDispatch(); const { @@ -70,12 +75,19 @@ const EditActivityModal = ({ }); const handleActivityChange = (e) => { - const selectedId = Number(e.target.value); - const selected = activityData.find( ( a ) => a.id === selectedId ); + const selectedId = String(e.target.value); + const selected = activityData.find((a) => a.id === selectedId); setSelectedActivity(selected || null); setValue("activityID", selectedId); }; + const handleCategoryChange = (e) => { + const selectedId = String(e.target.value); + const category = categoryData.find((b) => b.id === selectedId); + setSelectedCategory(category || null); + setValue("workCategoryId", selectedId); + }; + const onSubmitForm = async ( data ) => { setIsSubmitting(true) @@ -167,6 +179,8 @@ const EditActivityModal = ({ useEffect(() => { reset({ activityID: workItem?.workItem?.activityId || workItem?.activityId || 0, + workCategoryId: + workItem?.workItem?.workCategoryId || workItem?.workCategoryId || 0, plannedWork: workItem?.workItem?.plannedWork || workItem?.plannedWork || 0, completedWork: @@ -177,14 +191,13 @@ const EditActivityModal = ({ const ISselectedActivity = watch("activityID"); useEffect(() => { - if( ISselectedActivity ){ + if (ISselectedActivity) { const selected = activities.find((a) => a.id === ISselectedActivity); - setSelectedActivity( selected || null ); - setActivityUnit(selected?.unitOfMeasurement) - } - }, [ ISselectedActivity,activities] ); - - + setSelectedActivity(selected || null); + setActivityUnit(selected?.unitOfMeasurement); + } + }, [ISselectedActivity, activities]); + return (
@@ -279,6 +292,45 @@ const EditActivityModal = ({ )}
+ {/* Select Category */} +
+ + + + {errors.workCategoryId && ( +

{errors.workCategoryId.message}

+ )} +
+ {/* Planned Work */} {/* {ISselectedActivity && ( */}
diff --git a/src/components/Project/Infrastructure/TaskModel.jsx b/src/components/Project/Infrastructure/TaskModel.jsx index 43cb1c5b..087a731e 100644 --- a/src/components/Project/Infrastructure/TaskModel.jsx +++ b/src/components/Project/Infrastructure/TaskModel.jsx @@ -2,23 +2,28 @@ import React, { useState, useEffect } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; -import {useActivitiesMaster} from "../../../hooks/masterHook/useMaster"; +import { + useActivitiesMaster, + useWorkCategoriesMaster, +} from "../../../hooks/masterHook/useMaster"; const taskSchema = z.object({ buildingID: z.string().min(1, "Building is required"), floorId: z.string().min(1, "Floor is required"), workAreaId: z.string().min(1, "Work Area is required"), activityID: z.string().min(1, "Activity is required"), + workCategoryId: z.string().min(1, "Work Category is required"), plannedWork: z.number().min(1, "Planned Work must be greater than 0"), completedWork: z.number().min(0, "Completed Work must be greater than 0"), }); const defaultModel = { id: null, - buildingID:"0", + buildingID: "0", floorId: "0", workAreaId: "0", activityID: null, + workCategoryId: "", plannedWork: 0, completedWork: 0, }; @@ -30,15 +35,18 @@ const TaskModel = ({ onClearComplete, onClose, }) => { - const [formData, setFormData] = useState(defaultModel); const [selectedBuilding, setSelectedBuilding] = useState(null); const [selectedFloor, setSelectedFloor] = useState(null); const [selectedWorkArea, setSelectedWorkArea] = useState(null); const [selectedActivity, setSelectedActivity] = useState(null); + const [selectedCategory, setSelectedCategory] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); const [activityData, setActivityData] = useState([]); - const {activities, loading, error} = useActivitiesMaster(); + const [categoryData, setCategoryData] = useState([]); + const { activities, loading, error } = useActivitiesMaster(); + const { categories, categoryLoading, categoryError } = + useWorkCategoriesMaster(); const { register, @@ -79,6 +87,7 @@ const TaskModel = ({ floorId: value, workAreaId: 0, activityID: 0, + workCategoryId: categoryData?.[0]?.id?.toString() ?? "", })); }; @@ -104,13 +113,24 @@ const TaskModel = ({ })); }; - const onSubmitForm = async ( data ) => - { + const handleCategoryChange = (e) => { + const { value } = e.target; + const category = categoryData.find((b) => b.id === String(value)); + setSelectedCategory(category); + reset((prev) => ({ + ...prev, + workCategoryId: String(value), + })); + }; + + const onSubmitForm = async (data) => { + console.log(data); setIsSubmitting(true); await onSubmit(data); setValue("plannedWork", 0); - setValue( "completedWork", 0 ); - setValue("activityID",0) + setValue("completedWork", 0); + setValue("activityID", 0); + setValue("workCategoryId", categoryData?.[0]?.id?.toString() ?? ""); setIsSubmitting(false); }; @@ -120,15 +140,32 @@ const TaskModel = ({ setSelectedFloor(null); setSelectedWorkArea(null); setSelectedActivity(null); + setSelectedCategory(categoryData?.[0]?.id?.toString() ?? ""); reset(defaultModel); }; useEffect(() => { if (!loading && Array.isArray(activities) && activities.length > 0) { - setActivityData(activities); } }, [activities, loading]); + + useEffect(() => { + if ( + !categoryLoading && + Array.isArray(categories) && + categories.length > 0 + ) { + const newCategories = categories?.slice()?.sort((a, b) => { + const nameA = a?.name || ""; + const nameB = b?.name || ""; + return nameA.localeCompare(nameB); + }); + setCategoryData(newCategories); + setSelectedCategory(newCategories[0]) + } + }, [categories, categoryLoading]); + return (
@@ -247,9 +284,7 @@ const TaskModel = ({ {selectedWorkArea && (
- + {errors.activityID && ( @@ -287,7 +319,38 @@ const TaskModel = ({
)} - {selectedActivity && ( + {selectedWorkArea && ( +
+ + + + {errors.workCategoryId && ( +

+ {errors.workCategoryId.message} +

+ )} +
+ )} + + {selectedActivity && selectedCategory && (
)} - {selectedActivity && ( + {selectedActivity && selectedCategory && (