Changes In Popup of Document.

This commit is contained in:
Kartik Sharma 2025-09-09 12:38:11 +05:30
parent 1b98c60120
commit 8d44606b0b
2 changed files with 270 additions and 155 deletions

View File

@ -13,6 +13,9 @@ const DocumentVersionList = ({
isPending, isPending,
setOpenDocument, setOpenDocument,
VerifyDocument, VerifyDocument,
RejectDocument,
showVersions,
latestDoc,
}) => { }) => {
const canVerifyDocument = useHasUserPermission(VERIFY_DOCUMENT); const canVerifyDocument = useHasUserPermission(VERIFY_DOCUMENT);
const canDownloadDocument = useHasUserPermission(DOWNLOAD_DOCUMENT); const canDownloadDocument = useHasUserPermission(DOWNLOAD_DOCUMENT);
@ -23,146 +26,267 @@ const DocumentVersionList = ({
} }
}; };
const sortedVersions = versionList?.data
? [...versionList.data].sort((a, b) => b.version - a.version)
: [];
if (versionLoding) { if (versionLoding) {
return <VersionListSkeleton items={2} />; return <VersionListSkeleton items={2} />;
} }
const sortedVersions = versionList?.data
? [...versionList.data].sort((a, b) => b.version - a.version)
: [];
const currentDoc = sortedVersions.length ? sortedVersions[0] : latestDoc;
if (!showVersions) {
if (!currentDoc) {
return <p className="text-muted">No documents available.</p>;
}
return (
<>
<div className="list-group list-group-flush" style={{ marginTop: "-4px", marginLeft: "10px" }}>
<div className="list-group-item list-group-item-action cursor-pointer" style={{ marginLeft: "-30px" }}>
<div className="d-flex justify-content-between">
{/* Left Side: Document Details */}
<div className="d-flex align-items-start" onClick={handleOpenDocument}>
<FileIcon
type={currentDoc.contentType}
size="fs-2"
className="me-2"
/>
<div>
<div className="d-flex align-items-center mb-1">
<span className="fw-semibold" style={{ marginTop: "-6px" }}>
{currentDoc.name}
</span>
</div>
<div className="d-flex align-items-center mb-1">
{getDocuementsStatus(currentDoc.isVerified)}
<span className="text-secondary ms-7 fw-semibold">
File Size: {currentDoc.fileSize} Kb
</span>
</div>
<div className="d-flex align-items-center">
<small className="text-secondary fw-semibold me-2">
Uploaded by
</small>
<Avatar
size="xs"
classAvatar="m-0"
firstName={currentDoc.uploadedBy?.firstName}
lastName={currentDoc.uploadedBy?.lastName}
/>
<span className="ms-1">
<small className="fw-normal" style={{ marginLeft: "-10px" }}>
{`${currentDoc.uploadedBy?.firstName ?? ""} ${currentDoc.uploadedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
</div>
<small className="ms-2" style={{ marginRight: "-113px" }}>
{formatUTCToLocalTime(currentDoc?.uploadedAt)}
</small>
</div>
</div>
<div className="d-flex flex-column align-items-end" style={{ marginTop: "-8px", marginRight: "-540px" }}>
<span className="badge bg-success-subtle text-success">
latest
</span>
</div>
{/* Right Side: Status and Info */}
<div className="d-flex flex-column align-items-end" style={{ marginTop: "31px", marginRight: "21px" }}>
{/* <span className="badge bg-success-subtle text-success">
latest
</span> */}
<div className="d-flex align-items-center mt-1">
{currentDoc?.updatedBy && (
<>
<small className="text-secondary me-2 fw-semibold">Updated by</small>
<Avatar
size="xs"
classAvatar="m-0"
firstName={currentDoc.updatedBy?.firstName}
lastName={currentDoc.updatedBy?.lastName}
/>
<span className="ms-1" style={{ marginRight: "-37px" }}>
<small className="fw-normal" style={{ marginLeft: "-10px" }}>
{`${currentDoc.updatedBy?.firstName ?? ""} ${currentDoc.updatedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
</>
)}
</div>
{/* Conditionally render updated date */}
{currentDoc?.updatedAt && (
<small className="ms-2" style={{ marginRight: "-75px" }}>
{formatUTCToLocalTime(currentDoc?.updatedAt)}
</small>
)}
</div>
</div>
</div>
</div>
{/* Buttons Div - only for the latest pending document when showVersions is false */}
{currentDoc.isVerified === null && canVerifyDocument && (
<div className="d-flex justify-content-end mb-3 me-4">
{isPending ? (
<span className="text-muted">Please Wait...</span>
) : (
<>
<button
type="button"
onClick={RejectDocument}
className="btn btn-sm btn-danger me-2"
>
Reject
</button>
<button
type="button"
onClick={VerifyDocument}
className="btn btn-sm btn-primary"
>
Verify
</button>
</>
)}
</div>
)}
</>
);
}
// If showVersions is true, display all versions
if (!sortedVersions.length) { if (!sortedVersions.length) {
return <p className="text-muted">No documents available.</p>; return <p className="text-muted">No documents available.</p>;
} }
return ( return (
<> <div className="accordion" id="docAccordion">
<div className="d-flex justify-content-between align-items-center mb-3"> <div className="accordion-item shadow-none">
<h5 className="mb-0">Documents</h5> <div className="accordion-body p-2" style={{ marginTop: "-15px" }}>
<div className="form-check form-switch"> <div className="list-group list-group-flush">
<input {sortedVersions.map((document, index) => (
className="form-check-input" <div
type="checkbox" key={document.id}
id="showVersionsSwitch" className="list-group-item list-group-item-action cursor-pointer" style={{ marginLeft: "-30px",marginTop:"5px" }}
/> >
<label className="form-check-label" htmlFor="showVersionsSwitch"> <div className="d-flex justify-content-between">
Show Versions {/* Left Side: Document Details */}
</label> <div className="d-flex align-items-start" onClick={handleOpenDocument}>
</div> <FileIcon
</div> type={document.contentType}
<div className="accordion" id="docAccordion"> size="fs-2"
<div className="accordion-item shadow-none"> className="me-2"
<div className="accordion-body p-2"> />
<div className="list-group list-group-flush"> <div>
{sortedVersions.map((document, index) => ( <div className="d-flex align-items-center mb-1">
<div <span className="fw-semibold" style={{ marginTop: "-6px" }}>
key={document.id} {document.name}
className="list-group-item list-group-item-action" style={{ marginLeft: "-30px" }} </span>
> </div>
<div className="d-flex justify-content-between"> <div className="d-flex align-items-center mb-1">
{/* Left Side: Document Details */} {getDocuementsStatus(document.isVerified)}
<div className="d-flex align-items-start"> <span className="text-secondary ms-7 fw-semibold">
<FileIcon File Size: {document.fileSize} Kb
type={document.contentType} </span>
size="fs-2" </div>
className="me-2" <div className="d-flex align-items-center">
/> <small className="text-secondary fw-semibold me-2">
<div> Uploaded by
<div className="d-flex align-items-center mb-1"> </small>
<span className="fw-normal"> <Avatar
{document.name} size="xs"
</span> classAvatar="m-0"
</div> firstName={document.uploadedBy?.firstName}
<div className="d-flex align-items-center mb-1"> lastName={document.uploadedBy?.lastName}
{getDocuementsStatus(document.isVerified)} />
<span className="text-secondary ms-7"> <span className="ms-1">
File Size: {document.fileSize} Kb <small className="fw-normal" style={{ marginLeft: "-10px" }}>
</span> {`${document.uploadedBy?.firstName ?? ""} ${document.uploadedBy?.lastName ?? ""}`.trim() || "N/A"}
</div> </small>
<div className="d-flex align-items-center"> </span>
<small className="text-secondary me-2"> </div>
Uploaded by <small className="ms-2" style={{ marginRight: "-113px" }}>
{formatUTCToLocalTime(document?.uploadedAt)}
</small>
{document?.verifiedAt && (
<div className="d-flex align-items-center mt-1">
<small className="text-secondary me-2 fw-semibold">
{document.isVerified ? "Approved by" : "Rejected by"}
</small> </small>
<Avatar <Avatar
size="xs" size="xs"
classAvatar="m-0" classAvatar="m-0"
firstName={document.uploadedBy?.firstName} firstName={document.verifiedBy?.firstName}
lastName={document.uploadedBy?.lastName} lastName={document.verifiedBy?.lastName}
/> />
<span className="ms-1"> <span className="ms-1">
<small className="fw-normal"> <small className="fw-normal" style={{ marginLeft: "-10px" }}>
{`${document.uploadedBy?.firstName ?? ""} ${document.uploadedBy?.lastName ?? ""}`.trim() || "N/A"} {`${document.verifiedBy?.firstName ?? ""} ${document.verifiedBy?.lastName ?? ""}`.trim() || "N/A"}
</small> </small>
</span> </span>
<small className="ms-2">
{formatUTCToLocalTime(document?.uploadedAt)}
</small>
</div> </div>
{document?.verifiedAt && (
<div className="d-flex align-items-center mt-1">
<small className="text-secondary me-2">
{document.isVerified ? "Approved by" : "Rejected by"}
</small>
<Avatar
size="xs"
classAvatar="m-0"
firstName={document.verifiedBy?.firstName}
lastName={document.verifiedBy?.lastName}
/>
<span className="ms-1">
<small className="fw-normal">
{`${document.verifiedBy?.firstName ?? ""} ${document.verifiedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
<small className="ms-2">
{formatUTCToLocalTime(document?.verifiedAt)}
</small>
</div>
)}
</div>
</div>
{/* Right Side: Status and Actions */}
<div className="d-flex flex-column align-items-end" style={{ marginTop: "42px", marginRight: "-52px" }}>
{document.isLatest && (
<span className="badge bg-success-subtle text-success">
latest
</span>
)} )}
{/* Conditionally render verified date */}
<div className="d-flex align-items-center mt-1"> {document?.verifiedAt && (
{document?.updatedBy && ( <small className="ms-2" style={{ marginRight: "-103px" }}>
<> {formatUTCToLocalTime(document?.verifiedAt)}
<small className="text-secondary me-2">Updated by</small> </small>
<Avatar )}
size="xs"
classAvatar="m-0"
firstName={document.updatedBy?.firstName}
lastName={document.updatedBy?.lastName}
/>
<span className="ms-1">
<small className="fw-normal">
{`${document.updatedBy?.firstName ?? ""} ${document.updatedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
<small className="ms-2">
{formatUTCToLocalTime(document?.updatedAt)}
</small>
</>
)}
</div>
<small className="text-secondary mt-1">
version {document.version}
</small>
</div> </div>
</div> </div>
<div className="d-flex flex-column align-items-end" style={{ marginTop: "-13px", marginRight: "46px" }}>
<small className="badge rounded-pill bg-label-secondary mt-1" style={{ marginRight: "-336px" }}>
version {document.version}
</small>
{document.isLatest && (
<span className="badge bg-success-subtle text-success">
latest
</span>
)}
</div>
{/* Right Side: Status and Actions */}
<div className="d-flex flex-column align-items-end" style={{ marginTop: "16px", marginRight: "46px" }}>
{/* <small className="badge rounded-pill bg-label-secondary mt-1" style={{ marginRight: "-105px" }}>
version {document.version}
</small> */}
{document.isLatest && (
<span className="badge bg-success-subtle text-success">
latest
</span>
)}
<div className="d-flex align-items-center mt-1">
{document?.updatedBy && (
<>
<small className="text-secondary me-2 fw-semibold">Updated by</small>
<Avatar
size="xs"
classAvatar="m-0"
firstName={document.updatedBy?.firstName}
lastName={document.updatedBy?.lastName}
/>
<span className="ms-1" style={{ marginRight: "-37px" }}>
<small className="fw-normal" style={{ marginLeft: "-10px" }}>
{`${document.updatedBy?.firstName ?? ""} ${document.updatedBy?.lastName ?? ""}`.trim() || "N/A"}
</small>
</span>
</>
)}
</div>
{/* Conditionally render updated date */}
{document?.updatedAt && (
<small className="ms-2" style={{ marginRight: "-75px" }}>
{formatUTCToLocalTime(document?.updatedAt)}
</small>
)}
</div>
</div> </div>
))} </div>
</div> ))}
</div> </div>
</div> </div>
</div> </div>
</> </div>
); );
}; };

View File

@ -1,3 +1,4 @@
// ViewDocument.jsx
import React, { useState } from "react"; import React, { useState } from "react";
import { import {
useDocumentDetails, useDocumentDetails,
@ -12,9 +13,6 @@ import {
ITEMS_PER_PAGE, ITEMS_PER_PAGE,
VERIFY_DOCUMENT, VERIFY_DOCUMENT,
} from "../../utils/constants"; } from "../../utils/constants";
import Pagination from "../common/Pagination";
import VersionListSkeleton from "./VersionListSkeleton";
// import DocumentDetailsSkeleton from "./DocumentDetailsSkeleton";
import DocumentDetailsSkeleton from "./DocumentDetailsSkeleton "; import DocumentDetailsSkeleton from "./DocumentDetailsSkeleton ";
import { useHasUserPermission } from "../../hooks/useHasUserPermission"; import { useHasUserPermission } from "../../hooks/useHasUserPermission";
import DocumentVersionList from "./DocumentVersionList"; import DocumentVersionList from "./DocumentVersionList";
@ -22,15 +20,20 @@ import DocumentVersionList from "./DocumentVersionList";
const ViewDocument = () => { const ViewDocument = () => {
const { viewDoc, setOpenDocument } = useDocumentContext(); const { viewDoc, setOpenDocument } = useDocumentContext();
const [currentPage, setCurrentPage] = useState(1); const [currentPage, setCurrentPage] = useState(1);
const [showVersions, setShowVersions] = useState(false);
const canVerifyDocument = useHasUserPermission(VERIFY_DOCUMENT); const canVerifyDocument = useHasUserPermission(VERIFY_DOCUMENT);
// Document Details
const { data, isLoading, isError, error } = useDocumentDetails( const { data, isLoading, isError, error } = useDocumentDetails(
viewDoc?.document viewDoc?.document
); );
// Document Versions (fetch only if toggle is ON)
const { const {
data: versionList, data: versionList,
isLoading: versionLoding, isLoading: versionLoading,
} = useDocumentVersionList( } = useDocumentVersionList(
data?.parentAttachmentId, showVersions ? data?.parentAttachmentId : null,
ITEMS_PER_PAGE - 10, ITEMS_PER_PAGE - 10,
currentPage currentPage
); );
@ -41,6 +44,7 @@ const ViewDocument = () => {
} }
}; };
// Verify / Reject
const { mutate: VerifyDoc, isPending } = useVerifyDocument(); const { mutate: VerifyDoc, isPending } = useVerifyDocument();
const VerifyDocument = () => { const VerifyDocument = () => {
VerifyDoc({ documentId: viewDoc?.document, isVerify: true }); VerifyDoc({ documentId: viewDoc?.document, isVerify: true });
@ -57,11 +61,12 @@ const ViewDocument = () => {
<p className="danger-text">{error?.response?.status}</p> <p className="danger-text">{error?.response?.status}</p>
</div> </div>
); );
console.log("kartik", data)
return ( return (
<div className="p-3"> <div className="p-3">
<p className="fw-bold fs-5 mb-3 border-bottom pb-2">Document Details</p> <p className="fw-bold fs-5 mb-3 border-bottom pb-2">Document Details</p>
{/* Document Info Rows */}
<div className="row mb-2 text-start"> <div className="row mb-2 text-start">
<div className="col-12 col-md-6 d-flex"> <div className="col-12 col-md-6 d-flex">
<span className="fw-semibold me-2" style={{ minWidth: "140px" }}> <span className="fw-semibold me-2" style={{ minWidth: "140px" }}>
@ -103,14 +108,7 @@ const ViewDocument = () => {
{formatUTCToLocalTime(data.uploadedAt)} {formatUTCToLocalTime(data.uploadedAt)}
</span> </span>
</div> </div>
<div className="col-12 col-md-6 d-flex">
<span className="fw-semibold me-2" style={{ minWidth: "140px" }}>
Updated At:
</span>
<span className="text-muted">
{formatUTCToLocalTime(data.updatedAt) || "-"}
</span>
</div>
</div> </div>
<div className="row mb-2 text-start"> <div className="row mb-2 text-start">
@ -144,39 +142,32 @@ const ViewDocument = () => {
</div> </div>
</div> </div>
{/* Verify / Reject */} {/* Toggle for Versions */}
{data.isVerified === null && canVerifyDocument && ( <div className="d-flex justify-content-between align-items-center mb-3">
<div className="d-flex justify-content-end mb-3"> <p className="m-0 fw-semibold fs-6">Documents:</p>
{isPending ? ( <div className="form-check form-switch">
<span className="text-muted">Please Wait...</span> <label className="form-check-label" htmlFor="showVersionsSwitch">
) : ( Show Versions
<> </label>
<button <input
type="button" className="form-check-input"
onClick={RejectDocument} type="checkbox"
className="btn btn-sm btn-danger me-2" id="showVersionsSwitch"
> checked={showVersions}
Reject onChange={(e) => setShowVersions(e.target.checked)}
</button> />
<button
type="button"
onClick={VerifyDocument}
className="btn btn-sm btn-primary"
>
Verify
</button>
</>
)}
</div> </div>
)} </div>
<DocumentVersionList <DocumentVersionList
versionLoding={versionLoding} versionLoding={versionLoading}
versionList={versionList} versionList={versionList}
isPending={isPending} isPending={isPending}
setOpenDocument={setOpenDocument} setOpenDocument={setOpenDocument}
VerifyDocument={VerifyDocument} VerifyDocument={VerifyDocument}
RejectDocument={RejectDocument}
showVersions={showVersions}
latestDoc={data}
/> />
</div> </div>
); );