add SignDocument microfrontend

This commit is contained in:
prafullnavkar-nxg
2023-10-27 21:21:46 +05:30
parent 71001efb93
commit 9b6b5dbe71
69 changed files with 35235 additions and 17 deletions
@@ -0,0 +1,608 @@
import React, { useState, useEffect, useRef } from "react";
import folder from "../../../assests/folder.png";
import "../LegaDrive.css";
import draftDoc from "../../../assests/draftDoc1.png";
import pdfLogo from "../../../assests/pdf3.png";
import axios from "axios";
import * as ContextMenu from "@radix-ui/react-context-menu";
import { saveAs } from "file-saver";
import { getHostUrl } from "../../../utils/Utils";
import { useNavigate } from "react-router-dom";
import Table from "react-bootstrap/Table";
import * as HoverCard from "@radix-ui/react-hover-card";
function PdfFileComponent({
pdfData,
setFolderName,
setDocId,
setIsLoading,
setPdfData,
isList,
}) {
const [rename, setRename] = useState("");
const [renameValue, setRenameValue] = useState("");
const inputRef = useRef(null);
const navigate = useNavigate();
//to focus input box on press rename to change doc name
useEffect(() => {
if (rename && inputRef.current) {
// console.log("ref", inputRef.current)
setTimeout(() => {
inputRef.current.focus();
}, 10);
}
}, [rename]);
//function to handle folder component
const handleOnclikFolder = (data) => {
const folderData = {
name: data.Name,
objectId: data.objectId,
};
setFolderName((prev) => [...prev, folderData]);
const loadObj = {
isLoad: true,
message: "This might take some time",
};
setIsLoading(loadObj);
setDocId(data.objectId);
};
//function for change doc name and update doc name in _document class
const handledRenameDoc = async (data) => {
setRename("");
const trimmedValue = renameValue.trim();
if (trimmedValue.length > 0) {
const updateName = {
Name: renameValue,
};
const docId = data.objectId;
const docData = pdfData;
const updatedData = docData.map((item) => {
if (item.objectId === docId) {
// If the item's ID matches the target ID, update the name
return { ...item, Name: renameValue };
}
// If the item's ID doesn't match, keep it unchanged
return item;
});
setPdfData(updatedData);
await axios
.put(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document/${docId}`,
updateName,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken"),
},
}
)
.then((result) => {
// const res = result.data;
// console.log("res", res);
})
.catch((err) => {
console.log("error updating field is decline ", err);
});
}
};
//function for navigate user to microapp-signature component
const checkPdfStatus = async (data) => {
// console.log("document", data);
const hostUrl = getHostUrl();
const expireDate = data.ExpiryDate.iso;
const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime();
const signerExist = data.Signers && data.Signers;
const signUrl = data.SignedUrl && data.SignedUrl;
const isDecline = data.IsDeclined && data.IsDeclined;
const isPlaceholder = data.Placeholders && data.Placeholders;
//checking and navigate to signyouself page
const checkPlaceHolder = data.Placeholders;
//checking if document has completed
if (data.IsCompleted && signerExist) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
} else if (data.IsCompleted && !signerExist) {
navigate(
`${hostUrl}recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`
);
// window.location.hash = `/recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`;
}
//checking if document has declined by someone
else if (isDecline) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
} else if (currDate > expireUpdateDate && signerExist && !isPlaceholder) {
// window.location.hash = `/placeHolderSign/${data.objectId}`;
navigate(`${hostUrl}placeHolderSign/${data.objectId}`);
} else if (
currDate > expireUpdateDate &&
!signerExist &&
!isPlaceholder &&
!signUrl
) {
navigate(`${hostUrl}signaturePdf/${data.objectId}`);
// window.location.hash = `/signaturePdf/${data.objectId}`;
}
//checking if document has expired
else if (currDate > expireUpdateDate) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
} //checking if document is draft signers type and signers placeholder does not placed yet
else if (!signUrl && signerExist) {
// window.location.hash = `/placeHolderSign/${data.objectId}`;
navigate(`${hostUrl}placeHolderSign/${data.objectId}`);
}
//checking if document is request type and signers placeholder exist and does not completed yet
//then user can check progress of document and sign also
else if (
checkPlaceHolder &&
checkPlaceHolder.length > 0 &&
!data.IsCompleted
) {
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
}
//checking document is draft and signyourself type then user can sign document
else {
navigate(`${hostUrl}signaturePdf/${data.objectId}`);
// navigate(`/signaturePdf/${data.objectId}`);
// window.location.hash = `/signaturePdf/${data.objectId}`;
}
};
//component to handle type of document and render according to type
const handleFolderData = (data, ind, listType) => {
// console.log("data", data);
let createddate,
status,
isDecline,
signerExist,
isExpire,
isComplete,
signUrl,
isPlaceholder;
if (data.Type !== "Folder") {
const expireDate = data.ExpiryDate && data.ExpiryDate.iso;
const createdDate = data.createdAt && data.createdAt;
createddate = new Date(createdDate).toLocaleDateString();
isComplete = data.IsCompleted && data.IsCompleted ? true : false;
isDecline = data.IsDeclined && data.IsDeclined;
isPlaceholder = data.Placeholders && data.Placeholders;
signerExist = data.Signers && data.Signers;
signUrl = data.SignedUrl && data.SignedUrl;
const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime();
if (currDate > expireUpdateDate) {
isExpire = true;
} else {
isExpire = false;
}
if (isComplete) {
status = "Completed";
} else if (isDecline) {
status = "Declined";
} else if (isExpire && !isPlaceholder && signerExist) {
// status = "Expired";
status = "Draft";
} else if (isExpire && !isPlaceholder && !signerExist && !signUrl) {
// status = "Expired";
status = "Draft";
} else if (isExpire) {
status = "Expired";
} else if (!signUrl) {
status = "Draft";
} else {
status = "InComplete";
}
}
const handleDraftDoc = (data) => {
window.location.hash = `/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9MZWdhR2VuaWUtTWljcm9hcHBWMi9yZW1vdGVFbnRyeS5qcw==&moduleToLoad=AppRoutes&remoteName=legageniemicroapp/legagenie?${data.objectId}`;
};
const handleMenuItemClick = (selectType, data) => {
// console.log("data",data)
if (selectType === "Download") {
// console.log("download")
const pdfName = data && data.Name;
const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL;
saveAs(pdfUrl, `${pdfName}_signed_by_opensign.qik.ai.pdf`);
} else if (selectType === "Rename") {
// console.log("rename")
setRenameValue(data.Name);
setRename(data.objectId);
}
};
const handleEnterPress = (e, data) => {
if (e.key === "Enter") {
handledRenameDoc(data);
}
};
return listType === "table" ? (
data.Type === "Folder" ? (
<tr onClick={() => handleOnclikFolder(data)}>
<td>
<i
className="fa fa-folder"
aria-hidden="true"
style={{ color: "#f0ad26", marginRight: "8px", fontSize: "26px" }}
></i>
<span style={{ fontSize: "12px", fontWeight: "500" }}>
{data.Name}
</span>
</td>
<td>_</td>
<td>Folder</td>
<td>_</td>
<td>_</td>
</tr>
) : data.Type === "AIDoc" ? (
<tr onClick={() => handleDraftDoc(data)}>
<td>
<i
className="fa fa-file-text"
style={{ color: "#0ea3ed", marginRight: "8px", fontSize: "26px" }}
></i>
<span style={{ fontSize: "12px", fontWeight: "500" }}>
{data.Name}
</span>
</td>
<td>{createddate}</td>
<td>LegaGenie Draft</td>
<td>_</td>
<td>_</td>
</tr>
) : (
<tr onClick={() => checkPdfStatus(data)}>
<td>
<i
className="fa fa-file-pdf"
style={{ color: "#ed4d0e", marginRight: "8px", fontSize: "26px" }}
></i>
<span style={{ fontSize: "12px", fontWeight: "500" }}>
{data.Name}
</span>
</td>
<td>{createddate}</td>
<td>Pdf</td>
<td>{status}</td>
<td>
<i
onClick={(e) => {
e.stopPropagation();
handleMenuItemClick("Download", data);
}}
className="fa fa-download"
aria-hidden="true"
style={{ color: "#ed280e", marginRight: "8px" }}
></i>
</td>
</tr>
)
) : listType === "list" && data.Type === "Folder" ? (
<div key={ind} className="folderBox">
<ContextMenu.Root>
<ContextMenu.Trigger className="ContextMenuTrigger">
<div
style={{
display: "flex",
flexDirection: "column",
cursor: "pointer",
}}
>
<img
alt="no img"
onClick={() => handleOnclikFolder(data)}
src={folder}
width={100}
height={103}
/>
{rename === data.objectId ? (
<input
onFocus={() => {
inputRef.current.setSelectionRange(0, 0);
const input = inputRef.current;
if (input) {
input.select();
}
}}
autoFocus={true}
type="text"
// onFocus={()=>console.log("focus")}
onBlur={() => handledRenameDoc(data)}
onKeyDown={(e) => handleEnterPress(e, data)}
ref={inputRef}
defaultValue={renameValue}
// value={renameValue}
onChange={(e) => setRenameValue(e.target.value)}
style={{
width: "100px",
border: "1.5px solid black",
borderRadius: "2px",
fontSize: "10px",
}}
/>
) : (
<span className="foldName">{data.Name}</span>
)}
</div>
</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content
className="ContextMenuContent"
sideOffset={5}
align="end"
>
{/* <ContextMenu.Item
onClick={() => handleMenuItemClick("Download", data)}
onSelect={(e) => console.log("event", e)}
className="ContextMenuItem"
>
Download
</ContextMenu.Item> */}
<ContextMenu.Item
onClick={() => handleMenuItemClick("Rename", data)}
className="ContextMenuItem"
>
Rename
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
</div>
) : data.Type === "AIDoc" ? (
<div key={ind} className="folderBox">
<ContextMenu.Root>
<ContextMenu.Trigger className="ContextMenuTrigger">
<div
style={{
display: "flex",
flexDirection: "column",
cursor: "pointer",
}}
>
<img
alt="no img"
onClick={() => handleDraftDoc(data)}
src={draftDoc}
width={100}
height={103}
/>
{rename === data.objectId ? (
<input
onFocus={() => {
inputRef.current.setSelectionRange(0, 0);
const input = inputRef.current;
if (input) {
input.select();
}
}}
autoFocus={true}
type="text"
// onFocus={()=>console.log("focus")}
onBlur={() => handledRenameDoc(data)}
onKeyDown={(e) => handleEnterPress(e, data)}
ref={inputRef}
defaultValue={renameValue}
// value={renameValue}
onChange={(e) => setRenameValue(e.target.value)}
style={{
width: "100px",
border: "1.5px solid black",
borderRadius: "2px",
fontSize: "10px",
}}
/>
) : (
<span className="foldName">{data.Name}</span>
)}
</div>
</ContextMenu.Trigger>
<ContextMenu.Portal>
<ContextMenu.Content
className="ContextMenuContent"
sideOffset={5}
align="end"
>
{/* <ContextMenu.Item
onClick={() => handleMenuItemClick("Download", data)}
onSelect={(e) => console.log("event", e)}
className="ContextMenuItem"
>
Download
</ContextMenu.Item> */}
<ContextMenu.Item
onClick={() => handleMenuItemClick("Rename", data)}
className="ContextMenuItem"
>
Rename
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
</div>
) : (
<HoverCard.Root>
<HoverCard.Trigger asChild>
<div>
<ContextMenu.Root>
<div className="icon-container">
<ContextMenu.Trigger className="ContextMenuTrigger">
<img
alt="PDF"
className="pdf-icon"
src={pdfLogo}
onClick={() => checkPdfStatus(data)}
/>
{rename === data.objectId ? (
<input
autoFocus={true}
type="text"
onFocus={() => {
inputRef.current.setSelectionRange(0, 0);
const input = inputRef.current;
if (input) {
input.select();
}
}}
onBlur={() => handledRenameDoc(data)}
onKeyDown={(e) => handleEnterPress(e, data)}
ref={inputRef}
defaultValue={renameValue}
// value={renameValue}
onChange={(e) => setRenameValue(e.target.value)}
style={{
width: "100px",
border: "1.5px solid black",
borderRadius: "2px",
fontSize: "10px",
}}
/>
) : (
<span className="fileName">{data.Name}</span>
)}
</ContextMenu.Trigger>
{status === "Completed" ? (
<div className="status-badge completed">
<i className="fas fa-check-circle"></i>
</div>
) : status === "Declined" ? (
<div className="status-badge declined">
<i className="fa fa-thumbs-down"></i>
</div>
) : status === "Expired" ? (
<div className="status-badge expired">
<i className="fa fa-hourglass-end"></i>
</div>
) : status === "Draft" ? (
<div className="status-badge draft">
<i className="fa fa-file"></i>
</div>
) : (
status === "InComplete" && (
<div className="status-badge in-progress">
<i className="fa fa-paper-plane"></i>
</div>
)
)}
</div>
<ContextMenu.Portal>
<ContextMenu.Content
className="ContextMenuContent"
sideOffset={5}
align="end"
>
<ContextMenu.Item
onClick={() => handleMenuItemClick("Download", data)}
onSelect={(e) => console.log("event", e)}
className="ContextMenuItem"
>
Download
</ContextMenu.Item>
<ContextMenu.Item
onClick={() => handleMenuItemClick("Rename", data)}
className="ContextMenuItem"
>
Rename
</ContextMenu.Item>
</ContextMenu.Content>
</ContextMenu.Portal>
</ContextMenu.Root>
</div>
</HoverCard.Trigger>
<HoverCard.Portal>
<HoverCard.Content className="HoverCardContent" sideOffset={5}>
<strong style={{ fontSize: "13px" }}>Title: </strong>
<span className="statusSpan" style={{ marginBottom: "0px" }}>
{" "}
{data.Name}
</span>
<br />
<strong style={{ fontSize: "13px" }}>Status: </strong>
<span className="statusSpan"> {status}</span>
<br />
<strong style={{ fontSize: "13px" }}>Created Date: </strong>
<span className="statusSpan">{createddate}</span>
<br />
{signerExist && (
<>
<strong style={{ fontSize: "13px" }}>Signers: </strong>
{signerExist.map((data, key) => {
return (
<React.Fragment key={key}>
<span className="statusSpan">{data.Name}, </span>
</React.Fragment>
);
})}
</>
)}
<HoverCard.Arrow className="HoverCardArrow" />
</HoverCard.Content>
</HoverCard.Portal>
</HoverCard.Root>
);
};
//component to handle type of document and render according to type
return isList ? (
<div className="container" style={{overflowX:"auto"}}>
<Table striped bordered hover >
<thead>
<tr>
<th>Name</th>
<th>Created Date</th>
<th>Type</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{pdfData.map((data, ind) => {
return (
<React.Fragment key={ind}>
{handleFolderData(data, ind, "table")}
</React.Fragment>
);
})}
</tbody>
</Table>
</div>
) : (
<div className="pdfContainer">
{pdfData.map((data, ind) => {
return (
<div className="box" key={ind}>
{handleFolderData(data, ind, "list")}
</div>
);
})}
</div>
);
}
export default PdfFileComponent;
@@ -0,0 +1,530 @@
@import '@radix-ui/colors/black-alpha.css';
@import '@radix-ui/colors/mauve.css';
@import '@radix-ui/colors/violet.css';
.ContextMenuContent,
.ContextMenuSubContent {
min-width: 150px;
background-color: white;
border-radius: 6px;
overflow: hidden;
padding: 5px;
box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2);
}
.ContextMenuItem,
.ContextMenuCheckboxItem,
.ContextMenuRadioItem,
.ContextMenuSubTrigger {
font-size: 13px;
line-height: 1;
color: var(--violet-11);
border-radius: 3px;
display: flex;
align-items: center;
height: 25px;
padding: 0 5px;
position: relative;
padding-left: 25px;
user-select: none;
outline: none;
}
.ContextMenuSubTrigger[data-state='open'] {
background-color: gray;
color: var(--violet-11);
}
.ContextMenuItem[data-disabled],
.ContextMenuCheckboxItem[data-disabled],
.ContextMenuRadioItem[data-disabled],
.ContextMenuSubTrigger[data-disabled] {
color: var(--mauve-8);
pointer-events: 'none';
}
.ContextMenuItem[data-highlighted],
.ContextMenuCheckboxItem[data-highlighted],
.ContextMenuRadioItem[data-highlighted],
.ContextMenuSubTrigger[data-highlighted] {
background-color: #dad9db;
color: var(--violet-11);
}
.ContextMenuLabel {
padding-left: 25px;
font-size: 12px;
line-height: 25px;
color: var(--mauve-11);
}
.ContextMenuItemIndicator {
position: absolute;
left: 0;
width: 25px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.RightSlot {
margin-left: auto;
padding-left: 20px;
color: var(--mauve-11);
}
[data-highlighted]>.RightSlot {
color: white;
}
[data-disabled] .RightSlot {
color: var(--mauve-8);
}
.dropdown-menu {
min-width: 10rem;
}
.dropdown-item {
display: block;
width: 100%;
padding: 0.3rem 1.2rem;
clear: both;
font-weight: 400;
color: #393a39;
text-align: inherit;
white-space: nowrap;
background-color: transparent;
border: 0;
}
.dropdown-item:hover {
background-color: #dad9db;
color: var(--violet-11);
}
.itemColor {
font-size: 13px !important;
}
.folderComponent {
margin: 30px;
height: 100%;
}
.folderComponent::-webkit-scrollbar {
display: none;
/* for Chrome, Safari, and Opera */
}
.modal {
margin-top: 50px;
}
.folderBox {
/* box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
margin: 10px ;
padding: 5px 0px 5px 40px; */
/* overflow: scroll;
display: flex;
justify-content: space-between;
width: 200px; */
margin: 10px;
/* box-shadow: rgba(0, 0, 0, 0.15) 1.95px 1.95px 2.6px; */
}
.folderContainer {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center
}
/* .folderBox:hover{
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
font-weight: bold;
} */
.pdfName {
font-size: 10px;
font-weight: 600;
}
.viewbotton {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
padding: 8px 20px;
color: white;
font-weight: 600;
font-size: 14px;
border: none;
border-radius: 2px;
margin-left: 10px;
}
.viewbotton:focus {
border: none;
outline: none;
}
.folderRender {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
cursor: pointer;
position: relative;
width: 100px;
height: 100px;
margin: 20px;
display: inline-block;
}
.pdfContainer {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-top: 20px;
align-items: center;
justify-content: space-around
}
.pdfContainer .box:last-child {
margin-left: 0;
/* Override the margin on the last box */
margin-right: auto;
/* Align it to the start */
}
.icon-container {
position: relative;
width: 100px;
height: 100px;
margin: 10px;
display: inline-block;
cursor: pointer
}
.hrStyle {
margin-top: 0rem !important;
margin-bottom: 0rem !important;
border: 0;
border-top: 1px solid rgba(0, 0, 0, .1);
}
.pdf-icon {
width: 100%;
height: 100%;
}
.status-badge {
position: absolute;
top: 0;
right: 0;
background-color: #fff;
width: 24px;
height: 24px;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.status-badge i {
font-size: 12px;
}
/* Status-specific colors */
.completed {
background-color: #4CAF50;
color: #fff;
}
.in-progress {
background-color: #FFC107;
color: #fff;
}
.declined {
background-color: #F44336;
color: #fff;
}
.expired {
background-color: #9E9E9E;
color: #fff;
}
.draft {
background-color: #079cdc;
color: #fff;
}
.add {
background-color: #05bbdb;
color: #fff;
padding: 8px 15px;
text-align: center;
display: flex;
margin: 5px;
}
.sort {
padding: 8px 15px;
margin: 5px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.sort:hover {
box-shadow: 0 2px 4px rgba(168, 204, 206, 0.1);
background-color: var(--mauve-3);
border-radius: 2px;
}
/* Hover effect */
.info-box {
position: absolute;
bottom: 100%;
left: 0;
background-color: #fff;
border: 1px solid #ccc;
border-radius: 4px;
padding: 5px;
width: 180px;
display: none;
z-index: 10;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
text-align: center;
}
.icon-container:hover .info-box {
display: block;
}
.folderRender:hover .info-box {
display: block;
}
.info-box:hover {
z-index: 999;
}
.addFolderInput {
padding: 10px;
border-radius: 4px;
/* width: 440px; */
font-size: 15px;
border: 0.5px solid rgb(198, 195, 195);
}
.tooltip-inner {
background-color: #fff;
border: 1px solid black;
font-weight: 600;
opacity: 1 !important;
color: rgb(0, 0, 0);
border-radius: 3px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
font-size: 12px;
}
.fileName {
display: inline-block;
width: 100px;
white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis;
font-size: 11px;
text-align: center;
font-weight: 480;
}
.foldName {
display: inline-block;
width: 100px;
white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis;
font-size: 11px;
text-align: center;
font-weight: 480;
}
.statusSpan {
font-size: 12px;
font-weight: 500;
}
a {
all: unset;
}
.HoverCardContent {
border-radius: 6px;
padding: 5px 10px;
width: 170px;
background-color: white;
box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
animation-duration: 400ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
will-change: transform, opacity;
text-align: center;
align-items: center;
}
.HoverCardContent[data-side='top'] {
animation-name: slideDownAndFade;
}
.HoverCardContent[data-side='right'] {
animation-name: slideLeftAndFade;
}
.HoverCardContent[data-side='bottom'] {
animation-name: slideUpAndFade;
}
.HoverCardContent[data-side='left'] {
animation-name: slideRightAndFade;
}
.HoverCardArrow {
fill: white;
}
@keyframes slideUpAndFade {
0% {
opacity: 0;
transform: translateY(2px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideRightAndFade {
0% {
opacity: 0;
transform: translateX(-2px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slideDownAndFade {
0% {
opacity: 0;
transform: translateY(-2px);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideLeftAndFade {
0% {
opacity: 0;
transform: translateX(2px);
}
100% {
opacity: 1;
transform: translateX(0);
}
}
.dropMenuBD {
display: flex;
flex-direction: row;
align-items: center;
}
.dropMenuSS {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
display: none;
}
.folderPath{
overflow-x: auto;
white-space: nowrap;
cursor: pointer;
user-select: none;
}
.folderPath::-webkit-scrollbar {
display: none;
/* for Chrome, Safari, and Opera */
}
@media (min-width: 310px) and (max-width:550px) {
.pdfContainer {
justify-content: space-around;
}
.sort {
padding: 2px;
}
.folderComponent{
margin: 10px;
}
}
@media screen and (max-width:309px) {
.pdfContainer {
justify-content: center;
}
.sort {
padding: 2px;
}
.folderComponent{
margin: 10px;
}
}
@@ -0,0 +1,722 @@
import React, { useEffect, useState, useRef } from "react";
import axios from "axios";
import "./LegaDrive.css";
import loader from "../../assests/loader2.gif";
import PdfFileComponent from "./FolderDrive/legaDriveComponent";
import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader";
import { themeColor, iconColor } from "../../utils/ThemeColor/backColor";
function PdfFile() {
const scrollRef = useRef(null);
const [isList, setIsList] = useState(false);
const [selectedSort, setSelectedSort] = useState("Date");
const [sortingOrder, setSortingOrder] = useState("Decending");
const [pdfData, setPdfData] = useState([]);
const [isFolder, setIsFolder] = useState(false);
const [newFolderName, setNewFolderName] = useState();
// const [parentFolderName, setParentFolderName] = useState();
// const [parentFolder, setParentFolder] = useState([]);
const [error, setError] = useState();
const [folderLoader, setIsFolderLoader] = useState(false);
const [isShowSort, setIsShowSort] = useState(false);
const [isLoading, setIsLoading] = useState({
isLoad: true,
message: "This might take some time",
});
const [docId, setDocId] = useState();
const [handleError, setHandleError] = useState();
const [folderName, setFolderName] = useState([]);
const senderUser =
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
) &&
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
);
const jsonSender = JSON.parse(senderUser);
useEffect(() => {
if (docId) {
getPdfFolderDocumentList();
} else {
getPdfDocumentList();
}
}, [docId]);
//function for get all pdf document list
const getPdfDocumentList = async () => {
const load = {
isLoad: true,
message: "This might take some time",
};
setIsLoading(load);
//?where={"Type":"Folder" }&include=ExtUserPtr,Signers
//?where={"$or":[{"Type":{"$exists":true}},{"Folder":{"$exists":false}}]}&include=ExtUserPtr,Signers
// "CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${jsonSender.objectId}"}
// where={"Folder":{"$exists":false} }&include=ExtUserPtr,Signers`,
await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document?where={"Folder":{"$exists":false},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${
jsonSender.objectId
}"}}]}&include=ExtUserPtr,Signers`,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken"),
},
}
)
.then((Listdata) => {
const json = Listdata.data;
const res = json.results;
// console.log("result", res);
if (res[0] && res.length > 0) {
setPdfData(res);
}
const data = [
{
name: "OpenSignDrive™",
objectId: "",
},
];
setFolderName(data);
const loadObj = {
isLoad: false,
};
setIsLoading(loadObj);
})
.catch((err) => {
const loadObj = {
isLoad: false,
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
});
};
//function for get parent folder document list
const getPdfFolderDocumentList = async () => {
const load = {
isLoad: true,
message: "This might take some time",
};
setIsLoading(load);
//{"$inQuery":{"where":{"objectId":"${docId}"},"className":"${appName}_Document"}}
//"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${jsonSender.objectId}"}
await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document?where={"Folder":{"__type":"Pointer","className":"${localStorage.getItem(
"_appName"
)}_Document","objectId":"${docId}"},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${
jsonSender.objectId
}"}}]}&include=ExtUserPtr,Signers,Folder`,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken"),
},
}
)
.then((Listdata) => {
const json = Listdata.data;
const res = json.results;
if (res[0] && res.length > 0) {
setPdfData(res);
} else {
setPdfData([]);
}
const loadObj = {
isLoad: false,
};
setIsLoading(loadObj);
})
.catch((err) => {
const loadObj = {
isLoad: false,
};
setHandleError("Error: Something went wrong!");
setIsLoading(loadObj);
});
};
//function for get all pdf document list
const getParentFolder = async () => {
setIsFolder(true);
};
//function for handle folder name path
const handleRoute = (data) => {
let loadObj = {
isLoad: true,
message: "This might take some time",
};
if (data.name === "LegaDrive™") {
setIsLoading(loadObj);
if (docId) {
setDocId();
} else {
setTimeout(() => {
const loadObj = {
isLoad: false,
};
setIsLoading(loadObj);
}, 1000);
}
} else if (data.name === folderName[folderName.length - 1].name) {
setIsLoading(loadObj);
setTimeout(() => {
const loadObj = {
isLoad: false,
};
setIsLoading(loadObj);
}, 1000);
} else {
// console.log("go here1",data.objectId)
const findIndex = folderName.findIndex(
(fold) => fold.objectId === data.objectId
);
const newFolder = folderName.slice(0, findIndex + 1);
setFolderName(newFolder);
const getLastId = newFolder[newFolder.length - 1];
setDocId(getLastId.objectId);
setIsLoading(loadObj);
}
};
//function for add new folder name
const handleFolderName = (e) => {
setError();
const value = e.target.value;
setNewFolderName(value);
};
//function for add folder
const handleAddFolder = async () => {
if (newFolderName) {
setIsFolderLoader(true);
const getParentObjId = folderName[folderName.length - 1];
const isParentId = getParentObjId && getParentObjId.objectId;
let data;
if (isParentId) {
data = {
Name: newFolderName,
Type: "Folder",
Folder: {
__type: "Pointer",
className: `${localStorage.getItem("_appName")}_Document`,
objectId: isParentId,
},
};
} else {
data = {
Name: newFolderName,
Type: "Folder",
};
}
// console.log("data", data);
await axios
.post(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document`,
data,
{
headers: {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
"X-Parse-Session-Token": localStorage.getItem("accesstoken"),
},
}
)
.then((Listdata) => {
// console.log("Listdata ", Listdata);
const json = Listdata.data;
// console.log("json ", json);
if (json) {
setNewFolderName();
setIsFolderLoader(false);
setIsFolder(false);
if (docId) {
getPdfFolderDocumentList();
} else {
getPdfDocumentList();
}
}
})
.catch((err) => {
console.log("axois err ", err);
alert("something went wrong");
});
} else {
setError("Please fill out this field");
}
};
const sortingApp = (appInfo, type, order) => {
if (type === "Name") {
if (order === "Accending") {
return appInfo.sort((a, b) => (a.Name > b.Name ? 1 : -1));
} else if (order === "Decending") {
return appInfo.sort((a, b) => (a.Name > b.Name ? -1 : 1));
}
} else if (type === "Date") {
if (order === "Accending") {
return appInfo.sort((a, b) => (a.createdAt > b.createdAt ? 1 : -1));
} else if (order === "Decending") {
return appInfo.sort((a, b) => (a.createdAt > b.createdAt ? -1 : 1));
}
}
};
const sortApps = () => {
const selectedSortType = selectedSort;
const sortOrder = sortingOrder;
let sortingData = pdfData;
if (selectedSortType === "Name") {
sortingApp(sortingData, "Name", sortOrder);
} else if (selectedSortType === "Date") {
sortingApp(sortingData, "Date", sortOrder);
}
setPdfData(sortingData);
};
//function for handle auto scroll on folder path
const handleMouseEnter = (e) => {
let side = "";
const container = scrollRef.current;
const containerRect = container.getBoundingClientRect();
const cursorX = e.clientX;
const containerX = containerRect.left;
const containerWidth = containerRect.width;
// Define a threshold (e.g., 10 pixels) for the start and end points
const threshold = 10;
if (cursorX - containerX <= threshold) {
side = "start";
} else if (containerX + containerWidth - cursorX <= threshold) {
side = "end";
} else {
side = "";
}
const scrollSpeed = 10;
let scrollAmount = 0;
const scroll = () => {
if (side === "start" && container.scrollLeft > 0) {
container.scrollLeft -= scrollAmount;
requestAnimationFrame(scroll);
} else if (
side === "end" &&
container.scrollLeft < container.scrollWidth - container.clientWidth
) {
container.scrollLeft += scrollAmount;
requestAnimationFrame(scroll);
}
};
container.addEventListener("mousemove", (e) => {
const rect = container.getBoundingClientRect();
const x = e.clientX - rect.left;
const containerWidth = rect.width;
// Calculate the scroll amount based on the cursor's position
scrollAmount = (x / containerWidth) * scrollSpeed;
});
scroll();
};
//handle to close drop down menu onclick screen
useEffect(() => {
const closeMenuOnOutsideClick = (e) => {
if (isShowSort && !e.target.closest("#menu-container")) {
setIsShowSort(false);
}
};
document.addEventListener("click", closeMenuOnOutsideClick);
return () => {
// Cleanup the event listener when the component unmounts
document.removeEventListener("click", closeMenuOnOutsideClick);
};
}, [isShowSort]);
return (
<div className="folderComponent ">
<div>
<Modal show={isFolder}>
<ModalHeader style={{ background: themeColor() }}>
<span style={{ color: "white" }}>Add New Folder</span>
{!folderLoader && (
<span
style={{ cursor: "pointer" }}
onClick={() => {
setNewFolderName("");
setIsFolder(false);
}}
>
X
</span>
)}
</ModalHeader>
<Modal.Body>
{folderLoader ? (
<div
style={{
height: "200px",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
}}
>
<img
alt="loader img"
src={loader}
style={{ width: "50px", height: "50px" }}
/>
<span style={{ fontSize: "13px", color: "gray" }}>
Loading...
</span>
</div>
) : (
<form style={{ display: "flex", flexDirection: "column" }}>
<label
style={{
margin: "10px 0px 10px 0px",
fontSize: "15px",
fontWeight: "400",
}}
>
Name*
</label>
<input
required
className="form-control"
type="text"
value={newFolderName}
onChange={(e) => handleFolderName(e)}
// className="addFolderInput"
/>
<span style={{ color: "red", fontSize: "12px" }}>{error}</span>
<div
style={{
margin: "20px 10px 10px 10px ",
display: "flex",
alignItems: "flex-end",
justifyContent: "flex-end",
alignContent: "flex-end",
}}
>
<button
type="submit"
style={{
borderRadius: "0px",
border: "1.5px solid #e3e2e1",
fontWeight: "600",
color: "black",
}}
className="finishBtn"
onClick={() => setIsFolder(false)}
>
Close
</button>
<button
onClick={() => handleAddFolder()}
style={{
background: themeColor(),
}}
type="button"
className="finishBtn"
>
Add
</button>
</div>
</form>
)}
</Modal.Body>
</Modal>
{isLoading.isLoad ? (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
width: "100%",
flexDirection: "column",
}}
>
<img
alt="loader img"
src={loader}
style={{ width: "80px", height: "80px" }}
/>
<span style={{ fontSize: "13px", color: "gray" }}>
{isLoading.message}
</span>
</div>
) : handleError ? (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
width: "100%",
}}
>
<span style={{ fontSize: "20px", color: "gray" }}>
{handleError}
</span>
</div>
) : (
<>
<div className="folderContainer">
<div
onMouseEnter={(e) => handleMouseEnter(e)}
ref={scrollRef}
style={{
width: "100%",
}}
className="folderPath"
>
{folderName.map((data, id) => {
return (
<span
key={id}
onClick={() => handleRoute(data)}
style={{
color: "#a64b4e",
fontWeight: "400",
cursor: "pointer",
}}
>
{data.name}
<span
style={{
color: "#a64b4e",
fontWeight: "200",
cursor: "pointer",
margin: "0 4px",
}}
>
&gt;
</span>
</span>
);
})}
</div>
<div className="dropMenuBD">
<div
id="menu-container"
class={isShowSort ? "dropdown show" : "dropdown"}
onClick={() => setIsShowSort(!isShowSort)}
>
<div className=" sort " data-toggle="dropdown">
<i
className="fa fa-sort-amount-asc"
aria-hidden="true"
style={{
marginRight: "5px",
fontSize: "14px",
color: `${iconColor()}`,
}}
></i>
<span
style={{
fontSize: "15px",
color: `${iconColor()}`,
}}
>
{selectedSort}
</span>
</div>
<div
className={
isShowSort ? "dropdown-menu show" : "dropdown-menu"
}
aria-labelledby="dropdownMenuButton"
aria-expanded={isShowSort ? "true" : "false"}
>
<span
onClick={() => {
setSelectedSort("Name");
sortApps();
}}
className="dropdown-item itemColor"
>
{selectedSort !== "Name" ? (
<i
className="fa fa-arrow-up"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
) : (
<i
className="fa fa-check"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
)}
Name
</span>
<span
onClick={() => {
setSelectedSort("Date");
sortApps();
}}
className="dropdown-item itemColor"
>
{selectedSort !== "Date" ? (
<i
className="fa fa-arrow-up"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
) : (
<i
className="fa fa-check"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
)}
Date
</span>
<hr className="hrStyle" />
<span
onClick={() => {
setSortingOrder("Accending");
sortApps();
}}
className="dropdown-item itemColor"
>
{sortingOrder !== "Accending" ? (
<i
className="fa fa-arrow-up"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
) : (
<i
className="fa fa-check"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
)}
Accending
</span>
<span
onClick={() => {
setSortingOrder("Decending");
sortApps();
}}
className="dropdown-item itemColor"
>
{sortingOrder !== "Decending" ? (
<i
className="fa fa-arrow-up"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
) : (
<i
className="fa fa-check"
aria-hidden="true"
style={{ marginRight: "5px" }}
></i>
)}
Decending
</span>
</div>
</div>
<div>
{isList ? (
<div className="sort" onClick={() => setIsList(!isList)}>
<i
onClick={() => setIsList(!isList)}
className="fa fa-th-large"
style={{ fontSize: "24px", color: `${iconColor()}` }}
aria-hidden="true"
></i>
</div>
) : (
<div className="sort" onClick={() => setIsList(!isList)}>
<i
className="fa fa-list"
aria-hidden="true"
style={{ fontSize: "23px", color: `${iconColor()}` }}
></i>
</div>
)}
</div>
<div className="sort" onClick={() => getParentFolder()}>
<i
className="fa fa-plus-square"
aria-hidden="true"
style={{ fontSize: "25px", color: `${iconColor()}` }}
></i>
</div>
</div>
</div>
{pdfData && pdfData.length === 0 ? (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "50vh",
width: "100%",
}}
>
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
</div>
) : (
<PdfFileComponent
pdfData={pdfData}
setFolderName={setFolderName}
setIsLoading={setIsLoading}
setDocId={setDocId}
getPdfFolderDocumentList={getPdfFolderDocumentList}
getPdfDocumentList={getPdfDocumentList}
isDocId={docId}
setPdfData={setPdfData}
isList={isList}
/>
)}
</>
)}
</div>
</div>
);
}
export default PdfFile;