added view comments
This commit is contained in:
parent
0210e17170
commit
e99d49b83e
@ -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";
|
||||
|
||||
|
||||
@ -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 <div><SpinnerLoader/></div>
|
||||
if(isError) return <div><Error error={error}/></div>
|
||||
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 <BranchDetailsSkeleton />;
|
||||
if (isError)
|
||||
return (
|
||||
<div>
|
||||
<Error error={error} />
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className='row w-auto'>
|
||||
<div className='col-12 d-flex flex-row gap-3'>
|
||||
<span className='text-secondry'>Name:</span> <span>{data.branchName}</span>
|
||||
</div>
|
||||
<div className='col-12 d-flex flex-row gap-3'>
|
||||
<span className='text-secondry'>Type:</span> <span>{data.branchType}</span>
|
||||
</div>
|
||||
<div className='col-12 d-flex flex-row gap-3'>
|
||||
<span className='text-secondry'>Address:</span> <span>{data.address}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className="">
|
||||
<div className="d-flex mb-2">
|
||||
<span className="fs-6 fw-medium">
|
||||
<i className="bx bx-sm me-2 bx-buildings"></i>Branch Details
|
||||
</span>
|
||||
</div>
|
||||
<div className="row mb-1">
|
||||
<div className="col-4 col-md-4 text-secondary">Name:</div>
|
||||
<div className="col-8 col-md-8">{data?.branchName}</div>
|
||||
</div>
|
||||
|
||||
export default BranchDetails
|
||||
<div className="row mb-1">
|
||||
<div className="col-4 col-md-4 text-secondary">Type:</div>
|
||||
<div className="col-8 col-md-8">{data?.branchType}</div>
|
||||
</div>
|
||||
<div className="row mb-1">
|
||||
<div className="col-4 col-md-4 text-secondary">Contact No:</div>
|
||||
<div className="col-8 col-md-8">{data?.contactInformation}</div>
|
||||
</div>
|
||||
|
||||
<div className="row mb-1">
|
||||
<div className="col-4 col-md-4 text-secondary">Address:</div>
|
||||
<div className="col-8 col-md-8">{data?.address}</div>
|
||||
</div>
|
||||
|
||||
{googleMapUrl && (
|
||||
<div className="row mb-1">
|
||||
<div className="col-4 col-md-4 text-secondary">Map:</div>
|
||||
|
||||
<div className="col-8 col-md-8 d-flex align-items-center gap-2">
|
||||
<a
|
||||
href={googleMapUrl}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary text-decoration-underline text-break"
|
||||
style={{ wordBreak: "break-all" }}
|
||||
>
|
||||
Open in Google Maps
|
||||
</a>
|
||||
|
||||
<i
|
||||
className={`bx ${
|
||||
copied ? "bx-check-double text-secondry " : "bx-copy"
|
||||
}`}
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={handleCopy}
|
||||
></i>
|
||||
|
||||
{copied && <span className="text-secondry small">Copied!</span>}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BranchDetails;
|
||||
|
||||
@ -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 (
|
||||
<AppFormProvider {...methods}>
|
||||
<div className="d-flex mb-2">
|
||||
<span className="fs-6 fw-medium">
|
||||
Change Status
|
||||
</span>
|
||||
</div>
|
||||
<form className="row text-start" onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="mb-2">
|
||||
<AppFormController
|
||||
@ -1,16 +1,16 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import Avatar from "../common/Avatar";
|
||||
import { useAppForm } from "../../hooks/appHooks/useAppForm";
|
||||
import Avatar from "../../common/Avatar";
|
||||
import { useAppForm } from "../../../hooks/appHooks/useAppForm";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { JobCommentSchema } from "./ServiceProjectSchema";
|
||||
import { JobCommentSchema } from "../ServiceProjectSchema";
|
||||
import {
|
||||
useAddCommentJob,
|
||||
useJobComments,
|
||||
} from "../../hooks/useServiceProject";
|
||||
import { ITEMS_PER_PAGE } from "../../utils/constants";
|
||||
import { formatUTCToLocalTime } from "../../utils/dateUtils";
|
||||
import Filelist from "../Expenses/Filelist";
|
||||
import { formatFileSize, getIconByFileType } from "../../utils/appUtils";
|
||||
} from "../../../hooks/useServiceProject";
|
||||
import { ITEMS_PER_PAGE } from "../../../utils/constants";
|
||||
import { formatUTCToLocalTime } from "../../../utils/dateUtils";
|
||||
import Filelist from "../../Expenses/Filelist";
|
||||
import { formatFileSize, getIconByFileType } from "../../../utils/appUtils";
|
||||
|
||||
const JobComments = ({ data }) => {
|
||||
const {
|
||||
@ -161,46 +161,48 @@ const JobComments = ({ data }) => {
|
||||
const user = item?.createdBy;
|
||||
|
||||
return (
|
||||
<div
|
||||
key={item.id}
|
||||
className="list-group-item border-0 border-bottom p-0"
|
||||
>
|
||||
<div className="d-flex align-items-start mt-2 mx-0 px-0">
|
||||
<Avatar
|
||||
firstName={user?.firstName}
|
||||
lastName={user?.lastName}
|
||||
/>
|
||||
<div className="">
|
||||
<div className="d-flex flex-row gap-3">
|
||||
<span className="fw-semibold">
|
||||
{user?.firstName} {user?.lastName}
|
||||
</span>
|
||||
<span className="text-secondary">
|
||||
<em>{formatUTCToLocalTime(item?.createdAt, true)}</em>
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-muted text-secondary">
|
||||
{user?.jobRoleName}
|
||||
</div>
|
||||
<div className="text-wrap">
|
||||
<p className="mb-1 mt-2 text-muted">{item.comment}</p>
|
||||
<div className="d-flex flex-wrap jusify-content-end gap-2 gap-sm-6 ">
|
||||
{item.attachments?.map((file) => (
|
||||
<div className="d-flex align-items-center">
|
||||
<i
|
||||
className={`bx bx-xxl ${getIconByFileType(
|
||||
file?.contentType
|
||||
)} fs-3`}
|
||||
></i>
|
||||
<div className="d-flex flex-column">
|
||||
<p className="m-0">{file.fileName}</p>
|
||||
<small className="text-secondary">
|
||||
{formatFileSize(file.fileSize)}
|
||||
</small>
|
||||
</div>
|
||||
<div className="d-flex align-items-start mt-2 mx-0 px-0">
|
||||
<Avatar
|
||||
size="xs"
|
||||
firstName={user?.firstName}
|
||||
lastName={user?.lastName}
|
||||
/>
|
||||
|
||||
<div className="w-100">
|
||||
<div className="d-flex flex-row align-items-center gap-3 w-100">
|
||||
<span className="fw-semibold">
|
||||
{user?.firstName} {user?.lastName}
|
||||
</span>
|
||||
|
||||
<span className="text-secondary">
|
||||
<em>{formatUTCToLocalTime(item?.createdAt, true)}</em>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="text-muted text-secondary">
|
||||
{user?.jobRoleName}
|
||||
</div>
|
||||
|
||||
<div className="text-wrap">
|
||||
<p className="mb-1 mt-2 text-muted">{item.comment}</p>
|
||||
|
||||
<div className="d-flex flex-wrap jusify-content-end gap-2 gap-sm-6">
|
||||
{item.attachments?.map((file) => (
|
||||
<div className="d-flex align-items-center">
|
||||
<i
|
||||
className={`bx bx-xxl ${getIconByFileType(
|
||||
file?.contentType
|
||||
)} fs-3`}
|
||||
></i>
|
||||
<div className="d-flex flex-column">
|
||||
<p className="m-0">{file.fileName}</p>
|
||||
<small className="text-secondary">
|
||||
{formatFileSize(file.fileSize)}
|
||||
</small>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -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 (
|
||||
@ -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();
|
||||
@ -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 <SpinnerLoader />;
|
||||
if (isLoading) return <JobDetailsSkeleton />;
|
||||
if (isError)
|
||||
return (
|
||||
<div>
|
||||
@ -46,7 +47,7 @@ const drawerRef = useRef();
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div className="row text-start">
|
||||
<div className="row text-start" ref={drawerRef}>
|
||||
<div className="col-12">
|
||||
<h6 className="fs-5 fw-semibold">{data?.title}</h6>
|
||||
<div className="d-flex justify-content-between align-items-start flex-wrap mb-2">
|
||||
@ -62,7 +63,6 @@ const drawerRef = useRef();
|
||||
{STATUS_JOB_CLOSED !== data?.status?.id && (
|
||||
<HoverPopup
|
||||
id="STATUS_CHANEG"
|
||||
title="Change Status"
|
||||
Mode="click"
|
||||
className=""
|
||||
content={
|
||||
@ -128,11 +128,19 @@ const drawerRef = useRef();
|
||||
{data?.projectBranch && (
|
||||
<div className="d-flex flex-row gap-3 my-2">
|
||||
<span className="fw-semibold">
|
||||
{" "}
|
||||
<i className="bx bx-buildings me-1"></i>Branch Name :
|
||||
<i className="bx bx-buildings me-1"></i> Branch Name :
|
||||
</span>
|
||||
<HoverPopup align="left" boundaryRef={drawerRef} id="BRANCH_DETAILS" Mode="click" content={ <BranchDetails branch={data?.projectBranch?.id}/>} >
|
||||
<span className="text">{data?.projectBranch?.branchName}</span>
|
||||
|
||||
<HoverPopup
|
||||
id="BRANCH_DETAILS"
|
||||
Mode="click"
|
||||
align="auto"
|
||||
boundaryRef={drawerRef}
|
||||
content={<BranchDetails branch={data?.projectBranch?.id} />}
|
||||
>
|
||||
<span className="text text-decoration-underline ">
|
||||
{data?.projectBranch?.branchName}
|
||||
</span>
|
||||
</HoverPopup>
|
||||
</div>
|
||||
)}
|
||||
@ -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 (
|
||||
<div>
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="d-flex">
|
||||
<Avatar firstName={"A"} lastName={"D"} />
|
||||
|
||||
<div className="flex-grow-1">
|
||||
<textarea
|
||||
className="form-control"
|
||||
rows={3}
|
||||
placeholder="Write your comment..."
|
||||
{...register("comment")}
|
||||
></textarea>
|
||||
|
||||
{errors?.comment && (
|
||||
<small className="danger-text">{errors?.comment?.message}</small>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{/* <div className="flex-grow-1 ms-10 mt-2">
|
||||
{files?.length > 0 && (
|
||||
<Filelist files={} removeFile={removeFile} />
|
||||
)}
|
||||
</div> */}
|
||||
<div className="d-flex justify-content-end gap-2 align-items-center text-end mt-3 ms-10 ms-md-0">
|
||||
<div
|
||||
onClick={() => document.getElementById("attachments").click()}
|
||||
className="cursor-pointer"
|
||||
style={{ whiteSpace: "nowrap" }}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
accept=".pdf,.jpg,.jpeg,.png"
|
||||
id="attachments"
|
||||
multiple
|
||||
className="d-none"
|
||||
{...register("attachments")}
|
||||
onChange={(e) => {
|
||||
onFileChange(e);
|
||||
e.target.value = "";
|
||||
}}
|
||||
/>
|
||||
<i className="bx bx-sm bx-paperclip mb-1 me-1"></i>
|
||||
Add Attachment
|
||||
</div>
|
||||
|
||||
<button
|
||||
className="btn btn-primary btn-sm px-1 py-1"
|
||||
type="submit"
|
||||
disabled={!watch("comment")?.trim() || isPending}
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateJobComment;
|
||||
138
src/components/ServiceProject/ServiceProjectSeketon.jsx
Normal file
138
src/components/ServiceProject/ServiceProjectSeketon.jsx
Normal file
@ -0,0 +1,138 @@
|
||||
import React from "react";
|
||||
|
||||
const SkeletonLine = ({ height = 18, width = "100%", className = "" }) => (
|
||||
<div
|
||||
className={`skeleton ${className}`}
|
||||
style={{
|
||||
height,
|
||||
width,
|
||||
borderRadius: "4px",
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
|
||||
export const BranchDetailsSkeleton = () => {
|
||||
return (
|
||||
<div className="w-100">
|
||||
<div className="d-flex mb-3">
|
||||
<SkeletonLine height={22} width="280px" />
|
||||
</div>
|
||||
|
||||
<div className="row mb-2">
|
||||
<div className="col-4">
|
||||
<SkeletonLine height={16} width="70%" />
|
||||
</div>
|
||||
<div className="col-8">
|
||||
<SkeletonLine height={16} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row mb-2">
|
||||
<div className="col-4">
|
||||
<SkeletonLine height={16} width="70%" />
|
||||
</div>
|
||||
<div className="col-8">
|
||||
<SkeletonLine height={16} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row mb-2">
|
||||
<div className="col-4">
|
||||
<SkeletonLine height={16} width="70%" />
|
||||
</div>
|
||||
<div className="col-8">
|
||||
<SkeletonLine height={16} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row mb-2">
|
||||
<div className="col-4">
|
||||
<SkeletonLine height={16} width="70%" />
|
||||
</div>
|
||||
<div className="col-8">
|
||||
<SkeletonLine height={16} width="90%" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row mb-2">
|
||||
<div className="col-4">
|
||||
<SkeletonLine height={16} width="70%" />
|
||||
</div>
|
||||
<div className="col-8 d-flex gap-2 align-items-center">
|
||||
<SkeletonLine height={16} width="60%" />
|
||||
<SkeletonLine height={16} width="20px" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const JobDetailsSkeleton = () => {
|
||||
return (
|
||||
<div className="row text-start">
|
||||
<div className="col-12">
|
||||
{/* Title */}
|
||||
<SkeletonLine height={24} width="50%" />
|
||||
|
||||
{/* Job ID + Status */}
|
||||
<div className="d-flex justify-content-between align-items-start flex-wrap mb-3 mt-2">
|
||||
<SkeletonLine height={18} width="30%" />
|
||||
<div className="d-flex flex-row gap-2">
|
||||
<SkeletonLine height={22} width="70px" />
|
||||
<SkeletonLine height={22} width="22px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Description */}
|
||||
<SkeletonLine height={40} width="100%" />
|
||||
|
||||
{/* Created Date */}
|
||||
<div className="d-flex my-3">
|
||||
<SkeletonLine height={16} width="40%" />
|
||||
</div>
|
||||
|
||||
{/* Start / Due Date */}
|
||||
<div className="d-flex justify-content-between mb-4">
|
||||
<SkeletonLine height={16} width="50%" />
|
||||
<SkeletonLine height={22} width="70px" />
|
||||
</div>
|
||||
|
||||
{/* Branch Name */}
|
||||
<div className="d-flex flex-row gap-3 my-2">
|
||||
<SkeletonLine height={16} width="30%" />
|
||||
<SkeletonLine height={16} width="40%" />
|
||||
</div>
|
||||
|
||||
{/* Created By */}
|
||||
<div className="row align-items-center my-3">
|
||||
<div className="col-12 col-md-auto mb-2">
|
||||
<SkeletonLine height={16} width="80px" />
|
||||
</div>
|
||||
|
||||
<div className="col d-flex align-items-center gap-2">
|
||||
<SkeletonLine height={30} width="30px" /> {/* Avatar */}
|
||||
<SkeletonLine height={16} width="40%" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Assigned To */}
|
||||
<div className="row mt-2">
|
||||
<div className="col-12 col-md-auto mb-2">
|
||||
<SkeletonLine height={16} width="90px" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Tabs */}
|
||||
<div className="mt-4">
|
||||
<div className="d-flex gap-3 mb-3">
|
||||
<SkeletonLine height={35} width="80px" />
|
||||
<SkeletonLine height={35} width="80px" />
|
||||
<SkeletonLine height={35} width="80px" />
|
||||
</div>
|
||||
|
||||
<SkeletonLine height={150} width="100%" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -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(
|
||||
[
|
||||
{
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user