From 0210e1717058e91238b48891c6b6d99659d5a533 Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Wed, 19 Nov 2025 22:58:41 +0530 Subject: [PATCH 1/3] added branch details --- src/components/ServiceProject/ManageJob.jsx | 6 +- .../ServiceProject/ManageJobTicket.jsx | 23 ++- .../ServiceProjectBranch/BranchDetails.jsx | 25 ++++ .../ServiceProject/ServiceProjectSchema.jsx | 2 +- src/components/common/HoverPopup.jsx | 140 +++++++++++++----- 5 files changed, 149 insertions(+), 47 deletions(-) create mode 100644 src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx diff --git a/src/components/ServiceProject/ManageJob.jsx b/src/components/ServiceProject/ManageJob.jsx index 6ec96e3b..1ba3a04a 100644 --- a/src/components/ServiceProject/ManageJob.jsx +++ b/src/components/ServiceProject/ManageJob.jsx @@ -165,7 +165,7 @@ const ManageJob = ({ Job }) => { dueDate: JobData.dueDate ?? null, tags: JobData.tags ?? [], statusId: JobData.status.id, - branchId : JobData?.projectBranch?.id + projectBranchId : JobData?.projectBranch?.id }); }, [JobData, Job, projectId]); return ( @@ -248,8 +248,8 @@ const ManageJob = ({ Job }) => { setValue("branchId", val)} + value={watch("projectBranchId")} + onChange={(val) => setValue("projectBranchId", val)} valueKey="id" labelKey="branchName" hookParams={[projectId, true, 10, 1]} diff --git a/src/components/ServiceProject/ManageJobTicket.jsx b/src/components/ServiceProject/ManageJobTicket.jsx index c589509c..4399d490 100644 --- a/src/components/ServiceProject/ManageJobTicket.jsx +++ b/src/components/ServiceProject/ManageJobTicket.jsx @@ -1,4 +1,4 @@ -import React, { useEffect } from "react"; +import React, { useEffect, useRef } from "react"; import { useServiceProjectJobDetails } from "../../hooks/useServiceProject"; import { SpinnerLoader } from "../common/Loader"; import Error from "../common/Error"; @@ -13,13 +13,14 @@ import ChangeStatus from "./ChangeStatus"; import { useParams } from "react-router-dom"; import { STATUS_JOB_CLOSED } from "../../utils/constants"; import Tooltip from "../common/Tooltip"; +import BranchDetails from "./ServiceProjectBranch/BranchDetails"; const ManageJobTicket = ({ Job }) => { const { projectId } = useParams(); const { data, isLoading, isError, error } = useServiceProjectJobDetails( Job?.job ); - +const drawerRef = useRef(); const tabsData = [ { id: "comment", @@ -124,12 +125,18 @@ const ManageJobTicket = ({ Job }) => { ); })()} -
- - {" "} - Branch Name : - -
+ {data?.projectBranch && ( +
+ + {" "} + Branch Name : + + } > + {data?.projectBranch?.branchName} + +
+ )} +
diff --git a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx new file mode 100644 index 00000000..1160ccfe --- /dev/null +++ b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx @@ -0,0 +1,25 @@ +import React from 'react' +import { useBranch } from '../../../hooks/useServiceProject' +import { SpinnerLoader } from '../../common/Loader' +import Error from '../../common/Error' + +const BranchDetails = ({branch}) => { + const {data,isLoading,isError,error} = useBranch(branch) + if(isLoading) return
+ if(isError) return
+ return ( +
+
+ Name: {data.branchName} +
+
+ Type: {data.branchType} +
+
+ Address: {data.address} +
+
+ ) +} + +export default BranchDetails diff --git a/src/components/ServiceProject/ServiceProjectSchema.jsx b/src/components/ServiceProject/ServiceProjectSchema.jsx index 38013cae..dc8a6713 100644 --- a/src/components/ServiceProject/ServiceProjectSchema.jsx +++ b/src/components/ServiceProject/ServiceProjectSchema.jsx @@ -75,7 +75,7 @@ export const jobSchema = z.object({ statusId: z.string().optional().nullable(), - branchId: z.string().optional().nullable(), + projectBranchId: z.string().optional().nullable(), }); const MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB diff --git a/src/components/common/HoverPopup.jsx b/src/components/common/HoverPopup.jsx index e1c2dd4d..2093c25a 100644 --- a/src/components/common/HoverPopup.jsx +++ b/src/components/common/HoverPopup.jsx @@ -1,11 +1,11 @@ -import React, { useEffect, useMemo, useRef, useState } from "react"; +import React, { useEffect, useRef } from "react"; import { useDispatch, useSelector } from "react-redux"; -import { - closePopup, - openPopup, - togglePopup, -} from "../../slices/localVariablesSlice"; +import { closePopup, openPopup, togglePopup } from "../../slices/localVariablesSlice"; +/** + * align: "auto" | "left" | "right" + * boundaryRef: optional ref to the drawer/container element to use as boundary + */ const HoverPopup = ({ id, title, @@ -13,6 +13,8 @@ const HoverPopup = ({ children, className = "", Mode = "hover", + align = "auto", + boundaryRef = null, }) => { const dispatch = useDispatch(); const visible = useSelector((s) => s.localVariables.popups[id] || false); @@ -23,11 +25,9 @@ const HoverPopup = ({ const handleMouseEnter = () => { if (Mode === "hover") dispatch(openPopup(id)); }; - const handleMouseLeave = () => { if (Mode === "hover") dispatch(closePopup(id)); }; - const handleClick = (e) => { if (Mode === "click") { e.stopPropagation(); @@ -35,43 +35,111 @@ const HoverPopup = ({ } }; + // Close on outside click when using click mode useEffect(() => { if (Mode !== "click" || !visible) return; - const handleOutside = (e) => { + const handler = (e) => { if ( - !popupRef.current?.contains(e.target) && - !triggerRef.current?.contains(e.target) + popupRef.current && + !popupRef.current.contains(e.target) && + triggerRef.current && + !triggerRef.current.contains(e.target) ) { dispatch(closePopup(id)); } }; - document.addEventListener("click", handleOutside); - return () => document.removeEventListener("click", handleOutside); - }, [visible, Mode, id]); + document.addEventListener("click", handler); + return () => document.removeEventListener("click", handler); + }, [Mode, visible, dispatch, id]); + + // Positioning effect: respects align prop and stays inside boundary (drawer) useEffect(() => { - if (!visible || !popupRef.current) return; + if (!visible || !popupRef.current || !triggerRef.current) return; - const popup = popupRef.current; - const rect = popup.getBoundingClientRect(); + // run in next frame so DOM/layout settles + requestAnimationFrame(() => { + const popup = popupRef.current; - popup.style.left = "50%"; - popup.style.right = "auto"; - popup.style.transform = "translateX(-50%)"; + // choose boundary: provided boundaryRef or nearest positioned parent (popup.parentElement) + const boundaryEl = (boundaryRef && boundaryRef.current) || popup.parentElement; + if (!boundaryEl) return; - if (rect.right > window.innerWidth) { - popup.style.left = "auto"; - popup.style.right = "0"; - popup.style.transform = "none"; - } + const boundaryRect = boundaryEl.getBoundingClientRect(); + const triggerRect = triggerRef.current.getBoundingClientRect(); - if (rect.left < 0) { - popup.style.left = "0"; - popup.style.right = "auto"; - popup.style.transform = "none"; - } - }, [visible]); + // reset styles first + popup.style.left = ""; + popup.style.right = ""; + popup.style.transform = ""; + popup.style.top = ""; + + // default: place below trigger and center horizontally relative to parent + // We'll use absolute positioning with respect to the positioned parent container. + // Ensure popup is positioned using left/right in parent's coordinate system. + // Compute desired left (centered under trigger) + const popupRect = popup.getBoundingClientRect(); + const parentRect = boundaryRect; // alias + + // Convert trigger center to parent coordinates + const triggerCenterX = triggerRect.left + triggerRect.width / 2 - parentRect.left; + + // preferred left so popup center aligns to trigger center: + const preferredLeft = triggerCenterX - popupRect.width / 2; + + // Helpers to set styles in parent's coordinate system: + const setLeft = (leftPx) => { + popup.style.left = `${leftPx}px`; + popup.style.right = "auto"; + popup.style.transform = "none"; + }; + const setRight = (rightPx) => { + popup.style.left = "auto"; + popup.style.right = `${rightPx}px`; + popup.style.transform = "none"; + }; + + // If user forced align: + if (align === "left") { + // align popup's left to parent's left (0) + setLeft(0); + return; + } + if (align === "right") { + // align popup's right to parent's right (0) + setRight(0); + return; + } + + // align === "auto": try preferred centered position, but flip fully if overflow + // clamp preferredLeft to boundaries so it doesn't render partially outside + const leftIfCentered = Math.max(0, Math.min(preferredLeft, parentRect.width - popupRect.width)); + + // if centered fits, use it + if (leftIfCentered === preferredLeft) { + setLeft(leftIfCentered); + return; + } + + // if centering would overflow right -> stick popup fully to left (left=0) + if (preferredLeft > parentRect.width - popupRect.width) { + // place popup so its right aligns to parent's right + // i.e., left = parent width - popup width + setLeft(parentRect.width - popupRect.width); + return; + } + + // if centering would overflow left -> stick popup fully to left=0 + if (preferredLeft < 0) { + setLeft(0); + return; + } + + // fallback center + setLeft(leftIfCentered); + }); + }, [visible, align, boundaryRef]); return (
@@ -88,16 +156,18 @@ const HoverPopup = ({ {visible && (
e.stopPropagation()} > {title &&
{title}
} -
{content}
)} From e99d49b83e9434529cd432a7c8e5da2bcfee631c Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Thu, 20 Nov 2025 09:26:02 +0530 Subject: [PATCH 2/3] added view comments --- src/components/ServiceProject/Jobs.jsx | 4 +- .../ServiceProjectBranch/BranchDetails.jsx | 105 ++++++++++--- .../{ => ServiceProjectJob}/ChangeStatus.jsx | 18 ++- .../{ => ServiceProjectJob}/JobComments.jsx | 96 ++++++------ .../{ => ServiceProjectJob}/JobStatusLog.jsx | 5 +- .../{ => ServiceProjectJob}/ManageJob.jsx | 28 ++-- .../ManageJobTicket.jsx | 50 ++++--- .../ServiceProjectJob/UpdateJobComment.jsx | 80 ++++++++++ .../ServiceProject/ServiceProjectSeketon.jsx | 138 ++++++++++++++++++ src/router/AppRoutes.jsx | 2 +- 10 files changed, 410 insertions(+), 116 deletions(-) rename src/components/ServiceProject/{ => ServiceProjectJob}/ChangeStatus.jsx (83%) rename src/components/ServiceProject/{ => ServiceProjectJob}/JobComments.jsx (67%) rename src/components/ServiceProject/{ => ServiceProjectJob}/JobStatusLog.jsx (94%) rename src/components/ServiceProject/{ => ServiceProjectJob}/ManageJob.jsx (90%) rename src/components/ServiceProject/{ => ServiceProjectJob}/ManageJobTicket.jsx (84%) create mode 100644 src/components/ServiceProject/ServiceProjectJob/UpdateJobComment.jsx create mode 100644 src/components/ServiceProject/ServiceProjectSeketon.jsx diff --git a/src/components/ServiceProject/Jobs.jsx b/src/components/ServiceProject/Jobs.jsx index d6339174..3859fb3a 100644 --- a/src/components/ServiceProject/Jobs.jsx +++ b/src/components/ServiceProject/Jobs.jsx @@ -5,8 +5,8 @@ import { useServiceProjects } from "../../hooks/useServiceProject"; import { ITEMS_PER_PAGE } from "../../utils/constants"; import OffcanvasComponent from "../common/OffcanvasComponent"; import showToast from "../../services/toastService"; -import ManageJob from "./ManageJob"; -import ManageJobTicket from "./ManageJobTicket"; +import ManageJob from "./ServiceProjectJob/ManageJob"; +import ManageJobTicket from "./ServiceProjectJob/ManageJobTicket"; import GlobalModel from "../common/GlobalModel"; import PreviewDocument from "../Expenses/PreviewDocument"; diff --git a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx index 1160ccfe..66bd700c 100644 --- a/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx +++ b/src/components/ServiceProject/ServiceProjectBranch/BranchDetails.jsx @@ -1,25 +1,86 @@ -import React from 'react' -import { useBranch } from '../../../hooks/useServiceProject' -import { SpinnerLoader } from '../../common/Loader' -import Error from '../../common/Error' +import React, { useState } from "react"; +import { useBranch } from "../../../hooks/useServiceProject"; +import { SpinnerLoader } from "../../common/Loader"; +import Error from "../../common/Error"; +import { BranchDetailsSkeleton } from "../ServiceProjectSeketon"; -const BranchDetails = ({branch}) => { - const {data,isLoading,isError,error} = useBranch(branch) - if(isLoading) return
- if(isError) return
+const BranchDetails = ({ branch }) => { + const [copied, setCopied] = useState(false); + + const { data, isLoading, isError, error } = useBranch(branch); + + const googleMapUrl = data?.googleMapUrl || data?.locationLink; + + const handleCopy = async () => { + if (!googleMapUrl) return; + + await navigator.clipboard.writeText(googleMapUrl); + setCopied(true); + + setTimeout(() => setCopied(false), 3000); + }; + if (isLoading) return ; + if (isError) + return ( +
+ +
+ ); return ( -
-
- Name: {data.branchName} -
-
- Type: {data.branchType} -
-
- Address: {data.address} -
-
- ) -} +
+
+ + Branch Details + +
+
+
Name:
+
{data?.branchName}
+
-export default BranchDetails +
+
Type:
+
{data?.branchType}
+
+
+
Contact No:
+
{data?.contactInformation}
+
+ +
+
Address:
+
{data?.address}
+
+ + {googleMapUrl && ( +
+
Map:
+ +
+ + Open in Google Maps + + + + + {copied && Copied!} +
+
+ )} +
+ ); +}; + +export default BranchDetails; diff --git a/src/components/ServiceProject/ChangeStatus.jsx b/src/components/ServiceProject/ServiceProjectJob/ChangeStatus.jsx similarity index 83% rename from src/components/ServiceProject/ChangeStatus.jsx rename to src/components/ServiceProject/ServiceProjectJob/ChangeStatus.jsx index 49b2fc70..935c621d 100644 --- a/src/components/ServiceProject/ChangeStatus.jsx +++ b/src/components/ServiceProject/ServiceProjectJob/ChangeStatus.jsx @@ -1,17 +1,16 @@ -import SelectField from "../common/Forms/SelectField"; -import { useJobStatus } from "../../hooks/masterHook/useMaster"; -import { SpinnerLoader } from "../common/Loader"; -import Error from "../common/Error"; +import SelectField from "../../common/Forms/SelectField"; +import Error from "../../common/Error"; import { z } from "zod"; import { AppFormController, AppFormProvider, useAppForm, -} from "../../hooks/appHooks/useAppForm"; +} from "../../../hooks/appHooks/useAppForm"; import { zodResolver } from "@hookform/resolvers/zod"; import { useDispatch, useSelector } from "react-redux"; -import { closePopup } from "../../slices/localVariablesSlice"; -import { useUpdateServiceProjectJob } from "../../hooks/useServiceProject"; +import { closePopup } from "../../../slices/localVariablesSlice"; +import { useUpdateServiceProjectJob } from "../../../hooks/useServiceProject"; +import { useJobStatus } from "../../../hooks/masterHook/useMaster"; export const ChangeStatusSchema = z.object({ statusId: z.string().min(1, { message: "Please select status" }), @@ -53,6 +52,11 @@ const ChangeStatus = ({ statusId, projectId, jobId, popUpId }) => { }; return ( +
+ + Change Status + +
{ const { @@ -161,46 +161,48 @@ const JobComments = ({ data }) => { const user = item?.createdBy; return ( -
-
- -
-
- - {user?.firstName} {user?.lastName} - - - {formatUTCToLocalTime(item?.createdAt, true)} - -
-
- {user?.jobRoleName} -
-
-

{item.comment}

-
- {item.attachments?.map((file) => ( -
- -
-

{file.fileName}

- - {formatFileSize(file.fileSize)} - -
+
+ + +
+
+ + {user?.firstName} {user?.lastName} + + + + {formatUTCToLocalTime(item?.createdAt, true)} + + +
+ +
+ {user?.jobRoleName} +
+ +
+

{item.comment}

+ +
+ {item.attachments?.map((file) => ( +
+ +
+

{file.fileName}

+ + {formatFileSize(file.fileSize)} +
- ))} -
+
+ ))}
diff --git a/src/components/ServiceProject/JobStatusLog.jsx b/src/components/ServiceProject/ServiceProjectJob/JobStatusLog.jsx similarity index 94% rename from src/components/ServiceProject/JobStatusLog.jsx rename to src/components/ServiceProject/ServiceProjectJob/JobStatusLog.jsx index 88ff3562..bf13b7e5 100644 --- a/src/components/ServiceProject/JobStatusLog.jsx +++ b/src/components/ServiceProject/ServiceProjectJob/JobStatusLog.jsx @@ -1,6 +1,7 @@ import React from "react"; -import Avatar from "../common/Avatar"; -import { formatUTCToLocalTime } from "../../utils/dateUtils"; +import Avatar from "../../common/Avatar"; +import { formatUTCToLocalTime } from "../../../utils/dateUtils"; + const JobStatusLog = ({ data }) => { return ( diff --git a/src/components/ServiceProject/ManageJob.jsx b/src/components/ServiceProject/ServiceProjectJob/ManageJob.jsx similarity index 90% rename from src/components/ServiceProject/ManageJob.jsx rename to src/components/ServiceProject/ServiceProjectJob/ManageJob.jsx index 1ba3a04a..cc2066e0 100644 --- a/src/components/ServiceProject/ManageJob.jsx +++ b/src/components/ServiceProject/ServiceProjectJob/ManageJob.jsx @@ -1,8 +1,8 @@ import React, { useEffect, useState } from "react"; -import Breadcrumb from "../common/Breadcrumb"; -import Label from "../common/Label"; +import Breadcrumb from "../../common/Breadcrumb"; +import Label from "../../common/Label"; import { zodResolver } from "@hookform/resolvers/zod"; -import { defaultJobValue, jobSchema } from "./ServiceProjectSchema"; +import { defaultJobValue, jobSchema } from "../ServiceProjectSchema"; import { useBranches, useCreateServiceProjectJob, @@ -10,23 +10,23 @@ import { useServiceProjectJobDetails, useServiceProjects, useUpdateServiceProjectJob, -} from "../../hooks/useServiceProject"; -import { ITEMS_PER_PAGE } from "../../utils/constants"; -import DatePicker from "../common/DatePicker"; -import PmsEmployeeInputTag from "../common/PmsEmployeeInputTag"; -import TagInput from "../common/TagInput"; -import { localToUtc } from "../../utils/appUtils"; -import SelectField from "../common/Forms/SelectField"; +} from "../../../hooks/useServiceProject"; +import { ITEMS_PER_PAGE } from "../../../utils/constants"; +import DatePicker from "../../common/DatePicker"; +import PmsEmployeeInputTag from "../../common/PmsEmployeeInputTag"; +import TagInput from "../../common/TagInput"; +import { localToUtc } from "../../../utils/appUtils"; +import SelectField from "../../common/Forms/SelectField"; import { AppFormController, AppFormProvider, useAppForm, -} from "../../hooks/appHooks/useAppForm"; +} from "../../../hooks/appHooks/useAppForm"; 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"; +import { useJobStatus } from "../../../hooks/masterHook/useMaster"; +import { useServiceProjectJobContext } from "../Jobs"; +import { SelectFieldSearch } from "../../common/Forms/SelectFieldServerSide"; const ManageJob = ({ Job }) => { const { setManageJob, setSelectedJob } = useServiceProjectJobContext(); diff --git a/src/components/ServiceProject/ManageJobTicket.jsx b/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx similarity index 84% rename from src/components/ServiceProject/ManageJobTicket.jsx rename to src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx index 4399d490..1041d93c 100644 --- a/src/components/ServiceProject/ManageJobTicket.jsx +++ b/src/components/ServiceProject/ServiceProjectJob/ManageJobTicket.jsx @@ -1,26 +1,27 @@ import React, { useEffect, useRef } from "react"; -import { useServiceProjectJobDetails } from "../../hooks/useServiceProject"; -import { SpinnerLoader } from "../common/Loader"; -import Error from "../common/Error"; -import { formatUTCToLocalTime } from "../../utils/dateUtils"; -import Avatar from "../common/Avatar"; -import EmployeeAvatarGroup from "../common/EmployeeAvatarGroup"; -import JobStatusLog from "./JobStatusLog"; -import JobComments from "./JobComments"; -import { daysLeft, getJobStatusBadge } from "../../utils/appUtils"; -import HoverPopup from "../common/HoverPopup"; +import { useServiceProjectJobDetails } from "../../../hooks/useServiceProject"; +import { SpinnerLoader } from "../../common/Loader"; +import Error from "../../common/Error"; +import { formatUTCToLocalTime } from "../../../utils/dateUtils"; +import Avatar from "../../common/Avatar"; +import EmployeeAvatarGroup from "../../common/EmployeeAvatarGroup"; +import { daysLeft, getJobStatusBadge } from "../../../utils/appUtils"; +import HoverPopup from "../../common/HoverPopup"; import ChangeStatus from "./ChangeStatus"; import { useParams } from "react-router-dom"; -import { STATUS_JOB_CLOSED } from "../../utils/constants"; -import Tooltip from "../common/Tooltip"; -import BranchDetails from "./ServiceProjectBranch/BranchDetails"; +import { STATUS_JOB_CLOSED } from "../../../utils/constants"; +import Tooltip from "../../common/Tooltip"; +import BranchDetails from "../ServiceProjectBranch/BranchDetails"; +import { JobDetailsSkeleton } from "../ServiceProjectSeketon"; +import JobComments from "./JobComments"; +import JobStatusLog from "./JobStatusLog"; const ManageJobTicket = ({ Job }) => { const { projectId } = useParams(); const { data, isLoading, isError, error } = useServiceProjectJobDetails( Job?.job ); -const drawerRef = useRef(); + const drawerRef = useRef(); const tabsData = [ { id: "comment", @@ -38,7 +39,7 @@ const drawerRef = useRef(); }, ]; - if (isLoading) return ; + if (isLoading) return ; if (isError) return (
@@ -46,7 +47,7 @@ const drawerRef = useRef();
); return ( -
+
{data?.title}
@@ -62,7 +63,6 @@ const drawerRef = useRef(); {STATUS_JOB_CLOSED !== data?.status?.id && ( - {" "} - Branch Name : + Branch Name : - } > - {data?.projectBranch?.branchName} + + } + > + + {data?.projectBranch?.branchName} +
)} diff --git a/src/components/ServiceProject/ServiceProjectJob/UpdateJobComment.jsx b/src/components/ServiceProject/ServiceProjectJob/UpdateJobComment.jsx new file mode 100644 index 00000000..48ce3e27 --- /dev/null +++ b/src/components/ServiceProject/ServiceProjectJob/UpdateJobComment.jsx @@ -0,0 +1,80 @@ +import React from "react"; +import { useAppForm } from "../../../hooks/appHooks/useAppForm"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { JobCommentSchema } from "../ServiceProjectSchema"; +import Avatar from "../../common/Avatar"; +import Filelist from "../../Expenses/Filelist"; + +const UpdateJobComment = () => { + const { + register, + handleSubmit, + watch, + reset, + setValue, + formState: { errors }, + } = useAppForm({ + resolver: zodResolver(JobCommentSchema), + defaultValues: { comment: "", attachments: [] }, + }); + const onSubmit = () => {}; + return ( +
+ +
+ + +
+ + + {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 3/3] 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 +