From c718269dfd3c0d36b4e91051efab0132a7c5d3ab Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 19 Nov 2025 15:35:39 +0530 Subject: [PATCH 01/17] added spinner in service profile page --- src/components/ServiceProject/ServiceProjectProfile.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectProfile.jsx b/src/components/ServiceProject/ServiceProjectProfile.jsx index dfda4880..8e131852 100644 --- a/src/components/ServiceProject/ServiceProjectProfile.jsx +++ b/src/components/ServiceProject/ServiceProjectProfile.jsx @@ -4,14 +4,13 @@ import { useServiceProject } from "../../hooks/useServiceProject"; import { formatUTCToLocalTime } from "../../utils/dateUtils"; import ManageServiceProject from "./ManageServiceProject"; import GlobalModel from "../common/GlobalModel"; +import { SpinnerLoader } from "../common/Loader"; const ServiceProjectProfile = () => { const { projectId } = useParams(); const [IsOpenModal, setIsOpenModal] = useState(false); const { data, isLoading, isError, error } = useServiceProject(projectId); - if (isLoading) { - return
Loadng.
; - } + if (isLoading) return
return ( <> {IsOpenModal && ( From c52f85ee4a2a4d326488c37a2c45f84f19ad8365 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 19 Nov 2025 15:44:54 +0530 Subject: [PATCH 02/17] added Advance payment flag inside paymentRequest list and view details --- src/components/PaymentRequest/PaymentRequestList.jsx | 2 +- src/components/PaymentRequest/ViewPaymentRequest.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/PaymentRequest/PaymentRequestList.jsx b/src/components/PaymentRequest/PaymentRequestList.jsx index e533634f..0c9edfd5 100644 --- a/src/components/PaymentRequest/PaymentRequestList.jsx +++ b/src/components/PaymentRequest/PaymentRequestList.jsx @@ -85,7 +85,7 @@ const PaymentRequestList = ({ filters, filterData, removeFilterChip, clearFilter key: "paymentRequestUID", label: "Request ID", align: "text-start mx-2", - getValue: (e) => e.paymentRequestUID || "N/A", + getValue: (e) =>
{e.paymentRequestUID || "N/A"} {e.isAdvancePayment && Adv}
, }, { key: "title", diff --git a/src/components/PaymentRequest/ViewPaymentRequest.jsx b/src/components/PaymentRequest/ViewPaymentRequest.jsx index d8e936fe..7bf122db 100644 --- a/src/components/PaymentRequest/ViewPaymentRequest.jsx +++ b/src/components/PaymentRequest/ViewPaymentRequest.jsx @@ -148,7 +148,7 @@ const ViewPaymentRequest = ({ requestId }) => {
-
PR No : {data?.paymentRequestUID}
+
PR No : {data?.paymentRequestUID} {data.isAdvancePayment && Advance}
Date: Wed, 19 Nov 2025 16:28:37 +0530 Subject: [PATCH 03/17] configure branch related api inside service repo. and made hooks for branch --- src/hooks/useServiceProject.jsx | 104 +++++++++++++++++- src/repositories/ServiceProjectRepository.jsx | 16 +++ 2 files changed, 119 insertions(+), 1 deletion(-) diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx index 1e480118..95283992 100644 --- a/src/hooks/useServiceProject.jsx +++ b/src/hooks/useServiceProject.jsx @@ -181,7 +181,7 @@ export const useJobComments = (jobId, pageSize, pageNumber) => { ); return resp.data; }, - enabled:!!jobId, + enabled: !!jobId, initialPageParam: pageNumber, @@ -282,3 +282,105 @@ export const useUpdateServiceProjectJob = (onSuccessCallback) => { }; //#endregion + +//#region Branch +export const useBranches = ( + projectId, + isActive, + pageSize, + pageNumber, + searchString +) => { + return useQuery({ + queryKey: [ + "branches", + projectId, + isActive, + pageSize, + pageNumber, + searchString, + ], + queryFn: async () => { + const resp = await ServiceProjectRepository.GetBranchList( + projectId, + isActive, + pageSize, + pageNumber, + searchString + ); + return resp.data; + }, + enabled: !!projectId, + }); +}; + +export const useBranch = (id)=>{ + return useQuery({ + queryKey:["branch",id], + queryFn:()=>{ + const resp = await ServiceProjectRepository.GetBranchDetail(id); + return resp.data ?? resp; + }, + enabled:!!id + }) +} + +export const useCreateBranche =()=>{ + return useMutation({ + mutationFn:(payload)=> await ServiceProjectRepository.CreateBranch(payload), + onSuccess: (data, variables) => { + queryClient.invalidateQueries({ + queryKey: ["branches"], + }); + if (onSuccessCallback) onSuccessCallback(); + showToast("Branch created successfully", "success"); + }, + onError: (error) => { + showToast( + error?.response?.data?.message || + error.message || + "Failed to create branch", + "error" + ); + }, + }) +} + +export const useUpdateBranch=()=>{ + return useMutation({ + mutationFn:async({id,payload})=> await ServiceProjectRepository.UpdateBranch(id,payload), + onSuccess: (_,variables) => { + queryClient.invalidateQueries({ queryKey: ["branches"] }); + queryClient.invalidateQueries({ queryKey: ["branch",variables.id] }); + if (onSuccessCallback) onSuccessCallback(); + showToast("Branch Updated successfully", "success"); + }, + onError: (error) => { + showToast( + error?.response?.data?.message || + error.message || + "Failed to update branch", + "error" + ); + }, + }) +} + +export const useDeleteBranch=()=>{ + return useMutation({ + mutationFn:async(id)=> await ServiceProjectRepository.DeleteBranch(id), + onSuccess: (_,variables) => { + queryClient.invalidateQueries({ queryKey: ["branches"] }); + if (onSuccessCallback) onSuccessCallback(); + showToast("Branch Deleted successfully", "success"); + }, + onError: (error) => { + showToast( + error?.response?.data?.message || + error.message || + "Failed to delete branch", + "error" + ); + }, + }) +} \ No newline at end of file diff --git a/src/repositories/ServiceProjectRepository.jsx b/src/repositories/ServiceProjectRepository.jsx index 94ef3c8e..e1c94e06 100644 --- a/src/repositories/ServiceProjectRepository.jsx +++ b/src/repositories/ServiceProjectRepository.jsx @@ -1,6 +1,7 @@ import { api } from "../utils/axiosClient"; export const ServiceProjectRepository = { + //#region Service Project CreateServiceProject: (data) => api.post("/api/ServiceProject/create", data), GetServiceProjects: (pageSize, pageNumber) => api.get( @@ -17,6 +18,8 @@ export const ServiceProjectRepository = { api.get( `/api/ServiceProject/get/allocation/list?projectId=${projectId}&isActive=${isActive} ` ), + //#endregion + //#region Job CreateJob: (data) => api.post(`/api/ServiceProject/job/create`, data), @@ -35,4 +38,17 @@ export const ServiceProjectRepository = { api.patch(`/api/ServiceProject/job/edit/${id}`, patchData, { "Content-Type": "application/json-patch+json", }), + //#endregion + + //#region Project Branch + CreateBranch: (data) => api.post(`/api/ServiceProject/create`, data), + UpdateBranch: (id, data) => + api.put("/api/ServiceProject/branch/edit/${id}", data), + GetBranchList: (projectId, isActive, pageSize, pageNumber, searchString) => { + api.get( + `/api/ServiceProject/branch/list/${projectId}&isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` + ); + }, + GetBranchDetail: (id) => api.get(`/api/ServiceProject/branch/details/${id}`), + DeleteBranch: (id) => api.delete(`/api/ServiceProject/branch/delete/${id}`), }; From 7cc8cc99c2feaf9ce06de2bf97ae7e2a340f438d Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 16:30:51 +0530 Subject: [PATCH 04/17] Creating a list view and modal for Branches. --- src/components/ServiceProject/BranchSchema.js | 43 +++++ .../ServiceProject/ManageBranch.jsx | 176 ++++++++++++++++++ .../ServiceProject/ServiceBranch.jsx | 170 +++++++++++++++++ .../ServiceProject/ServiceProjectProfile.jsx | 5 + src/repositories/ServiceProjectRepository.jsx | 9 + 5 files changed, 403 insertions(+) create mode 100644 src/components/ServiceProject/BranchSchema.js create mode 100644 src/components/ServiceProject/ManageBranch.jsx create mode 100644 src/components/ServiceProject/ServiceBranch.jsx diff --git a/src/components/ServiceProject/BranchSchema.js b/src/components/ServiceProject/BranchSchema.js new file mode 100644 index 00000000..346654d3 --- /dev/null +++ b/src/components/ServiceProject/BranchSchema.js @@ -0,0 +1,43 @@ +import { z } from "zod"; + +export const BranchSchema = () => + z.object({ + projectId: z + .string() + .trim() + .min(1, { message: "Project is required" }), + + branchName: z + .string() + .trim() + .min(1, { message: "Branch Name is required" }), + + contactInformation: z + .string() + .trim() + .min(1, { message: "Contact Information is required" }), + + address: z + .string() + .trim() + .min(1, { message: "Address is required" }), + + branchType: z + .string() + .trim() + .min(1, { message: "Branch Type is required" }), + + googleMapUrl: z + .string() + .trim() + .url({ message: "Enter a valid Google Map URL" }), + }); + +export const defaultBranches = { + branchName: "", + projectId: "", + contactInformation: "", + address: "", + branchType: "", + googleMapUrl: "", +}; \ No newline at end of file diff --git a/src/components/ServiceProject/ManageBranch.jsx b/src/components/ServiceProject/ManageBranch.jsx new file mode 100644 index 00000000..51c8f7f6 --- /dev/null +++ b/src/components/ServiceProject/ManageBranch.jsx @@ -0,0 +1,176 @@ +import React from 'react' +import { useProjectName } from '../../hooks/useProjects'; +import { BranchSchema, defaultBranches } from './BranchSchema'; +import { useForm } from 'react-hook-form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import Label from '../common/Label'; + +const ManageBranch = ({ BranchToEdit = null }) => { + + const schema = BranchSchema(); + const { + register, + control, + watch, + handleSubmit, + setValue, + reset, + formState: { errors }, + } = useForm({ + resolver: zodResolver(schema), + defaultValues: defaultBranches, + }); + + const { + projectNames, + loading: projectLoading, + error, + isError: isProjectError, + } = useProjectName(); + + const handleClose = () => { + reset(); + closeModal(); + }; + + + return ( +
+
+ {BranchToEdit + ? "Update Branch" + : "Create Branch"} +
+
+
+
+ + + {errors.projectId && ( + {errors.projectId.message} + )} +
+ +
+ + + {errors.branchName && ( + {errors.branchName.message} + )} +
+
+ +
+
+ + + {errors.contactInformation && ( + {errors.contactInformation.message} + )} +
+ +
+ + + {errors.address && ( + {errors.address.message} + )} +
+
+ + +
+
+ + + {errors.branchType && ( + {errors.branchType.message} + )} +
+ +
+ + + {errors.googleMapUrl && ( + {errors.googleMapUrl.message} + )} +
+
+ +
+ + + +
+ + + +
+
+ ) +} + +export default ManageBranch diff --git a/src/components/ServiceProject/ServiceBranch.jsx b/src/components/ServiceProject/ServiceBranch.jsx new file mode 100644 index 00000000..7722bb19 --- /dev/null +++ b/src/components/ServiceProject/ServiceBranch.jsx @@ -0,0 +1,170 @@ +import React, { useState } from 'react' +import GlobalModel from '../common/GlobalModel'; +import ManageBranch from './ManageBranch'; + +const ServiceBranch = () => { + + const [ManageServiceBranch, setManageServiceBranch] = useState({ + IsOpen: null, + branchId: null, + }); + + const ServiceBranch = [ + { + key: "branchName", + label: "Branch Name", + align: "text-start", + getValue: (e) => e?.payee || "N/A", + }, + ]; + return ( +
+
+
+
+ +
+
+ + +
+ {/* {Array.isArray(filteredData) && filteredData.length > 0 && ( */} + + + + {ServiceBranch.map((col) => ( + + ))} + + + + + {/* + {filteredData?.length > 0 ? ( + filteredData?.map((recurringExpense) => ( + + {recurringExpenseColumns.map((col) => ( + + ))} + + + )) + ) : ( + + + + )} + */} +
+ {col.label} + Action
+ {col?.customRender + ? col?.customRender(recurringExpense) + : col?.getValue(recurringExpense)} + +
+ + setViewRecurring({ + recurringId: recurringExpense?.id, + view: true, + }) + } + > + +
+ +
    +
  • + setManageServiceBranch({ + IsOpen: true, + RecurringId: recurringExpense?.id, + }) + } + > + + + Modify + +
  • + +
  • { + setIsDeleteModalOpen(true); + setDeletingId(recurringExpense.id); + }} + > + + + Delete + +
  • +
+
+
+
+ {/* )} */} + {/* {!filteredData || + filteredData.length === 0 + && ( +
+ {isError ? (

{error.message}

) : (

No Recurring Expense Found

)} +
+ )} */} +
+ + {ManageServiceBranch.IsOpen && ( + + setManageServiceBranch({ IsOpen: null, branchId: null }) + } + > + + setManageServiceBranch({ IsOpen: null, branchId: null }) + } + // requestToEdit={ManageServiceBranch.branchId} + /> + + )} +
+
+ ) +} + +export default ServiceBranch diff --git a/src/components/ServiceProject/ServiceProjectProfile.jsx b/src/components/ServiceProject/ServiceProjectProfile.jsx index 8e131852..05a05fd3 100644 --- a/src/components/ServiceProject/ServiceProjectProfile.jsx +++ b/src/components/ServiceProject/ServiceProjectProfile.jsx @@ -5,6 +5,7 @@ import { formatUTCToLocalTime } from "../../utils/dateUtils"; import ManageServiceProject from "./ManageServiceProject"; import GlobalModel from "../common/GlobalModel"; import { SpinnerLoader } from "../common/Loader"; +import ServiceBranch from "./ServiceBranch"; const ServiceProjectProfile = () => { const { projectId } = useParams(); @@ -114,6 +115,10 @@ const ServiceProjectProfile = () => {
+
+ +
+
diff --git a/src/repositories/ServiceProjectRepository.jsx b/src/repositories/ServiceProjectRepository.jsx index 94ef3c8e..1da42fd2 100644 --- a/src/repositories/ServiceProjectRepository.jsx +++ b/src/repositories/ServiceProjectRepository.jsx @@ -35,4 +35,13 @@ export const ServiceProjectRepository = { api.patch(`/api/ServiceProject/job/edit/${id}`, patchData, { "Content-Type": "application/json-patch+json", }), + + //Branch API + getServiceBranch: (jobTicketId, pageSize, pageNumber) => + api.get( + `/api/serviceproject/branch/list?jobTicketId=${jobTicketId}&pageSize=${pageSize}&pageNumber=${pageNumber}` + ), + }; + + From 15978b2ac7308e33dba8aa1f87dee4e5cd1f4191 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 19 Nov 2025 16:35:53 +0530 Subject: [PATCH 05/17] fixed useClient implmention --- src/hooks/useServiceProject.jsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx index 95283992..b0b98719 100644 --- a/src/hooks/useServiceProject.jsx +++ b/src/hooks/useServiceProject.jsx @@ -317,7 +317,7 @@ export const useBranches = ( export const useBranch = (id)=>{ return useQuery({ queryKey:["branch",id], - queryFn:()=>{ + queryFn:async()=>{ const resp = await ServiceProjectRepository.GetBranchDetail(id); return resp.data ?? resp; }, @@ -326,8 +326,9 @@ export const useBranch = (id)=>{ } export const useCreateBranche =()=>{ + const queryClient = useQueryClient(); return useMutation({ - mutationFn:(payload)=> await ServiceProjectRepository.CreateBranch(payload), + mutationFn:async(payload)=> await ServiceProjectRepository.CreateBranch(payload), onSuccess: (data, variables) => { queryClient.invalidateQueries({ queryKey: ["branches"], @@ -347,6 +348,7 @@ export const useCreateBranche =()=>{ } export const useUpdateBranch=()=>{ + const queryClient = useQueryClient(); return useMutation({ mutationFn:async({id,payload})=> await ServiceProjectRepository.UpdateBranch(id,payload), onSuccess: (_,variables) => { @@ -367,6 +369,7 @@ export const useUpdateBranch=()=>{ } export const useDeleteBranch=()=>{ + const queryClient = useQueryClient(); return useMutation({ mutationFn:async(id)=> await ServiceProjectRepository.DeleteBranch(id), onSuccess: (_,variables) => { From df24b18a27b24b4a46f9c30061af04ef251105d1 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 16:36:32 +0530 Subject: [PATCH 06/17] At the time of hit in cancel form will be closed. --- src/components/ServiceProject/ManageBranch.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ServiceProject/ManageBranch.jsx b/src/components/ServiceProject/ManageBranch.jsx index 51c8f7f6..2eae8c49 100644 --- a/src/components/ServiceProject/ManageBranch.jsx +++ b/src/components/ServiceProject/ManageBranch.jsx @@ -5,7 +5,7 @@ import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import Label from '../common/Label'; -const ManageBranch = ({ BranchToEdit = null }) => { +const ManageBranch = ({ closeModal,BranchToEdit = null }) => { const schema = BranchSchema(); const { From 50269aead221f3533d18f2e113ecf1a85d0c623d Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 19 Nov 2025 18:28:54 +0530 Subject: [PATCH 07/17] added selectFiled for branch --- src/components/ServiceProject/ManageJob.jsx | 20 +- .../ServiceProject/ServiceProjectSchema.jsx | 3 + .../common/Forms/SelectFieldServerSide.jsx | 179 ++++++++++++++++++ src/hooks/useServiceProject.jsx | 2 + src/repositories/ServiceProjectRepository.jsx | 4 +- 5 files changed, 204 insertions(+), 4 deletions(-) diff --git a/src/components/ServiceProject/ManageJob.jsx b/src/components/ServiceProject/ManageJob.jsx index c0d9223e..97cd1a97 100644 --- a/src/components/ServiceProject/ManageJob.jsx +++ b/src/components/ServiceProject/ManageJob.jsx @@ -4,6 +4,7 @@ import Label from "../common/Label"; import { zodResolver } from "@hookform/resolvers/zod"; import { defaultJobValue, jobSchema } from "./ServiceProjectSchema"; import { + useBranches, useCreateServiceProjectJob, useJobTags, useServiceProjectJobDetails, @@ -25,6 +26,7 @@ import { useParams } from "react-router-dom"; import { useDispatch } from "react-redux"; import { useJobStatus } from "../../hooks/masterHook/useMaster"; import { useServiceProjectJobContext } from "./Jobs"; +import { SelectFieldSearch } from "../common/Forms/SelectFieldServerSide"; const ManageJob = ({ Job }) => { const { setManageJob, setSelectedJob } = useServiceProjectJobContext(); @@ -39,7 +41,7 @@ const ManageJob = ({ Job }) => { control, watch, handleSubmit, - reset, + reset,setValue, formState: { errors }, } = methods; @@ -199,7 +201,7 @@ const ManageJob = ({ Job }) => { />
- + { name="tags" label="Tag" placeholder="Enter Tag" + + /> +
+
+ setValue("branchId", val)} + valueKey="id" + labelKey="branchName" + hookParams={[projectId,true,10,1]} + useFetchHook={useBranches} + isMultiple={false} />
diff --git a/src/components/ServiceProject/ServiceProjectSchema.jsx b/src/components/ServiceProject/ServiceProjectSchema.jsx index 5a5727b7..9a14605c 100644 --- a/src/components/ServiceProject/ServiceProjectSchema.jsx +++ b/src/components/ServiceProject/ServiceProjectSchema.jsx @@ -70,6 +70,8 @@ export const jobSchema = z.object({ tags: z.array(TagSchema).optional().default([]), statusId: z.string().optional().nullable(), + + branchId: z.string().optional().nullable(), }); const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB @@ -109,6 +111,7 @@ export const defaultJobValue = { startDate: null, dueDate: null, tags: [], + branchId: null, }; //#endregion diff --git a/src/components/common/Forms/SelectFieldServerSide.jsx b/src/components/common/Forms/SelectFieldServerSide.jsx index 6ff6eb90..de0265af 100644 --- a/src/components/common/Forms/SelectFieldServerSide.jsx +++ b/src/components/common/Forms/SelectFieldServerSide.jsx @@ -361,3 +361,182 @@ export const SelectProjectField = ({
); }; + + + +export const SelectFieldSearch = ({ + label = "Select", + placeholder = "Select ", + required = false, + value = null, + onChange, + valueKey = "id", + labelKey = "name", + + isFullObject = false, + isMultiple = false, + hookParams, + useFetchHook, +}) => { + const [searchText, setSearchText] = useState(""); + const debounce = useDebounce(searchText, 300); + + const { data, isLoading } = useFetchHook(...hookParams,debounce); + const options = data?.data ?? []; + const [open, setOpen] = useState(false); + const dropdownRef = useRef(null); + + const getDisplayName = (entity) => { + if (!entity) return ""; + return `${entity[labelKey] || ""}`.trim(); + }; + + /** ----------------------------- + * SELECTED OPTION (SINGLE) + * ----------------------------- */ + let selectedSingle = null; + + if (!isMultiple) { + if (isFullObject && value) selectedSingle = value; + else if (!isFullObject && value) + selectedSingle = options.find((o) => o[valueKey] === value); + } + + /** ----------------------------- + * SELECTED OPTION (MULTIPLE) + * ----------------------------- */ + let selectedList = []; + if (isMultiple && Array.isArray(value)) { + if (isFullObject) selectedList = value; + else { + selectedList = options.filter((opt) => value.includes(opt[valueKey])); + } + } + + /** Main button label */ + const displayText = !isMultiple + ? getDisplayName(selectedSingle) || placeholder + : selectedList.length > 0 + ? selectedList.map((e) => getDisplayName(e)).join(", ") + : placeholder; + + /** ----------------------------- + * HANDLE OUTSIDE CLICK + * ----------------------------- */ + useEffect(() => { + const handleClickOutside = (e) => { + if (dropdownRef.current && !dropdownRef.current.contains(e.target)) { + setOpen(false); + } + }; + + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + /** ----------------------------- + * HANDLE SELECT + * ----------------------------- */ + const handleSelect = (option) => { + if (!isMultiple) { + // SINGLE SELECT + if (isFullObject) onChange(option); + else onChange(option[valueKey]); + } else { + // MULTIPLE SELECT + let updated = []; + + const exists = selectedList.some((e) => e[valueKey] === option[valueKey]); + + if (exists) { + // remove + updated = selectedList.filter((e) => e[valueKey] !== option[valueKey]); + } else { + // add + updated = [...selectedList, option]; + } + + if (isFullObject) onChange(updated); + else onChange(updated.map((x) => x[valueKey])); + } + }; + + return ( +
+ {label && ( + + )} + + {/* MAIN BUTTON */} + + + {/* DROPDOWN */} + {open && ( +
    +
    + setSearchText(e.target.value)} + className="form-control form-control-sm" + placeholder="Search..." + /> +
    + + {isLoading && ( +
  • Loading...
  • + )} + + {!isLoading && options.length === 0 && ( +
  • + No results found +
  • + )} + + {!isLoading && + options.map((option) => { + const isActive = isMultiple + ? selectedList.some((x) => x[valueKey] === option[valueKey]) + : selectedSingle && + selectedSingle[valueKey] === option[valueKey]; + + return ( +
  • + +
  • + ); + })} +
+ )} +
+ ); +}; diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx index b0b98719..ab536e2b 100644 --- a/src/hooks/useServiceProject.jsx +++ b/src/hooks/useServiceProject.jsx @@ -308,12 +308,14 @@ export const useBranches = ( pageNumber, searchString ); + console.log(resp) return resp.data; }, enabled: !!projectId, }); }; + export const useBranch = (id)=>{ return useQuery({ queryKey:["branch",id], diff --git a/src/repositories/ServiceProjectRepository.jsx b/src/repositories/ServiceProjectRepository.jsx index b61505cd..339d5212 100644 --- a/src/repositories/ServiceProjectRepository.jsx +++ b/src/repositories/ServiceProjectRepository.jsx @@ -45,8 +45,8 @@ export const ServiceProjectRepository = { UpdateBranch: (id, data) => api.put("/api/ServiceProject/branch/edit/${id}", data), GetBranchList: (projectId, isActive, pageSize, pageNumber, searchString) => { - api.get( - `/api/ServiceProject/branch/list/${projectId}&isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` + return api.get( + `/api/ServiceProject/branch/list/${projectId}?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` ); }, GetBranchDetail: (id) => api.get(`/api/ServiceProject/branch/details/${id}`), From 8a5d6158c2c5b27649fc7b6e851aba525d091bdb Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 18:31:17 +0530 Subject: [PATCH 08/17] Implementing Creating API. --- .../ServiceProject/ManageBranch.jsx | 120 +++++++------- .../ServiceProject/ServiceBranch.jsx | 155 ++++++++---------- src/hooks/useServiceProject.jsx | 83 +++++----- src/repositories/ServiceProjectRepository.jsx | 8 +- 4 files changed, 181 insertions(+), 185 deletions(-) diff --git a/src/components/ServiceProject/ManageBranch.jsx b/src/components/ServiceProject/ManageBranch.jsx index 2eae8c49..70257710 100644 --- a/src/components/ServiceProject/ManageBranch.jsx +++ b/src/components/ServiceProject/ManageBranch.jsx @@ -1,12 +1,16 @@ -import React from 'react' +import React, { useEffect } from 'react' import { useProjectName } from '../../hooks/useProjects'; import { BranchSchema, defaultBranches } from './BranchSchema'; import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import Label from '../common/Label'; +import { useCreateBranch, useServiceProjects, useUpdateBranch } from '../../hooks/useServiceProject'; +import { useAppForm } from '../../hooks/appHooks/useAppForm'; +import { useParams } from 'react-router-dom'; -const ManageBranch = ({ closeModal,BranchToEdit = null }) => { - +const ManageBranch = ({ closeModal, BranchToEdit = null }) => { + const { data } = {} + const { projectId } = useParams(); const schema = BranchSchema(); const { register, @@ -16,23 +20,50 @@ const ManageBranch = ({ closeModal,BranchToEdit = null }) => { setValue, reset, formState: { errors }, - } = useForm({ + } = useAppForm({ resolver: zodResolver(schema), - defaultValues: defaultBranches, + defaultValues: { + ...defaultBranches, + projectId: projectId || "" + }, }); - const { - projectNames, - loading: projectLoading, - error, - isError: isProjectError, - } = useProjectName(); - const handleClose = () => { reset(); closeModal(); }; + useEffect(() => { + if (BranchToEdit && data) { + reset({ + branchName: data.branchName || "", + projectId: data.project?.id || projectId || "", + contactInformation: data.contactInformation || "", + address: data.address || "", + branchType: data.branchType || "", + googleMapUrl: data.googleMapUrl || "", + }); + } + }, [data, reset]); + + const { mutate: CreateServiceBranch, isPending: createPending } = + useCreateBranch(() => { + handleClose(); + }); + const { mutate: ServiceBranchUpdate, isPending } = + useUpdateBranch(() => handleClose()); + + const onSubmit = (fromdata) => { + let payload = { + ...fromdata, projectId, + }; + if (BranchToEdit) { + const editPayload = { ...payload, id: data.id }; + ServiceBranchUpdate({ id: data.id, payload: editPayload }); + } else { + CreateServiceBranch(payload); + } + }; return (
@@ -41,50 +72,24 @@ const ManageBranch = ({ closeModal,BranchToEdit = null }) => { ? "Update Branch" : "Create Branch"} -
+
+
-
- -
- - - {errors.branchName && ( - {errors.branchName.message} - )} -
-
- -
+
+ +
+
-
- - -
+
+ + +
+
-
- - - )) - ) : ( - - + + + setManageServiceBranch({ + IsOpen: true, + branchId: branch.id, + }) + } + > + - )} - */} + )) + ) : ( + + + No Branch Found + + + )} + */} + + {/* )} */} {/* {!filteredData || @@ -158,10 +139,16 @@ const ServiceBranch = () => { closeModal={() => setManageServiceBranch({ IsOpen: null, branchId: null }) } - // requestToEdit={ManageServiceBranch.branchId} + // requestToEdit={ManageServiceBranch.branchId} /> )} + + {/* */}
) diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx index b0b98719..3dfd4115 100644 --- a/src/hooks/useServiceProject.jsx +++ b/src/hooks/useServiceProject.jsx @@ -59,8 +59,8 @@ export const useCreateServiceProject = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to delete task", + error.message || + "Failed to delete task", "error" ); }, @@ -84,8 +84,8 @@ export const useUpdateServiceProject = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -110,8 +110,8 @@ export const useActiveInActiveServiceProject = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -138,8 +138,8 @@ export const useAllocationServiceProjectTeam = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -223,8 +223,8 @@ export const useAddCommentJob = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -247,8 +247,8 @@ export const useCreateServiceProjectJob = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -273,8 +273,8 @@ export const useUpdateServiceProjectJob = (onSuccessCallback) => { onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update project", + error.message || + "Failed to update project", "error" ); }, @@ -314,65 +314,64 @@ export const useBranches = ( }); }; -export const useBranch = (id)=>{ +export const useBranch = (id) => { return useQuery({ - queryKey:["branch",id], - queryFn:async()=>{ + queryKey: ["branch", id], + queryFn: async () => { const resp = await ServiceProjectRepository.GetBranchDetail(id); return resp.data ?? resp; }, - enabled:!!id + enabled: !!id }) } -export const useCreateBranche =()=>{ +export const useCreateBranch = (onSuccessCallBack) => { const queryClient = useQueryClient(); return useMutation({ - mutationFn:async(payload)=> await ServiceProjectRepository.CreateBranch(payload), - onSuccess: (data, variables) => { - queryClient.invalidateQueries({ - queryKey: ["branches"], - }); - if (onSuccessCallback) onSuccessCallback(); - showToast("Branch created successfully", "success"); + mutationFn: async (payload) => { + await ServiceProjectRepository.CreateBranch(payload); + }, + + onSuccess: (_, variables) => { + queryClient.invalidateQueries({ queryKey: ["branches"] }); + showToast("Branches Created Successfully", "success"); + if (onSuccessCallBack) onSuccessCallBack(); }, onError: (error) => { showToast( - error?.response?.data?.message || - error.message || - "Failed to create branch", + error.message || "Something went wrong please try again !", "error" ); }, - }) -} + }); +}; -export const useUpdateBranch=()=>{ +export const useUpdateBranch = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn:async({id,payload})=> await ServiceProjectRepository.UpdateBranch(id,payload), - onSuccess: (_,variables) => { + mutationFn: async ({ id, payload }) => await ServiceProjectRepository.UpdateBranch(id, payload), + onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: ["branches"] }); - queryClient.invalidateQueries({ queryKey: ["branch",variables.id] }); + queryClient.invalidateQueries({ queryKey: ["branch", variables.id] }); if (onSuccessCallback) onSuccessCallback(); showToast("Branch Updated successfully", "success"); }, onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to update branch", + error.message || + "Failed to update branch", "error" ); }, }) } -export const useDeleteBranch=()=>{ +export const useDeleteBranch = () => { const queryClient = useQueryClient(); return useMutation({ - mutationFn:async(id)=> await ServiceProjectRepository.DeleteBranch(id), - onSuccess: (_,variables) => { + mutationFn: async (id) => await ServiceProjectRepository.DeleteBranch(id), + onSuccess: (_, variables) => { queryClient.invalidateQueries({ queryKey: ["branches"] }); if (onSuccessCallback) onSuccessCallback(); showToast("Branch Deleted successfully", "success"); @@ -380,8 +379,8 @@ export const useDeleteBranch=()=>{ onError: (error) => { showToast( error?.response?.data?.message || - error.message || - "Failed to delete branch", + error.message || + "Failed to delete branch", "error" ); }, diff --git a/src/repositories/ServiceProjectRepository.jsx b/src/repositories/ServiceProjectRepository.jsx index b61505cd..e838a04b 100644 --- a/src/repositories/ServiceProjectRepository.jsx +++ b/src/repositories/ServiceProjectRepository.jsx @@ -41,16 +41,16 @@ export const ServiceProjectRepository = { //#endregion //#region Project Branch - CreateBranch: (data) => api.post(`/api/ServiceProject/create`, data), + CreateBranch: (data) => api.post(`/api/ServiceProject/branch/create`, data), UpdateBranch: (id, data) => api.put("/api/ServiceProject/branch/edit/${id}", data), GetBranchList: (projectId, isActive, pageSize, pageNumber, searchString) => { api.get( - `/api/ServiceProject/branch/list/${projectId}&isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` + `/api/ServiceProject/branch/list/${projectId}/?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` ); - }, + }, + GetBranchDetail: (id) => api.get(`/api/ServiceProject/branch/details/${id}`), DeleteBranch: (id) => api.delete(`/api/ServiceProject/branch/delete/${id}`), }; - From 7e4dffff34ea1d2b01aefb28f029440b02e5e703 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Wed, 19 Nov 2025 18:47:30 +0530 Subject: [PATCH 09/17] Implementing Get api. --- .../ServiceProject/ServiceBranch.jsx | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/components/ServiceProject/ServiceBranch.jsx b/src/components/ServiceProject/ServiceBranch.jsx index 982b4ab4..fc0bf1ac 100644 --- a/src/components/ServiceProject/ServiceBranch.jsx +++ b/src/components/ServiceProject/ServiceBranch.jsx @@ -22,12 +22,11 @@ const ServiceBranch = () => { const { data, isLoading, isError, error } = useBranches( projectId, - debouncedSearch || null, - null, + true, + ITEMS_PER_PAGE, currentPage, - ITEMS_PER_PAGE + debouncedSearch, ); - const paginate = (page) => { if (page >= 1 && page <= (data?.totalPages ?? 1)) { setCurrentPage(page); @@ -68,30 +67,38 @@ const ServiceBranch = () => {
{/* {Array.isArray(filteredData) && filteredData.length > 0 && ( */} - +
{ServiceBranch.map((col) => ( - ))} - - {/* + {isLoading ? ( + ) : isError ? ( + + + ) : data?.data?.length > 0 ? ( data.data.map((branch) => ( - - - + + {ServiceBranch.map((col) => ( + + ))} )) @@ -112,9 +119,7 @@ const ServiceBranch = () => { )} - */} - - +
+ {col.label} Action
Loading...
+ {error?.message || "Error loading branches"} +
{branch.branchName}
+ {col.getValue(branch)} + { branchId: branch.id, }) } - > + />
{/* )} */} {/* {!filteredData || From e7fddd41c2fb0f1606ecf6578ba7ee089cf47be2 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 19 Nov 2025 21:28:01 +0530 Subject: [PATCH 10/17] added branch for projects --- .../PaymentRequest/ActionPaymentRequest.jsx | 1 - .../Infrastructure/EditActivityModal.jsx | 1 - src/components/ServiceProject/BranchSchema.js | 43 ---- .../ServiceProject/ManageBranch.jsx | 186 ------------------ src/components/ServiceProject/ManageJob.jsx | 11 +- .../ServiceProject/ManageJobTicket.jsx | 10 +- .../ServiceProject/ServiceBranch.jsx | 162 --------------- .../ServiceProject/ServiceProfile.jsx | 95 +++++++++ .../ServiceProjectBranch/ManageBranch.jsx | 183 +++++++++++++++++ .../ServiceProjectBranch/ServiceBranch.jsx | 174 ++++++++++++++++ .../ServiceProject/ServiceProjectProfile.jsx | 108 ++-------- .../ServiceProject/ServiceProjectSchema.jsx | 55 ++++++ src/components/Tenant/SubScriptionHistory.jsx | 3 +- src/components/Tenant/TenantForm.jsx | 2 - .../common/Forms/SelectFieldServerSide.jsx | 40 +++- .../common/GlobalModal/CommentEditor.jsx | 1 - src/hooks/useProjects.js | 1 - src/hooks/useServiceProject.jsx | 1 - 18 files changed, 571 insertions(+), 506 deletions(-) delete mode 100644 src/components/ServiceProject/BranchSchema.js delete mode 100644 src/components/ServiceProject/ManageBranch.jsx delete mode 100644 src/components/ServiceProject/ServiceBranch.jsx create mode 100644 src/components/ServiceProject/ServiceProfile.jsx create mode 100644 src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx create mode 100644 src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx diff --git a/src/components/PaymentRequest/ActionPaymentRequest.jsx b/src/components/PaymentRequest/ActionPaymentRequest.jsx index 5f3cc1d9..52222b55 100644 --- a/src/components/PaymentRequest/ActionPaymentRequest.jsx +++ b/src/components/PaymentRequest/ActionPaymentRequest.jsx @@ -40,7 +40,6 @@ const ActionPaymentRequest = ({ requestId }) => { error: PaymentModeError, } = usePaymentMode(); - console.log("Kartik", data) const IsReview = useHasUserPermission(REVIEW_EXPENSE); const [imageLoaded, setImageLoaded] = useState({}); diff --git a/src/components/Project/Infrastructure/EditActivityModal.jsx b/src/components/Project/Infrastructure/EditActivityModal.jsx index e57b6a30..14e66020 100644 --- a/src/components/Project/Infrastructure/EditActivityModal.jsx +++ b/src/components/Project/Infrastructure/EditActivityModal.jsx @@ -82,7 +82,6 @@ const EditActivityModal = ({ useEffect(() => { if (!workItem) return; - console.log(workItem) reset({ activityID: String( workItem?.workItem?.activityId || workItem?.activityMaster?.id diff --git a/src/components/ServiceProject/BranchSchema.js b/src/components/ServiceProject/BranchSchema.js deleted file mode 100644 index 346654d3..00000000 --- a/src/components/ServiceProject/BranchSchema.js +++ /dev/null @@ -1,43 +0,0 @@ -import { z } from "zod"; - -export const BranchSchema = () => - z.object({ - projectId: z - .string() - .trim() - .min(1, { message: "Project is required" }), - - branchName: z - .string() - .trim() - .min(1, { message: "Branch Name is required" }), - - contactInformation: z - .string() - .trim() - .min(1, { message: "Contact Information is required" }), - - address: z - .string() - .trim() - .min(1, { message: "Address is required" }), - - branchType: z - .string() - .trim() - .min(1, { message: "Branch Type is required" }), - - googleMapUrl: z - .string() - .trim() - .url({ message: "Enter a valid Google Map URL" }), - }); - -export const defaultBranches = { - branchName: "", - projectId: "", - contactInformation: "", - address: "", - branchType: "", - googleMapUrl: "", -}; \ No newline at end of file diff --git a/src/components/ServiceProject/ManageBranch.jsx b/src/components/ServiceProject/ManageBranch.jsx deleted file mode 100644 index 70257710..00000000 --- a/src/components/ServiceProject/ManageBranch.jsx +++ /dev/null @@ -1,186 +0,0 @@ -import React, { useEffect } from 'react' -import { useProjectName } from '../../hooks/useProjects'; -import { BranchSchema, defaultBranches } from './BranchSchema'; -import { useForm } from 'react-hook-form'; -import { zodResolver } from '@hookform/resolvers/zod'; -import Label from '../common/Label'; -import { useCreateBranch, useServiceProjects, useUpdateBranch } from '../../hooks/useServiceProject'; -import { useAppForm } from '../../hooks/appHooks/useAppForm'; -import { useParams } from 'react-router-dom'; - -const ManageBranch = ({ closeModal, BranchToEdit = null }) => { - const { data } = {} - const { projectId } = useParams(); - const schema = BranchSchema(); - const { - register, - control, - watch, - handleSubmit, - setValue, - reset, - formState: { errors }, - } = useAppForm({ - resolver: zodResolver(schema), - defaultValues: { - ...defaultBranches, - projectId: projectId || "" - }, - }); - - const handleClose = () => { - reset(); - closeModal(); - }; - - useEffect(() => { - if (BranchToEdit && data) { - reset({ - branchName: data.branchName || "", - projectId: data.project?.id || projectId || "", - contactInformation: data.contactInformation || "", - address: data.address || "", - branchType: data.branchType || "", - googleMapUrl: data.googleMapUrl || "", - }); - } - }, [data, reset]); - - const { mutate: CreateServiceBranch, isPending: createPending } = - useCreateBranch(() => { - handleClose(); - }); - const { mutate: ServiceBranchUpdate, isPending } = - useUpdateBranch(() => handleClose()); - - const onSubmit = (fromdata) => { - let payload = { - ...fromdata, projectId, - }; - if (BranchToEdit) { - const editPayload = { ...payload, id: data.id }; - ServiceBranchUpdate({ id: data.id, payload: editPayload }); - } else { - CreateServiceBranch(payload); - } - }; - - return ( -
-
- {BranchToEdit - ? "Update Branch" - : "Create Branch"} -
- -
- -
- - - {errors.branchName && ( - {errors.branchName.message} - )} -
-
- - - {errors.contactInformation && ( - {errors.contactInformation.message} - )} -
-
- -
- - -
- - - {errors.address && ( - {errors.address.message} - )} -
-
- - - {errors.branchType && ( - {errors.branchType.message} - )} -
-
- - -
- - -
- - - {errors.googleMapUrl && ( - {errors.googleMapUrl.message} - )} -
-
- -
- - - -
- - - - -
- ) -} - -export default ManageBranch diff --git a/src/components/ServiceProject/ManageJob.jsx b/src/components/ServiceProject/ManageJob.jsx index 97cd1a97..6ec96e3b 100644 --- a/src/components/ServiceProject/ManageJob.jsx +++ b/src/components/ServiceProject/ManageJob.jsx @@ -41,7 +41,8 @@ const ManageJob = ({ Job }) => { control, watch, handleSubmit, - reset,setValue, + reset, + setValue, formState: { errors }, } = methods; @@ -164,6 +165,7 @@ const ManageJob = ({ Job }) => { dueDate: JobData.dueDate ?? null, tags: JobData.tags ?? [], statusId: JobData.status.id, + branchId : JobData?.projectBranch?.id }); }, [JobData, Job, projectId]); return ( @@ -201,7 +203,7 @@ const ManageJob = ({ Job }) => { />
- + { name="tags" label="Tag" placeholder="Enter Tag" - />
setValue("branchId", val)} valueKey="id" labelKey="branchName" - hookParams={[projectId,true,10,1]} + hookParams={[projectId, true, 10, 1]} useFetchHook={useBranches} isMultiple={false} + disabled={Job} />
diff --git a/src/components/ServiceProject/ManageJobTicket.jsx b/src/components/ServiceProject/ManageJobTicket.jsx index 9dbf0b9f..c589509c 100644 --- a/src/components/ServiceProject/ManageJobTicket.jsx +++ b/src/components/ServiceProject/ManageJobTicket.jsx @@ -124,10 +124,16 @@ const ManageJobTicket = ({ Job }) => { ); })()}
+
+ + {" "} + Branch Name : + +
- Created By + Created By
{ {data?.assignees?.length > 0 && (
- Assigned To + Assigned To
diff --git a/src/components/ServiceProject/ServiceBranch.jsx b/src/components/ServiceProject/ServiceBranch.jsx deleted file mode 100644 index fc0bf1ac..00000000 --- a/src/components/ServiceProject/ServiceBranch.jsx +++ /dev/null @@ -1,162 +0,0 @@ -import React, { useState } from 'react' -import GlobalModel from '../common/GlobalModel'; -import ManageBranch from './ManageBranch'; -import { Pagination } from 'swiper/modules'; -import { useBranches } from '../../hooks/useServiceProject'; -import { ITEMS_PER_PAGE } from '../../utils/constants'; -import { useDebounce } from '../../utils/appUtils'; -import { useParams } from 'react-router-dom'; - -const ServiceBranch = () => { - - const [ManageServiceBranch, setManageServiceBranch] = useState({ - IsOpen: null, - branchId: null, - }); - - const { projectId } = useParams(); - - const [search, setSearch] = useState(""); - const [currentPage, setCurrentPage] = useState(1); - const debouncedSearch = useDebounce(search, 500); - - const { data, isLoading, isError, error } = useBranches( - projectId, - true, - ITEMS_PER_PAGE, - currentPage, - debouncedSearch, - ); - const paginate = (page) => { - if (page >= 1 && page <= (data?.totalPages ?? 1)) { - setCurrentPage(page); - } - }; - - const ServiceBranch = [ - { - key: "branchName", - label: "Branch Name", - align: "text-start", - getValue: (e) => e?.branchName || "N/A", - }, - ]; - return ( -
-
-
-
- -
-
- - -
- {/* {Array.isArray(filteredData) && filteredData.length > 0 && ( */} - - - - {ServiceBranch.map((col) => ( - - ))} - - - - - {isLoading ? ( - - - - ) : isError ? ( - - - - ) : data?.data?.length > 0 ? ( - data.data.map((branch) => ( - - {ServiceBranch.map((col) => ( - - ))} - - - )) - ) : ( - - - - )} - -
- {col.label} - Action
- Loading... -
- {error?.message || "Error loading branches"} -
- {col.getValue(branch)} - - - setManageServiceBranch({ - IsOpen: true, - branchId: branch.id, - }) - } - /> -
- No Branch Found -
- {/* )} */} - {/* {!filteredData || - filteredData.length === 0 - && ( -
- {isError ? (

{error.message}

) : (

No Recurring Expense Found

)} -
- )} */} -
- - {ManageServiceBranch.IsOpen && ( - - setManageServiceBranch({ IsOpen: null, branchId: null }) - } - > - - setManageServiceBranch({ IsOpen: null, branchId: null }) - } - // requestToEdit={ManageServiceBranch.branchId} - /> - - )} - - {/* */} -
-
- ) -} - -export default ServiceBranch diff --git a/src/components/ServiceProject/ServiceProfile.jsx b/src/components/ServiceProject/ServiceProfile.jsx new file mode 100644 index 00000000..30864106 --- /dev/null +++ b/src/components/ServiceProject/ServiceProfile.jsx @@ -0,0 +1,95 @@ +import React from 'react' +import { formatUTCToLocalTime } from '../../utils/dateUtils' + +const ServiceProfile = ({data,setIsOpenModal}) => { + return ( +
+
+
+ {" "} + + Project Profile +
+
+
+
    + +
  • +
    + + Name: +
    + +
    + {data.name} +
    +
  • +
  • +
    + + Nick Name: +
    + {data.shortName} +
  • +
  • +
    + + Assign Date: +
    + + {data.assignedDate ? formatUTCToLocalTime(data.assignedDate) : "NA"} + +
  • + +
  • +
    + + Status: +
    + {data?.status.status} +
  • +
  • +
    + + Contact: +
    + {data.contactName} +
  • +
  • + {/* Label section with icon */} +
    + + Address: +
    + + {/* Content section that wraps nicely */} +
    + {data.address} +
    +
  • + + + +
  • + + + + + +
  • +
+ +
+
+ ) +} + +export default ServiceProfile diff --git a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx new file mode 100644 index 00000000..34cc0530 --- /dev/null +++ b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx @@ -0,0 +1,183 @@ +import React, { useEffect } from "react"; +import { useProjectName } from "../../../hooks/useProjects"; +import { useForm } from "react-hook-form"; +import { zodResolver } from "@hookform/resolvers/zod"; +import Label from "../../common/Label"; +import { + useCreateBranch, + useServiceProjects, + useUpdateBranch, +} from "../../../hooks/useServiceProject"; +import { useAppForm } from "../../../hooks/appHooks/useAppForm"; +import { useParams } from "react-router-dom"; +import { BranchSchema, defaultBranches } from "../ServiceProjectSchema"; + +const ManageBranch = ({ closeModal, BranchToEdit = null }) => { + const { data } = {}; + const { projectId } = useParams(); + const schema = BranchSchema(); + const { + register, + control, + watch, + handleSubmit, + setValue, + reset, + formState: { errors }, + } = useAppForm({ + resolver: zodResolver(schema), + defaultValues: { + ...defaultBranches, + projectId: projectId || "", + }, + }); + + const handleClose = () => { + reset(); + closeModal(); + }; + + useEffect(() => { + if (BranchToEdit && data) { + reset({ + branchName: data.branchName || "", + projectId: data.project?.id || projectId || "", + contactInformation: data.contactInformation || "", + address: data.address || "", + branchType: data.branchType || "", + googleMapUrl: data.googleMapUrl || "", + }); + } + }, [data, reset]); + + const { mutate: CreateServiceBranch, isPending: createPending } = + useCreateBranch(() => { + handleClose(); + }); + const { mutate: ServiceBranchUpdate, isPending } = useUpdateBranch(() => + handleClose() + ); + + const onSubmit = (fromdata) => { + let payload = { + ...fromdata, + projectId, + }; + if (BranchToEdit) { + const editPayload = { ...payload, id: data.id }; + ServiceBranchUpdate({ id: data.id, payload: editPayload }); + } else { + CreateServiceBranch(payload); + } + }; + + return ( +
+
+ {BranchToEdit ? "Update Branch" : "Create Branch"} +
+
+
+
+ + + {errors.branchName && ( + {errors.branchName.message} + )} +
+
+ + + {errors.contactInformation && ( + + {errors.contactInformation.message} + + )} +
+
+ +
+ +
+ + + {errors.branchType && ( + {errors.branchType.message} + )} +
+
+ + + {errors.googleMapUrl && ( + + {errors.googleMapUrl.message} + + )} +
+
+ +
+ +
+ + + + {errors?.comment && ( + {errors?.comment?.message} + )} +
+
+ {/*
+ {files?.length > 0 && ( + + )} +
*/} +
+
document.getElementById("attachments").click()} + className="cursor-pointer" + style={{ whiteSpace: "nowrap" }} + > + { + onFileChange(e); + e.target.value = ""; + }} + /> + + Add Attachment +
+ + +
+
+
+ ); +}; + +export default UpdateJobComment; diff --git a/src/components/ServiceProject/ServiceProjectSeketon.jsx b/src/components/ServiceProject/ServiceProjectSeketon.jsx new file mode 100644 index 00000000..b4b3a93e --- /dev/null +++ b/src/components/ServiceProject/ServiceProjectSeketon.jsx @@ -0,0 +1,138 @@ +import React from "react"; + +const SkeletonLine = ({ height = 18, width = "100%", className = "" }) => ( +
+); + +export const BranchDetailsSkeleton = () => { + return ( +
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+
+ ); +}; + +export const JobDetailsSkeleton = () => { + return ( +
+
+ {/* Title */} + + + {/* Job ID + Status */} +
+ +
+ + +
+
+ + {/* Description */} + + + {/* Created Date */} +
+ +
+ + {/* Start / Due Date */} +
+ + +
+ + {/* Branch Name */} +
+ + +
+ + {/* Created By */} +
+
+ +
+ +
+ {/* Avatar */} + +
+
+ + {/* Assigned To */} +
+
+ +
+
+ + {/* Tabs */} +
+
+ + + +
+ + +
+
+
+ ); +}; diff --git a/src/router/AppRoutes.jsx b/src/router/AppRoutes.jsx index 1c95ec64..3ef8131b 100644 --- a/src/router/AppRoutes.jsx +++ b/src/router/AppRoutes.jsx @@ -60,7 +60,7 @@ import PaymentRequestPage from "../pages/PaymentRequest/PaymentRequestPage"; import RecurringExpensePage from "../pages/RecurringExpense/RecurringExpensePage"; import AdvancePaymentPage from "../pages/AdvancePayment/AdvancePaymentPage"; import ServiceProjectDetail from "../pages/ServiceProject/ServiceProjectDetail"; -import ManageJob from "../components/ServiceProject/ManageJob"; +import ManageJob from "../components/ServiceProject/ServiceProjectJob/ManageJob"; const router = createBrowserRouter( [ { From 5b86a2f64f5c27b1d721cf4db88b40ea74906b0a Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Thu, 20 Nov 2025 09:50:49 +0530 Subject: [PATCH 13/17] removed console error --- src/components/Layout/Sidebar.jsx | 10 ++-- .../ServiceProjectJob/ManageJobTicket.jsx | 59 +------------------ 2 files changed, 8 insertions(+), 61 deletions(-) diff --git a/src/components/Layout/Sidebar.jsx b/src/components/Layout/Sidebar.jsx index 1f4b63b8..4fa7cd9f 100644 --- a/src/components/Layout/Sidebar.jsx +++ b/src/components/Layout/Sidebar.jsx @@ -25,8 +25,7 @@ const Sidebar = () => { /> */} - @@ -35,12 +34,13 @@ const Sidebar = () => { OnField Work .com - + - + + - +
diff --git a/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx b/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx index 1041d93c..12428c77 100644 --- a/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx +++ b/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx @@ -145,62 +145,9 @@ const ManageJobTicket = ({ Job }) => {
)} -
-
-
- Created By -
-
- {" "} -
-

{`${data?.createdBy?.firstName} ${data?.createdBy?.lastName}`}

- - ({data?.createdBy?.jobRoleName}) - -
-
-
- - {data?.assignees?.length > 0 && ( -
-
- Assigned To -
- -
-
- {data?.assignees?.map((emp) => ( -
-
- - -
- - {emp.firstName} {emp.lastName} - - - {emp.jobRoleName} - -
-
-
- ))} -
-
-
- )} -
+
+ People +
From dd716187da267263557fac390a222807ce6e58bf Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 20 Nov 2025 09:51:23 +0530 Subject: [PATCH 14/17] Implementing edit api for branches. --- .../ServiceProjectBranch/ManageBranch.jsx | 17 +- .../ServiceProjectBranch/ServiceBranch.jsx | 320 ++++++++++++------ src/hooks/useServiceProject.jsx | 51 +-- src/repositories/ServiceProjectRepository.jsx | 10 +- 4 files changed, 255 insertions(+), 143 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx index 34cc0530..11bcdafd 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx @@ -4,6 +4,7 @@ import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import Label from "../../common/Label"; import { + useBranchDetails, useCreateBranch, useServiceProjects, useUpdateBranch, @@ -13,7 +14,13 @@ import { useParams } from "react-router-dom"; import { BranchSchema, defaultBranches } from "../ServiceProjectSchema"; const ManageBranch = ({ closeModal, BranchToEdit = null }) => { - const { data } = {}; + const { + data, + isLoading, + isError, + error: requestError, + } = useBranchDetails(BranchToEdit); + const { projectId } = useParams(); const schema = BranchSchema(); const { @@ -112,7 +119,7 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
- +
-
+
@@ -146,7 +153,7 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => {
- +
diff --git a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx index 0cae102a..e168778b 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx @@ -1,19 +1,24 @@ import React, { useState } from "react"; import GlobalModel from "../../common/GlobalModel"; import ManageBranch from "./ManageBranch"; -import { useBranches } from "../../../hooks/useServiceProject"; +import { useBranches, useDeleteBranch } from "../../../hooks/useServiceProject"; import { ITEMS_PER_PAGE } from "../../../utils/constants"; import { useDebounce } from "../../../utils/appUtils"; import { useParams } from "react-router-dom"; import Pagination from "../../common/Pagination"; +import ConfirmModal from "../../common/ConfirmModal"; +import { SpinnerLoader } from "../../common/Loader"; const ServiceBranch = () => { const { projectId } = useParams(); - + const [IsDeleteModalOpen, setIsDeleteModalOpen] = useState(false); + const [showInactive, setShowInactive] = useState(false); const [manageState, setManageState] = useState({ IsOpen: false, branchId: null, }); + const { mutate: DeleteBranch, isPending } = useDeleteBranch(); + const [deletingId, setDeletingId] = useState(null); const [search, setSearch] = useState(""); const [currentPage, setCurrentPage] = useState(1); @@ -21,7 +26,8 @@ const ServiceBranch = () => { const { data, isLoading, isError, error } = useBranches( projectId, - true, + // true, + !showInactive, ITEMS_PER_PAGE - 10, currentPage, debouncedSearch @@ -42,132 +48,222 @@ const ServiceBranch = () => { }, ]; + const handleDelete = (id) => { + setDeletingId(id); + DeleteBranch( + { id, isActive: false }, + { + onSettled: () => { + setDeletingId(null); + setIsDeleteModalOpen(false); + }, + } + ); + }; return ( -
-
- {/* Header Section */} -
-
-
- - Branches -
+ <> + {IsDeleteModalOpen && ( + setIsDeleteModalOpen(false)} + loading={isPending} + paramData={deletingId} + /> + )} +
+
+ {/* Header Section */} +
+
+
+ + Branch +
+
+ + {/* Flex container for toggle + button */} +
+
+ + {/* Toggle Switch */} +
+ setShowInactive(!showInactive)} + /> + +
+ + {/* Add Branch Button */} + + +
+
+
-
- -
-
- -
- - - - {columns.map((col) => ( - - ))} - - - - - - {isLoading && ( +
+
- {col.label} - Action
+ - + {columns.map((col) => ( + + ))} + - )} + - {isError && ( - - - - )} - - {!isLoading && - !isError && - data?.data?.length > 0 && - data.data.map((branch) => ( - - {columns.map((col) => ( - - ))} - - - ))} - - {!isLoading && - !isError && - (!data?.data || data.data.length === 0) && ( + + {isLoading && ( )} - -
- Loading... - + {col.label} + Action
- {error?.message || "Error loading branches"} -
- {col.getValue(branch)} - - - setManageState({ - IsOpen: true, - branchId: branch.id, - }) - } - /> -
- No Branch Found +
+ +
- {data?.data?.length > 0 && ( - + + {isError && ( + + + {error?.message || "Error loading branches"} + + + )} + + {!isLoading && + !isError && + data?.data?.length > 0 && + data.data.map((branch) => ( + + {columns.map((col) => ( + + {col.getValue(branch)} + + ))} + +
+ + +
    + {/* Modify */} +
  • + setManageState({ + IsOpen: true, + branchId: branch.id, + }) + } + > + + + Modify + +
  • + + {/* Delete */} +
  • { + setIsDeleteModalOpen(true); + setDeletingId(branch.id); + }} + > + + + Delete + +
  • +
+
+ + + + ))} + + {!isLoading && + !isError && + (!data?.data || data.data.length === 0) && ( + + + No Branch Found + + + )} + + + + {data?.data?.length > 0 && ( + + )} +
+ + {manageState.IsOpen && ( + setManageState({ IsOpen: false, branchId: null })} + > + + setManageState({ IsOpen: false, branchId: null }) + } + /> + + )}
- - {manageState.IsOpen && ( - setManageState({ IsOpen: false, branchId: null })} - > - - setManageState({ IsOpen: false, branchId: null }) - } - /> - - )}
-
+ ); }; diff --git a/src/hooks/useServiceProject.jsx b/src/hooks/useServiceProject.jsx index 3278fa2a..93817800 100644 --- a/src/hooks/useServiceProject.jsx +++ b/src/hooks/useServiceProject.jsx @@ -315,12 +315,12 @@ export const useBranches = ( }; -export const useBranch = (id)=>{ +export const useBranchDetails = (id) => { return useQuery({ queryKey: ["branch", id], queryFn: async () => { const resp = await ServiceProjectRepository.GetBranchDetail(id); - return resp.data ?? resp; + return resp.data; }, enabled: !!id }) @@ -346,37 +346,42 @@ export const useCreateBranch = (onSuccessCallBack) => { }, }); }; - -export const useUpdateBranch = () => { +export const useUpdateBranch = (onSuccessCallBack) => { const queryClient = useQueryClient(); return useMutation({ - mutationFn: async ({ id, payload }) => await ServiceProjectRepository.UpdateBranch(id, payload), + mutationFn: async ({ id, payload }) => + await ServiceProjectRepository.UpdateBranch(id, payload), + onSuccess: (_, variables) => { + // remove old single-branch cache + queryClient.removeQueries({ queryKey: ["branch", variables.id] }); + + // refresh list queryClient.invalidateQueries({ queryKey: ["branches"] }); - queryClient.invalidateQueries({ queryKey: ["branch", variables.id] }); - if (onSuccessCallback) onSuccessCallback(); - showToast("Branch Updated successfully", "success"); + + showToast("Branch updated successfully", "success"); + onSuccessCallBack?.(); }, - onError: (error) => { - showToast( - error?.response?.data?.message || - error.message || - "Failed to update branch", - "error" - ); + + onError: () => { + showToast("Something went wrong. Please try again later.", "error"); }, - }) -} + }); +}; + export const useDeleteBranch = () => { const queryClient = useQueryClient(); + return useMutation({ - mutationFn: async (id) => await ServiceProjectRepository.DeleteBranch(id), - onSuccess: (_, variables) => { + mutationFn: async ({ id, isActive}) => + await ServiceProjectRepository.DeleteBranch(id, isActive), + + onSuccess: () => { queryClient.invalidateQueries({ queryKey: ["branches"] }); - if (onSuccessCallback) onSuccessCallback(); - showToast("Branch Deleted successfully", "success"); + showToast("Branch deleted successfully", "success"); }, + onError: (error) => { showToast( error?.response?.data?.message || @@ -385,5 +390,5 @@ export const useDeleteBranch = () => { "error" ); }, - }) -} \ No newline at end of file + }); +}; diff --git a/src/repositories/ServiceProjectRepository.jsx b/src/repositories/ServiceProjectRepository.jsx index 1fa29fa9..23fe8b38 100644 --- a/src/repositories/ServiceProjectRepository.jsx +++ b/src/repositories/ServiceProjectRepository.jsx @@ -1,3 +1,4 @@ +import { isAction } from "@reduxjs/toolkit"; import { api } from "../utils/axiosClient"; export const ServiceProjectRepository = { @@ -43,14 +44,17 @@ export const ServiceProjectRepository = { //#region Project Branch CreateBranch: (data) => api.post(`/api/ServiceProject/branch/create`, data), UpdateBranch: (id, data) => - api.put("/api/ServiceProject/branch/edit/${id}", data), + api.put(`/api/ServiceProject/branch/edit/${id}`, data), + GetBranchList: (projectId, isActive, pageSize, pageNumber, searchString) => { return api.get( `/api/ServiceProject/branch/list/${projectId}?isActive=${isActive}&pageSize=${pageSize}&pageNumber=${pageNumber}&searchString=${searchString}` ); - }, + }, GetBranchDetail: (id) => api.get(`/api/ServiceProject/branch/details/${id}`), - DeleteBranch: (id) => api.delete(`/api/ServiceProject/branch/delete/${id}`), + DeleteBranch: (id, isActive = false) => + api.delete(`/api/ServiceProject/branch/delete/${id}?isActive=${isActive}`), + }; From 195a0c83bb8a0fea2bb634cb6efea183703821d6 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 20 Nov 2025 10:00:06 +0530 Subject: [PATCH 15/17] Correction in api for details. --- .../ServiceProject/ServiceProjectBranch/BranchDetails.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx index 66bd700c..2aefa4ad 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { useBranch } from "../../../hooks/useServiceProject"; +import { useBranchDetails } from "../../../hooks/useServiceProject"; import { SpinnerLoader } from "../../common/Loader"; import Error from "../../common/Error"; import { BranchDetailsSkeleton } from "../ServiceProjectSeketon"; @@ -7,7 +7,7 @@ import { BranchDetailsSkeleton } from "../ServiceProjectSeketon"; const BranchDetails = ({ branch }) => { const [copied, setCopied] = useState(false); - const { data, isLoading, isError, error } = useBranch(branch); + const { data, isLoading, isError, error } = useBranchDetails(branch); const googleMapUrl = data?.googleMapUrl || data?.locationLink; From d3c006279c7614ec0f1f377b08e3b61805682071 Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 20 Nov 2025 10:29:42 +0530 Subject: [PATCH 16/17] Increasing the size of Service details page. --- .../ServiceProject/ServiceProjectBranch/ServiceBranch.jsx | 4 +--- src/components/ServiceProject/ServiceProjectProfile.jsx | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx index e168778b..0655247f 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ServiceBranch.jsx @@ -117,10 +117,8 @@ const ServiceBranch = () => { Add Branch -
-
@@ -170,7 +168,7 @@ const ServiceBranch = () => { !isError && data?.data?.length > 0 && data.data.map((branch) => ( - + {columns.map((col) => ( {col.getValue(branch)} diff --git a/src/components/ServiceProject/ServiceProjectProfile.jsx b/src/components/ServiceProject/ServiceProjectProfile.jsx index 2a04be99..6ef359ff 100644 --- a/src/components/ServiceProject/ServiceProjectProfile.jsx +++ b/src/components/ServiceProject/ServiceProjectProfile.jsx @@ -33,11 +33,11 @@ const ServiceProjectProfile = () => { )}
-
+
-
+
From d167c57ab01c5fc7210a002ec54b0dde85acad6c Mon Sep 17 00:00:00 2001 From: Kartik Sharma Date: Thu, 20 Nov 2025 12:34:45 +0530 Subject: [PATCH 17/17] Implementing the Update api for branches. --- .../ServiceProjectBranch/ManageBranch.jsx | 221 +++++++++++++++--- .../ServiceProject/ServiceProjectSchema.jsx | 8 +- 2 files changed, 196 insertions(+), 33 deletions(-) diff --git a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx index 11bcdafd..720fa08f 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/ManageBranch.jsx @@ -21,6 +21,15 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { error: requestError, } = useBranchDetails(BranchToEdit); + const [contacts, setContacts] = React.useState([ + { + contactPerson: "", + designation: "", + contactEmails: [""], + contactNumbers: [""] + } + ]); + const { projectId } = useParams(); const schema = BranchSchema(); const { @@ -49,14 +58,22 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { reset({ branchName: data.branchName || "", projectId: data.project?.id || projectId || "", - contactInformation: data.contactInformation || "", address: data.address || "", branchType: data.branchType || "", googleMapUrl: data.googleMapUrl || "", }); + + if (data.contactInformation) { + try { + setContacts(JSON.parse(data.contactInformation)); + } catch { + setContacts([]); + } + } } }, [data, reset]); + const { mutate: CreateServiceBranch, isPending: createPending } = useCreateBranch(() => { handleClose(); @@ -65,19 +82,23 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { handleClose() ); - const onSubmit = (fromdata) => { + const onSubmit = (formdata) => { let payload = { - ...fromdata, + ...data, + ...formdata, projectId, + contactInformation: JSON.stringify(contacts), // ← important }; + if (BranchToEdit) { - const editPayload = { ...payload, id: data.id }; - ServiceBranchUpdate({ id: data.id, payload: editPayload }); + ServiceBranchUpdate({ id: data.id, payload }); } else { CreateServiceBranch(payload); } }; + + return (
@@ -100,26 +121,6 @@ const ManageBranch = ({ closeModal, BranchToEdit = null }) => { {errors.branchName.message} )}
-
- - - {errors.contactInformation && ( - - {errors.contactInformation.message} - - )} -
-
- -
-
+
+ +
+ +
-
+
+
+ + + {contacts.map((item, index) => ( +
+ + {/* Contact Person + Designation */} +
+
+ { + const list = [...contacts]; + list[index].contactPerson = e.target.value; + setContacts(list); + }} + /> +
+ +
+ { + const list = [...contacts]; + list[index].designation = e.target.value; + setContacts(list); + }} + /> +
+ + {/* Remove entire contact */} +
+ + setContacts(contacts.filter((_, i) => i !== index)) + } + > +
+
+ + {/* Numbers Section */} + + + {item.contactNumbers.map((num, numIndex) => ( +
+ + { + const value = e.target.value.replace(/\D/g, ""); // remove non-digit characters + const list = [...contacts]; + list[index].contactNumbers[numIndex] = value; + setContacts(list); + }} + /> + + {/* Show PLUS only on last row */} + {numIndex === item.contactNumbers.length - 1 ? ( + { + const list = [...contacts]; + list[index].contactNumbers.push(""); + setContacts(list); + }} + > + ) : ( + { + const list = [...contacts]; + list[index].contactNumbers.splice(numIndex, 1); + setContacts(list); + }} + > + )} + +
+ ))} + +
+ + {/* Emails Section */} + + + {item.contactEmails.map((email, emailIndex) => ( +
+ + { + const list = [...contacts]; + list[index].contactEmails[emailIndex] = e.target.value; + setContacts(list); + }} + /> + + {/* Show PLUS only on the last row */} + {emailIndex === item.contactEmails.length - 1 ? ( + { + const list = [...contacts]; + list[index].contactEmails.push(""); + setContacts(list); + }} + > + ) : ( + { + const list = [...contacts]; + list[index].contactEmails.splice(emailIndex, 1); + setContacts(list); + }} + > + )} + +
+ ))} + + +
+ ))} + + + + +
+
+ +
diff --git a/src/components/ServiceProject/ServiceProjectSchema.jsx b/src/components/ServiceProject/ServiceProjectSchema.jsx index dc8a6713..589f1497 100644 --- a/src/components/ServiceProject/ServiceProjectSchema.jsx +++ b/src/components/ServiceProject/ServiceProjectSchema.jsx @@ -138,11 +138,7 @@ export const BranchSchema = () => .trim() .min(1, { message: "Branch Name is required" }), - contactInformation: z - .string() - .trim() - .min(1, { message: "Contact Information is required" }), - + contactInformation: z.string().optional(), address: z .string() .trim() @@ -155,8 +151,6 @@ export const BranchSchema = () => googleMapUrl: z .string() - .trim() - .url({ message: "Enter a valid Google Map URL" }), }); export const defaultBranches = {