From 7df9d47f072a72cf3faf314d169f42a742f35a7d Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Fri, 5 Dec 2025 15:40:38 +0530 Subject: [PATCH 01/15] Adding dropdown in directory. --- src/components/Directory/ManageContact.jsx | 113 ++++++++++++++------- src/components/common/TagInput.jsx | 4 +- 2 files changed, 78 insertions(+), 39 deletions(-) diff --git a/src/components/Directory/ManageContact.jsx b/src/components/Directory/ManageContact.jsx index f55ed858..70a46979 100644 --- a/src/components/Directory/ManageContact.jsx +++ b/src/components/Directory/ManageContact.jsx @@ -19,6 +19,8 @@ import SelectMultiple from "../common/SelectMultiple"; import { ContactSchema, defaultContactValue } from "./DirectorySchema"; import InputSuggestions from "../common/InputSuggestion"; import Label from "../common/Label"; +import { AppFormController } from "../../hooks/appHooks/useAppForm"; +import SelectField from "../common/Forms/SelectField"; const ManageContact = ({ contactId, closeModal }) => { // fetch master data @@ -194,7 +196,7 @@ const ManageContact = ({ contactId, closeModal }) => { Name {errors.name && ( @@ -210,6 +212,7 @@ const ManageContact = ({ contactId, closeModal }) => { value={watch("organization") || ""} onChange={(val) => setValue("organization", val, { shouldValidate: true })} error={errors.organization?.message} + size="md" /> @@ -222,7 +225,7 @@ const ManageContact = ({ contactId, closeModal }) => { Designation @@ -257,7 +260,7 @@ const ManageContact = ({ contactId, closeModal }) => { {/* Emails + Phones */} -
+
{emailFields.map((field, index) => (
{ className="row d-flex align-items-center mb-1" >
- - + ( + + )} + /> + {errors.contactEmails?.[index]?.label && ( + + {errors.contactEmails[index].label.message} + + )}
-
+
@@ -308,27 +328,43 @@ const ManageContact = ({ contactId, closeModal }) => {
{phoneFields.map((field, index) => ( -
+
+
- - + ( + + )} + /> + {errors.contactPhones?.[index]?.label && ( + + {errors.contactPhones[index].label.message} + + )}
-
+ +
@@ -350,17 +386,19 @@ const ManageContact = ({ contactId, closeModal }) => { )}
+
))}
+
{/* Category + Projects */} -
+
- {errors.description && ( -
{errors.description.message}
- )} -
+ {/* Description */} +
+ + + {errors.description && ( +
{errors.description.message}
+ )} +
- {/* Buttons */} -
- - -
- - -
+ {/* Buttons */} +
+ + +
+ + +
+ ); }; diff --git a/src/components/Employee/ManageEmployee.jsx b/src/components/Employee/ManageEmployee.jsx index 53e294d4..f81d6c60 100644 --- a/src/components/Employee/ManageEmployee.jsx +++ b/src/components/Employee/ManageEmployee.jsx @@ -517,39 +517,35 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
-
- -
- -
+
+ ( + + a?.name?.localeCompare(b?.name) + )} + placeholder="Select Role" + labelKeyKey="name" + valueKeyKey="id" + value={field.value} + onChange={field.onChange} + className="m-0" + /> + )} + /> + {errors.jobRoleId && ( -
+
{errors.jobRoleId.message}
)}
-
+ +
@@ -570,7 +566,7 @@ const ManageEmployee = ({ employeeId, onClosed }) => {
)}
-
+
diff --git a/src/components/Project/ProjectPermission.jsx b/src/components/Project/ProjectPermission.jsx index a043603e..d3bf7238 100644 --- a/src/components/Project/ProjectPermission.jsx +++ b/src/components/Project/ProjectPermission.jsx @@ -10,6 +10,8 @@ import { useForm, Controller } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; import showToast from "../../services/toastService"; +import { AppFormController } from "../../hooks/appHooks/useAppForm"; +import SelectField from "../common/Forms/SelectField"; export const ProjectPermissionSchema = z.object({ employeeId: z.string().min(1, "Employee is required"), @@ -46,26 +48,26 @@ const ProjectPermission = () => { ); useEffect(() => { - if (!selectedEmployee) return; + if (!selectedEmployee) return; - const enabledPerms = + const enabledPerms = + selectedEmpPermissions?.permissions + ?.filter((perm) => perm.isEnabled) + ?.map((perm) => perm.id) || []; + + setValue("selectedPermissions", enabledPerms, { shouldValidate: true }); + }, [selectedEmpPermissions, setValue, selectedEmployee]); + + const selectedPermissions = watch("selectedPermissions") || []; + + const existingEnabledIds = selectedEmpPermissions?.permissions - ?.filter((perm) => perm.isEnabled) - ?.map((perm) => perm.id) || []; + ?.filter((p) => p.isEnabled) + ?.map((p) => p.id) || []; - setValue("selectedPermissions", enabledPerms, { shouldValidate: true }); -}, [selectedEmpPermissions, setValue, selectedEmployee]); - -const selectedPermissions = watch("selectedPermissions") || []; - -const existingEnabledIds = - selectedEmpPermissions?.permissions - ?.filter((p) => p.isEnabled) - ?.map((p) => p.id) || []; - -const hasChanges = - selectedPermissions.length !== existingEnabledIds.length || - selectedPermissions.some((id) => !existingEnabledIds.includes(id)); + const hasChanges = + selectedPermissions.length !== existingEnabledIds.length || + selectedPermissions.some((id) => !existingEnabledIds.includes(id)); const { mutate: updatePermission, isPending } = useUpdateProjectLevelEmployeePermission(); @@ -115,35 +117,42 @@ const hasChanges =
-
+ {/*
-
-
- {" "} - + /> + {errors.employeeId && (
{errors.employeeId.message} @@ -152,6 +161,7 @@ const hasChanges =
+
{hasChanges && (
); -- 2.43.0 From 29cebedfad7e73f40ad06576cfeb79e7a7a97a4a Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Sat, 6 Dec 2025 11:12:25 +0530 Subject: [PATCH 05/15] fixed selectfield ui --- src/components/common/Forms/SelectField.jsx | 75 +++++++++++++++------ 1 file changed, 53 insertions(+), 22 deletions(-) diff --git a/src/components/common/Forms/SelectField.jsx b/src/components/common/Forms/SelectField.jsx index a08eaf8c..cefaf33f 100644 --- a/src/components/common/Forms/SelectField.jsx +++ b/src/components/common/Forms/SelectField.jsx @@ -12,6 +12,8 @@ const SelectField = ({ labelKey = "name", isLoading = false, }) => { + const [position, setPosition] = useState("bottom"); + const [open, setOpen] = useState(false); const dropdownRef = useRef(null); @@ -34,10 +36,26 @@ const SelectField = ({ setOpen(false); }; - const toggleDropdown = () => setOpen((prev) => !prev); + const toggleDropdown = () => { + if (!open) { + const rect = dropdownRef.current?.getBoundingClientRect(); + const viewportHeight = window.innerHeight; + + const spaceBelow = viewportHeight - rect.bottom; + const dropdownHeight = 200; + + if (spaceBelow < dropdownHeight) { + setPosition("top"); // open upward + } else { + setPosition("bottom"); // open downward + } + } + + setOpen((prev) => !prev); + }; return ( -
+
{label && (
)}
); -- 2.43.0 From 19c8975e8ffefc1f9668c678270e18d03f5ba9c7 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Sat, 6 Dec 2025 11:30:32 +0530 Subject: [PATCH 06/15] added margin bottom for selectField --- src/components/common/Forms/SelectField.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/common/Forms/SelectField.jsx b/src/components/common/Forms/SelectField.jsx index cefaf33f..c5eb1627 100644 --- a/src/components/common/Forms/SelectField.jsx +++ b/src/components/common/Forms/SelectField.jsx @@ -55,7 +55,7 @@ const SelectField = ({ }; return ( -
+
{label && ( {errors.name && ( @@ -51,12 +51,12 @@ const BucketForm = ({ selectedBucket, mode, onSubmit, onCancel, isPending }) => )}
-
+
diff --git a/src/components/master/Services/ManageServices.jsx b/src/components/master/Services/ManageServices.jsx index bdc379a2..758d50d5 100644 --- a/src/components/master/Services/ManageServices.jsx +++ b/src/components/master/Services/ManageServices.jsx @@ -62,7 +62,7 @@ const ManageServices = ({ data , onClose }) => { {errors.name &&

{errors.name.message}

}
-
+
diff --git a/src/components/master/Services/ServicesGroups.jsx b/src/components/master/Services/ServicesGroups.jsx index a89235ae..6af740a0 100644 --- a/src/components/master/Services/ServicesGroups.jsx +++ b/src/components/master/Services/ServicesGroups.jsx @@ -40,7 +40,7 @@ const ServiceGroups = ({ service }) => {
{/* Service Header */} -
+

{service.name}

-
+
diff --git a/src/components/purchase/DeliveryChallane.jsx b/src/components/purchase/DeliveryChallane.jsx index d3448977..eebcfad7 100644 --- a/src/components/purchase/DeliveryChallane.jsx +++ b/src/components/purchase/DeliveryChallane.jsx @@ -142,7 +142,7 @@ const DeliveryChallane = ({ purchaseId }) => { label="Select Document Type" options={data ?? []} placeholder="Choose Type" - labelKeyKey="name" + labelKey="name" valueKeyKey="id" value={field.value} onChange={field.onChange} diff --git a/src/components/purchase/PurchasePayment.jsx b/src/components/purchase/PurchasePayment.jsx index 121f77a5..f53b946b 100644 --- a/src/components/purchase/PurchasePayment.jsx +++ b/src/components/purchase/PurchasePayment.jsx @@ -111,7 +111,7 @@ const PurchasePayment = ({ onClose, purchaseId }) => { options={paymentTypes?.data ?? []} placeholder="Choose a Status" required - labelKeyKey="name" + labelKey="name" valueKeyKey="id" value={field.value} onChange={field.onChange} diff --git a/src/components/purchase/PurchasePaymentDetails.jsx b/src/components/purchase/PurchasePaymentDetails.jsx index 89805b43..093851aa 100644 --- a/src/components/purchase/PurchasePaymentDetails.jsx +++ b/src/components/purchase/PurchasePaymentDetails.jsx @@ -223,7 +223,7 @@ const PurchasePaymentDetails = ({ purchaseId = null }) => { label="Select Document Type" options={InvoiceDocTypes ?? []} placeholder="Choose Type" - labelKeyKey="name" + labelKey="name" valueKeyKey="id" value={field.value} onChange={field.onChange} diff --git a/src/pages/Activities/TaskPlannng.jsx b/src/pages/Activities/TaskPlannng.jsx index 3f49331e..b0b7d562 100644 --- a/src/pages/Activities/TaskPlannng.jsx +++ b/src/pages/Activities/TaskPlannng.jsx @@ -16,10 +16,10 @@ const TaskPlanning = () => { const selectedService = useCurrentService(); const dispatch = useDispatch(); const { control } = useForm({ - defaultValues: { - serviceFilter: selectedService ?? "" - }, -}); + defaultValues: { + serviceFilter: selectedService ?? "" + }, + }); const { projectNames = [], loading: projectLoading } = useProjectName(); @@ -60,14 +60,14 @@ const TaskPlanning = () => { { - field.onChange(val); // react-hook-form update - dispatch(setService(val)); // Redux update + field.onChange(val); + dispatch(setService(val)); }} className="m-0" /> @@ -77,6 +77,7 @@ const TaskPlanning = () => {
+ {/* Planning Component */} {selectedProject ? ( diff --git a/src/pages/DailyProgressReport/DailyProgrssReport.jsx b/src/pages/DailyProgressReport/DailyProgrssReport.jsx index d3a4eef6..e543895e 100644 --- a/src/pages/DailyProgressReport/DailyProgrssReport.jsx +++ b/src/pages/DailyProgressReport/DailyProgrssReport.jsx @@ -107,15 +107,15 @@ const DailyProgrssReport = () => { render={({ field }) => ( { - field.onChange(val); // update RHF - setService(val); // update your local filter state + field.onChange(val); + setService(val); }} className="m-0" /> @@ -129,6 +129,7 @@ const DailyProgrssReport = () => {
+
); diff --git a/src/pages/authentication/ChangePassword.jsx b/src/pages/authentication/ChangePassword.jsx index 844ce97c..3e037521 100644 --- a/src/pages/authentication/ChangePassword.jsx +++ b/src/pages/authentication/ChangePassword.jsx @@ -71,8 +71,7 @@ const ChangePasswordPage = () => { const bodyContxt = ( -
- +
Change Password

@@ -86,7 +85,7 @@ const ChangePasswordPage = () => {

{
{
{ )}
-
+
Your password must have at least 8 characters and include a lower case letter, an uppercase letter, a number, and a special character.
{/* Action Buttons */} -
- +
+
diff --git a/src/pages/master/MasterPage.jsx b/src/pages/master/MasterPage.jsx index 31f14da4..06378102 100644 --- a/src/pages/master/MasterPage.jsx +++ b/src/pages/master/MasterPage.jsx @@ -15,6 +15,9 @@ import { changeMaster } from "../../slices/localVariablesSlice"; import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { MANAGE_MASTER } from "../../utils/constants"; import GlobalModel from "../../components/common/GlobalModel"; +import { AppFormController } from "../../hooks/appHooks/useAppForm"; +import SelectField from "../../components/common/Forms/SelectField"; +import { useForm } from "react-hook-form"; export const MasterContext = createContext(); @@ -33,6 +36,11 @@ const MasterPage = () => { (store) => store.localVariables.selectedMaster ); const hasMasterPermission = useHasUserPermission(MANAGE_MASTER); + const { control, handleSubmit } = useForm({ + defaultValues: { + masterSelection: selectedMaster || "", + }, + }); const { data: menuData, @@ -46,9 +54,9 @@ const MasterPage = () => { isError: isMasterError, } = useMaster(); const { mutate: DeleteMaster, isPending: isDeleting } = useDeleteMasterItem(); - const [isDeleletingServiceItem,setDeleletingServiceItem] = useState({isOpen:false,ItemId:null,whichItem:null}) - const {mutate:DeleteSericeGroup,isPending:deletingGroup} =useDeleteServiceGroup() - const {mutate:DeleteAcivity,isPending:deletingActivity} = useDeleteActivity() + const [isDeleletingServiceItem, setDeleletingServiceItem] = useState({ isOpen: false, ItemId: null, whichItem: null }) + const { mutate: DeleteSericeGroup, isPending: deletingGroup } = useDeleteServiceGroup() + const { mutate: DeleteAcivity, isPending: deletingActivity } = useDeleteActivity() const [modalConfig, setModalConfig] = useState(null); const [deleteData, setDeleteData] = useState(null); @@ -89,15 +97,15 @@ const MasterPage = () => { }; - const handleDeleteServiceItem =()=>{ - if(!isDeleletingServiceItem.ItemId) return + const handleDeleteServiceItem = () => { + if (!isDeleletingServiceItem.ItemId) return debugger - if(isDeleletingServiceItem.whichItem === "activity"){ - DeleteAcivity(isDeleletingServiceItem.ItemId,{onSuccess:()=>setDeleletingServiceItem({isOpen:false,ItemId:null,whichItem:null})}) - }else{ - DeleteSericeGroup(isDeleletingServiceItem.ItemId,{onSuccess:()=>setDeleletingServiceItem({isOpen:false,ItemId:null,whichItem:null})}) + if (isDeleletingServiceItem.whichItem === "activity") { + DeleteAcivity(isDeleletingServiceItem.ItemId, { onSuccess: () => setDeleletingServiceItem({ isOpen: false, ItemId: null, whichItem: null }) }) + } else { + DeleteSericeGroup(isDeleletingServiceItem.ItemId, { onSuccess: () => setDeleletingServiceItem({ isOpen: false, ItemId: null, whichItem: null }) }) } - + } @@ -115,7 +123,7 @@ const MasterPage = () => { ); return ( - + {modalConfig && ( { /> )} - - { onSubmit={handleDeleteSubmit} onClose={() => setDeleteData(null)} /> - + setDeleletingServiceItem({isOpen:false,ItemId:null,whichItem:null})} + onSubmit={handleDeleteServiceItem} + onClose={() => setDeleletingServiceItem({ isOpen: false, ItemId: null, whichItem: null })} />
@@ -164,28 +170,34 @@ const MasterPage = () => {
-
- + />
+
{ } > Add{" "} - {selectedMaster} + {selectedMaster} )}
@@ -220,7 +232,7 @@ const MasterPage = () => {
- + ); }; diff --git a/src/pages/master/MasterTable.jsx b/src/pages/master/MasterTable.jsx index cb5fe881..a242f89a 100644 --- a/src/pages/master/MasterTable.jsx +++ b/src/pages/master/MasterTable.jsx @@ -80,7 +80,7 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => { }; return ( -
+
{loading ? (

Loading...

) : ( @@ -92,14 +92,14 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => { {" "} {selectedMaster === "Activity" ? "Activity" : "Name"} - + {" "} {selectedMaster === "Activity" ? "Unit" : selectedMaster === "Document Type" - ? "Content Type" - : "Description"} + ? "Content Type" + : "Description"} Actions @@ -109,15 +109,15 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => { {currentItems.length > 0 ? ( currentItems.map((item, index) => ( - - + + {updatedColumns.map((col) => ( {col.key === "description" ? ( item[col.key] !== undefined && - item[col.key] !== null ? ( + item[col.key] !== null ? ( item[col.key].length > 80 ? ( <>{item[col.key].slice(0, 80)}... ) : ( @@ -137,7 +137,7 @@ const MasterTable = ({ data, columns, loading, handleModalData }) => { {(selectedMaster === "Application Role" || selectedMaster === "Work Category") && - item?.isSystem ? ( + item?.isSystem ? ( <>
-
+
{ )}
-
+
Date: Sat, 6 Dec 2025 14:49:23 +0530 Subject: [PATCH 10/15] Adding dropdown across all places. --- .../Project/Infrastructure/FloorModel.jsx | 61 ++- .../Project/Infrastructure/TaskModel.jsx | 516 ++++++++++-------- .../Project/Infrastructure/WorkAreaModel.jsx | 208 +++---- src/components/Project/ProjectInfra.jsx | 72 ++- 4 files changed, 483 insertions(+), 374 deletions(-) diff --git a/src/components/Project/Infrastructure/FloorModel.jsx b/src/components/Project/Infrastructure/FloorModel.jsx index fb71d29e..c9ae9d43 100644 --- a/src/components/Project/Infrastructure/FloorModel.jsx +++ b/src/components/Project/Infrastructure/FloorModel.jsx @@ -144,31 +144,42 @@ const FloorModel = ({ project, onClose, onSubmit }) => { name="id" control={control} rules={{ required: "Floor is required" }} - render={({ field }) => ( - f.floorName) - .sort((a, b) => a.floorName.localeCompare(b.floorName)) - .map((f) => ({ id: f.id, name: f.floorName })) ?? []), - ]} - value={field.value || ""} - onChange={(value) => { - field.onChange(value); - handleFloorChange?.(value); - }} - required - noOptionsMessage={() => - !selectedBuilding?.floors || selectedBuilding.floors.length === 0 - ? "No floors found" - : null - } - className="m-0 form-select-sm w-100" - /> - )} + render={({ field }) => { + // Prepare options + const floorOptions = [ + { id: "0", name: "Add New Floor" }, + ...(selectedBuilding?.floors + ?.filter((f) => f.floorName) + .sort((a, b) => a.floorName.localeCompare(b.floorName)) + .map((f) => ({ id: f.id, name: f.floorName })) ?? []), + ]; + + return ( + { + field.onChange(val); // update react-hook-form + + if (val === "0") { + setValue("floorName", ""); // clear for new floor + } else { + const floor = selectedBuilding?.floors?.find(f => f.id === val); + setValue("floorName", floor?.floorName || ""); + } + }} + required + noOptionsMessage={() => + !selectedBuilding?.floors || selectedBuilding.floors.length === 0 + ? "No floors found" + : null + } + className="m-0 form-select-sm w-100" + /> + ); + }} /> {errors.id && ( diff --git a/src/components/Project/Infrastructure/TaskModel.jsx b/src/components/Project/Infrastructure/TaskModel.jsx index 6e4e7546..257dda24 100644 --- a/src/components/Project/Infrastructure/TaskModel.jsx +++ b/src/components/Project/Infrastructure/TaskModel.jsx @@ -8,10 +8,12 @@ import { useGroups, useWorkCategoriesMaster, } from "../../../hooks/masterHook/useMaster"; -import { useManageTask, useProjectAssignedOrganizationsName, useProjectAssignedServices } from "../../../hooks/useProjects"; +import { useManageTask, useProjectAssignedOrganizationsName, useProjectAssignedServices } from "../../../hooks/useProjects"; import showToast from "../../../services/toastService"; import Label from "../../common/Label"; import { useSelectedProject } from "../../../slices/apiDataManager"; +import { AppFormController, AppFormProvider } from "../../../hooks/appHooks/useAppForm"; +import SelectField from "../../common/Forms/SelectField"; const taskSchema = z.object({ buildingID: z.string().min(1, "Building is required"), @@ -76,19 +78,13 @@ const TaskModel = ({ project, onSubmit, onClose }) => { setValue("activityID", ""); }; - - const { - register, - handleSubmit, - watch, - setValue, - reset, - formState: { errors }, - } = useForm({ - resolver: zodResolver(taskSchema), + const methods = useForm({ defaultValues: defaultModel, + resolver: zodResolver(taskSchema), }); + const { register, control, watch, handleSubmit, reset, setValue, formState: { errors } } = methods; + const [isSubmitting, setIsSubmitting] = useState(false); const [activityData, setActivityData] = useState([]); const [categoryData, setCategoryData] = useState([]); @@ -112,10 +108,10 @@ const TaskModel = ({ project, onSubmit, onClose }) => { const { mutate: CreateTask, isPending } = useManageTask({ onSuccessCallback: (response) => { showToast(response?.message, "success"); - setValue("activityID",""), - setValue("plannedWork",0), - setValue("completedWork",0) - setValue("comment","") + setValue("activityID", ""), + setValue("plannedWork", 0), + setValue("completedWork", 0) + setValue("comment", "") }, }); useEffect(() => { @@ -148,224 +144,290 @@ const TaskModel = ({ project, onSubmit, onClose }) => { }; return ( -
-
-
Manage Task
-
-
- - - {errors.buildingID && ( -

{errors.buildingID.message}

- )} -
- - {selectedBuilding && ( + + +
+
Manage Task
+
+ {/* Select Building */}
- - - {errors.floorId && ( -

{errors.floorId.message}

- )} -
- )} - - {/* Work Area Selection */} - {selectedFloor && ( -
- - - {errors.workAreaId && ( -

{errors.workAreaId.message}

- )} -
- )} - - {/* Services Selection */} - {selectedWorkArea && ( -
- - -
- )} - - {/* Activity Group (Organization) Selection */} - {selectedService && ( -
- - - {errors.activityGroupId &&

{errors.activityGroupId.message}

} -
- )} - - - {/* Activity Selection */} - {selectedGroup && ( -
- - - {errors.activityID &&

{errors.activityID.message}

} -
- )} - - {watchActivityId && ( -
- - - {errors.workCategoryId && ( -

{errors.workCategoryId.message}

- )} -
- )} - - {selectedActivity && selectedCategory && ( - <> -
- - - {errors.plannedWork && ( -

{errors.plannedWork.message}

+ ( + { + field.onChange(value); + setValue("floorId", ""); + setValue("workAreaId", ""); + setSelectedService(""); + setSelectedGroup(""); + }} + className="m-0" + /> )} -
-
- - - {errors.completedWork && ( -

{errors.completedWork.message}

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