From e99d49b83e9434529cd432a7c8e5da2bcfee631c Mon Sep 17 00:00:00 2001 From: "pramod.mahajan" Date: Thu, 20 Nov 2025 09:26:02 +0530 Subject: [PATCH] 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( [ {