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
+51
View File
@@ -0,0 +1,51 @@
import React from "react";
import { HashRouter } from "react-router-dom";
import AppRoutes from "./Routes";
import { HTML5Backend } from "react-dnd-html5-backend";
import { TouchBackend } from "react-dnd-touch-backend";
import {
DndProvider,
TouchTransition,
MouseTransition,
Preview
} from "react-dnd-multi-backend";
import DragElement from "./Component/component/DragElement";
export default function App() {
const HTML5toTouch = {
backends: [
{
id: "html5",
backend: HTML5Backend,
transition: MouseTransition,
},
{
id: "touch",
backend: TouchBackend,
options: { enableMouseEvents: true },
preview: true,
transition: TouchTransition,
},
],
};
const generatePreview = (props) => {
const { item, style } = props;
const newStyle = {
...style,
};
return (
<div style={newStyle}>
<DragElement {...item} />
</div>
);
};
return (
<DndProvider options={HTML5toTouch}>
<Preview>{generatePreview}</Preview>
<HashRouter>
<AppRoutes />
</HashRouter>
</DndProvider>
);
}
@@ -0,0 +1,280 @@
import React, { useEffect, useState } from "react";
import "./certificate.css";
import { Page, Text, View, Document, StyleSheet } from "@react-pdf/renderer";
function Certificate({ pdfData }) {
const [isMultiSigners, setIsMultiSigners] = useState();
const [multiSigner, setMultiSigners] = useState([]);
const [isLoad, setIsLoad] = useState(false);
useEffect(() => {
handleSignerData();
}, []);
const handleSignerData = () => {
const checkSigners = pdfData.filter((data) => data.Signers);
if (checkSigners && checkSigners.length > 0) {
setIsMultiSigners(true);
const checkSignSigners =
pdfData[0].AuditTrail &&
pdfData[0].AuditTrail.length > 0 &&
pdfData[0].AuditTrail.filter((data) => data.Activity === "Signed");
setMultiSigners(checkSignSigners);
} else {
setIsMultiSigners(false);
}
setIsLoad(true);
};
const styles = StyleSheet.create({
page: {
borderRadius: "5px",
padding: "10px",
backgroundColor: "white",
},
section1: {
border: "1px solid rgb(177, 174, 174)",
padding: "20px",
},
textStyle: {
fontWeight: "bold",
fontSize: "11px",
marginBottom: "10px",
},
textStyle2: {
fontWeight: "600",
fontSize: "11px",
marginBottom: "10px",
color: "gray",
},
});
const generatedDate = () => {
const newDate = new Date();
const localExpireDate = newDate.toLocaleDateString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
});
var currentOffset = newDate.getTimezoneOffset();
var ISTOffset = 330; // IST offset UTC +5:30
var ISTTime = new Date(
newDate.getTime() + (ISTOffset + currentOffset) * 60000
);
// ISTTime now represents the time in IST coordinates
var hoursIST = ISTTime.getHours();
var minutesIST = ISTTime.getMinutes();
return (
<Text
style={{
textAlign: "right",
color: "gray",
fontSize: "10px",
marginBottom: "30px",
}}
>
Generated On {localExpireDate} {hoursIST}:{minutesIST} IST
</Text>
);
};
const changeCompletedDate = () => {
const completedOn = pdfData[0].updatedAt;
const newDate = new Date(completedOn);
const localExpireDate = newDate.toLocaleDateString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
});
var currentOffset = newDate.getTimezoneOffset();
var ISTOffset = 330; // IST offset UTC +5:30
var ISTTime = new Date(
newDate.getTime() + (ISTOffset + currentOffset) * 60000
);
// ISTTime now represents the time in IST coordinates
var hoursIST = ISTTime.getHours();
var minutesIST = ISTTime.getMinutes();
return (
<Text style={styles.textStyle2}>
{localExpireDate} {hoursIST}:{minutesIST} IST
</Text>
);
};
const signerName = (data) => {
const getSignerName = pdfData[0].Signers.filter(
(sign) => sign.objectId === data.UserPtr.objectId
);
return (
getSignerName[0] &&
getSignerName.length > 0 && (
<>
<Text style={styles.textStyle}>
Name : &nbsp;
<Text style={styles.textStyle2}>{getSignerName[0].Name}</Text>
</Text>
<Text style={styles.textStyle}>
Email : &nbsp;
<Text style={styles.textStyle2}>{getSignerName[0].Email}</Text>
</Text>
</>
)
);
};
return (
isLoad && (
<Document>
{/** Page defines a single page of content. */}
<Page size="A4" style={styles.page}>
<View style={styles.section1}>
{generatedDate()}
<View style={{ justifyContent: "center" }}>
<Text
style={{
textAlign: "center",
fontSize: "20px",
fontWeight: "bold",
color: "#31bceb",
marginBottom: "10px",
}}
>
{" "}
Certificate of Completion
</Text>
<View style={{ border: "1px solid #bdbbbb" }}></View>
<View>
<View>
<Text
style={{
fontSize: "16px",
fontWeight: "bold",
color: "#31bceb",
margin: "10px 0px 10px 0px",
}}
>
Summary
</Text>
</View>
<View style={{ display: "flex", flexDirection: "column" }}>
<Text style={styles.textStyle}>
Document ID : &nbsp;
<Text style={styles.textStyle2}>{pdfData[0].objectId}</Text>
</Text>
<Text style={styles.textStyle}>
Document Name : &nbsp;
<Text style={styles.textStyle2}>{pdfData[0].Name}</Text>
</Text>
<Text style={styles.textStyle}>
Organization : &nbsp;
<Text style={styles.textStyle2}>__</Text>
</Text>
<Text style={styles.textStyle}>
Completed on : &nbsp;{changeCompletedDate()}
</Text>
{multiSigner && multiSigner.length > 0 && (
<Text style={styles.textStyle}>
Signers : &nbsp;
<Text style={styles.textStyle2}>
{multiSigner.length}
</Text>
</Text>
)}
</View>
{isMultiSigners ? (
<View style={{ display: "flex", flexDirection: "column" }}>
<Text
style={{
fontSize: "16px",
fontWeight: "bold",
color: "#31bceb",
margin: "10px 0px 10px 0px",
}}
>
Recipients
</Text>
<View>
{multiSigner && multiSigner.map((data, ind) => {
return (
<View
key={ind}
style={{ display: "flex", flexDirection: "column" }}
>
<View
style={{
border: "0.4px solid #bdbbbb",
marginBottom: "10px",
}}
></View>
{signerName(data)}
<Text style={styles.textStyle}>
Accessed from : &nbsp;
<Text style={styles.textStyle2}>
{data.ipAddress}
</Text>
</Text>
</View>
);
})}
</View>
</View>
) : (
<View style={{ display: "flex", flexDirection: "column" }}>
<Text
style={{
fontSize: "16px",
fontWeight: "bold",
color: "#31bceb",
margin: "10px 0px 10px 0px",
}}
>
Recipients
</Text>
<Text style={styles.textStyle}>
Signers : &nbsp;<Text style={styles.textStyle2}>1</Text>
</Text>
<Text style={styles.textStyle}>
Name : &nbsp;
<Text style={styles.textStyle2}>
{pdfData[0].ExtUserPtr.Name}
</Text>
</Text>
<Text style={styles.textStyle}>
Accessed from : &nbsp;
<Text style={styles.textStyle2}>
{pdfData[0].AuditTrail && pdfData[0].AuditTrail[0].ipAddress}
</Text>
</Text>
<Text style={styles.textStyle}>
Signed on : &nbsp;{changeCompletedDate()}
</Text>
</View>
)}
</View>
</View>
</View>
</Page>
</Document>
)
);
}
export default Certificate;
@@ -0,0 +1,9 @@
.containerBox {
border-radius: 5px;
padding: 10px;
}
.certificateBox {
border: 1px solid rgb(177, 174, 174);
padding: 20px;
}
@@ -0,0 +1,137 @@
import React, { useEffect, useState } from "react";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import Loader from "./component/loader";
import { getHostUrl } from "../utils/Utils";
function DraftDocument() {
const navigate = useNavigate();
const [pdfDetails, setPdfDetails] = useState([]);
const [isLoading, setIsLoading] = useState({
isLoad: true,
message: "This might take some time",
});
const rowLevel =
localStorage.getItem("rowlevel") &&
JSON.parse(localStorage.getItem("rowlevel"));
const signObjId =
rowLevel && rowLevel?.id
? rowLevel.id
: rowLevel?.objectId && rowLevel.objectId;
useEffect(() => {
if (signObjId) {
getDocumentDetails();
}
}, []);
//get document details
const getDocumentDetails = async () => {
await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Document?where={"objectId":"${signObjId}"}&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("res", res);
if (res[0] && res.length > 0) {
setPdfDetails(res);
const loadObj = {
isLoad: false,
};
setIsLoading(loadObj);
} else {
alert("No data found!");
}
})
.catch((err) => {
console.log("axois err ", err);
});
};
//check document type and render on signyour self and placeholder route
const handleDraftDoc = () => {
const data = pdfDetails[0];
const checkSignerExist =
pdfDetails[0] && pdfDetails[0].Signers && pdfDetails[0].Signers;
const isPlaceholder =
pdfDetails[0].Placeholders && pdfDetails[0].Placeholders;
const isDecline = data.IsDeclined && data.IsDeclined;
const signUrl = data.SignedUrl && data.SignedUrl;
const expireDate = pdfDetails[0] && pdfDetails[0].ExpiryDate.iso && pdfDetails[0].ExpiryDate.iso;
const expireUpdateDate = new Date(expireDate).getTime();
const currDate = new Date().getTime();
const hostUrl = getHostUrl();
//checking document is completed and signer exist then navigate to pdfRequestFiles file
if (data.IsCompleted && checkSignerExist) {
// window.location.hash = `/pdfRequestFiles`;
navigate(`${hostUrl}pdfRequestFiles`);
}
//checking document is completed and signer does not exist then navigate to recipientSignPdf file
else if (data.IsCompleted && !checkSignerExist) {
// window.location.hash = `/recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`;
navigate(
`${hostUrl}recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`
);
}
//checking document is declined by someone then navigate to pdfRequestFiles file
else if (isDecline) {
// window.location.hash = `/pdfRequestFiles`;
navigate(`${hostUrl}pdfRequestFiles`);
}
//checking document has expired and signers exist and placeholder does not set yet then navigate to pdfRequestFiles file
//draft type request sign document
else if (
currDate > expireUpdateDate &&
checkSignerExist &&
!isPlaceholder
) {
// window.location.hash = `/placeHolderSign`;
navigate(`${hostUrl}placeHolderSign`);
}
//checking document has expired and signers does not exist and document not signed yet then navigate to pdfRequestFiles file
//draft type signyouselfdocument
else if (
currDate > expireUpdateDate &&
!checkSignerExist &&
!isPlaceholder &&
!signUrl
) {
// window.location.hash = `/signaturePdf`;
navigate(`${hostUrl}signaturePdf`);
}
//checking document has expired and signers exist and document then navigate to pdfRequestFiles file
else if (currDate > expireUpdateDate) {
// window.location.hash = `/pdfRequestFiles`;
navigate(`${hostUrl}pdfRequestFiles`);
}
//checking document has expired not been expired yet and signers exist and placeholder does not set yet then navigate to pdfRequestFiles file
//draft type request sign document
else if (!signUrl && checkSignerExist) {
navigate(`${hostUrl}placeHolderSign`);
// window.location.hash = `/placeHolderSign`;
} else {
// window.location.hash = `/signaturePdf/`;
navigate(`${hostUrl}signaturePdf/`);
}
};
return (
<div>
{isLoading.isLoad ? <Loader isLoading={isLoading} /> : handleDraftDoc()}
</div>
);
}
export default DraftDocument;
@@ -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;
@@ -0,0 +1,704 @@
import React, { useState, useRef, useEffect } from "react";
import SignatureCanvas from "react-signature-canvas";
import redPen from "../assests/redPen.png";
import bluePen from "../assests/bluePen.png";
import blackPen from "../assests/blackPen.png";
import "../css/custom.css";
import "../css/signature.css";
import axios from "axios";
import { toDataUrl } from "../utils/toDataUrl";
// console.log("appName ", appName)
const ManageSign = () => {
let appName;
const [penColor, setPenColor] = useState("blue");
const [initialPen, setInitialPen] = useState("blue");
const [image, setImage] = useState();
const [signName, setSignName] = useState("");
const [signature, setSignature] = useState("");
const [warning, setWarning] = useState(false);
const [nameWarning, setNameWarning] = useState(false);
const [isvalue, setIsValue] = useState(false);
const allColor = [bluePen, redPen, blackPen];
const [isLoader, setIsLoader] = useState(true);
const [isSuccess, setIsSuccess] = useState(false);
const [Initials, setInitials] = useState("");
const [isInitials, setIsInitials] = useState(false);
const [id, setId] = useState("");
const canvasRef = useRef(null);
const imageRef = useRef(null);
const initailsRef = useRef(null);
useEffect(() => {
getLocalStorageValue();
}, []);
//function for get localstorage value first and than call another function.
const getLocalStorageValue = () => {
let User = JSON.parse(
localStorage.getItem(
"Parse/" + localStorage.getItem("parseAppId") + "/currentUser"
)
);
appName =
localStorage.getItem("_appName") && localStorage.getItem("_appName");
if (User) {
fetchUserSign(User);
}
};
const fetchUserSign = async (User) => {
const userId = {
__type: "Pointer",
className: "_User",
objectId: User.objectId,
};
const strObj = JSON.stringify(userId);
const url =
localStorage.getItem("baseUrl") +
`classes/${appName}_Signature?where={"UserId":${strObj}}&limit=1`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
// "X-Parse-Session-Token": localStorage.getItem("accesstoken"),
};
const res = await axios
.get(url, { headers: headers })
.then((res) => {
if (res.data.results.length > 0) {
setId(res.data.results[0].objectId);
setSignName(res.data.results[0].SignatureName);
// console.log(res.data.results[0].ImageURL);
setImage(res.data.results[0].ImageURL);
if (res.data.results[0] && res.data.results[0].Initials) {
setInitials(res.data.results[0].Initials);
setIsInitials(true);
}
}
setIsLoader(false);
return res;
})
.catch((error) => {
console.log(error);
alert(`${error.message}`);
});
return res;
};
const handleSignatureChange = () => {
if (imageRef.current) {
imageRef.current.value = "";
}
setImage("");
setSignature(canvasRef.current.toDataURL());
setIsValue(true);
};
const handleClear = () => {
if (canvasRef.current) {
canvasRef.current.clear();
}
if (imageRef.current) {
imageRef.current.value = "";
}
setImage("");
setSignature("");
setIsValue(false);
};
const handleClearInitials = () => {
if (initailsRef.current) {
initailsRef.current.clear();
}
setInitials("");
setIsValue(true);
setIsInitials(false);
};
// const handleReset = () => {
// if (canvasRef.current) {
// canvasRef.current.clear();
// }
// if (imageRef.current) {
// imageRef.current.value = "";
// }
// setImage("");
// setSignature("");
// setIsValue(false);
// setSignName("");
// };
const onImageChange = async (event) => {
if (canvasRef.current) {
canvasRef.current.clear();
}
setSignature("");
if (event.target.files && event.target.files[0]) {
const file = event.target.files[0];
const base64Img = await toDataUrl(file);
setImage(base64Img);
setIsValue(true);
}
};
const handleSubmit = async (e) => {
e.preventDefault();
const isUrl = image.includes("https");
if (!signName) {
setNameWarning(true);
// setTimeout(() => setNameWarning(false), 1000);
} else if (!isvalue) {
setWarning(true);
setTimeout(() => setWarning(false), 1000);
} else {
setIsLoader(true);
const replaceSpace = signName.replace(/ /g, "_");
let file;
if (signature) {
file = base64StringtoFile(signature, `${replaceSpace}.png`);
} else {
if (!isUrl) {
file = base64StringtoFile(image, `${replaceSpace}.png`);
}
}
console.log("isUrl ", isUrl);
let imgUrl;
if (!isUrl) {
imgUrl = await uploadFile(file);
} else {
imgUrl = { data: { imageUrl: image } };
}
let initialsUrl = "";
if (Initials) {
const initialsImg = base64StringtoFile(Initials, `${replaceSpace}.png`);
initialsUrl = await uploadFile(initialsImg);
}
if (imgUrl.data && imgUrl.data.imageUrl) {
await saveEntry({
name: signName,
url: imgUrl.data.imageUrl,
initialsUrl: initialsUrl,
});
}
}
};
function base64StringtoFile(base64String, filename) {
var arr = base64String.split(","),
mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]),
n = bstr.length,
u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, { type: mime });
}
const uploadFile = async (file) => {
let parseBaseUrl = localStorage.getItem("baseUrl");
parseBaseUrl = parseBaseUrl.slice(0, -4);
const url = parseBaseUrl + `file_upload`;
const formData = new FormData();
formData.append("file", file);
const config = {
headers: {
"content-type": "multipart/form-data",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
},
onUploadProgress: function (progressEvent) {
let percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
// setpercentage(percentCompleted);
},
};
const response = await axios
.post(url, formData, config)
.then((res) => {
if (res.data.status === "Error") {
alert(res.data.message);
}
return res;
})
.catch((error) => {
console.log(error);
setIsLoader(false);
alert(`${error.message}`);
});
return response;
};
const saveEntry = async (obj) => {
if (id) {
const User = JSON.parse(
localStorage.getItem(
"Parse/" + localStorage.getItem("parseAppId") + "/currentUser"
)
);
const url =
localStorage.getItem("baseUrl") +
`classes/${localStorage.getItem("_appName")}_Signature/${id}`;
const body = {
Initials: obj.initialsUrl ? obj.initialsUrl.data.imageUrl : "",
ImageURL: obj.url,
SignatureName: obj.name,
UserId: {
__type: "Pointer",
className: "_User",
objectId: User.objectId,
},
};
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
// "X-Parse-Session-Token": localStorage.getItem("accesstoken"),
};
const res = await axios
.put(url, body, { headers: headers })
.then((res) => {
// handleReset();
setIsLoader(false);
setIsSuccess(true);
return res;
})
.catch((error) => {
console.log(error);
setIsLoader(false);
alert(`${error.message}`);
});
return res;
} else {
const User = JSON.parse(
localStorage.getItem(
"Parse/" + localStorage.getItem("parseAppId") + "/currentUser"
)
);
const url =
localStorage.getItem("baseUrl") +
`classes/${localStorage.getItem("_appName")}_Signature`;
const body = {
Initials: obj.initialsUrl ? obj.initialsUrl.data.imageUrl : "",
ImageURL: obj.url,
SignatureName: obj.name,
UserId: {
__type: "Pointer",
className: "_User",
objectId: User.objectId,
},
};
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
// "X-Parse-Session-Token": localStorage.getItem("accesstoken"),
};
const res = await axios
.post(url, body, { headers: headers })
.then((res) => {
// handleReset();
setIsLoader(false);
setIsSuccess(true);
return res;
})
.catch((error) => {
console.log(error);
setIsLoader(false);
alert(`${error.message}`);
});
return res;
}
};
const handleSignatureBtn = () => {
if (imageRef.current) {
imageRef.current.value = "";
}
setImage("");
};
const handleUploadBtn = () => {
imageRef.current.click();
};
const handleInitialsChange = () => {
setInitials(initailsRef.current.toDataURL());
setIsValue(true);
};
return (
<div
style={{
maxHeight: "500px",
overflow: "auto",
}}
>
{isSuccess && (
<div
className="alert alert-success successBox"
role="alert"
onAnimationEnd={() => setIsSuccess(false)}
>
Signature saved successfully!
</div>
)}
<div
className="mainDiv"
style={{
// height: "100%",
width: "100%",
paddingRight: "10px",
// maxHeight:"500px",
}}
>
<div style={{ margin: 20 }}>
<div
style={{
fontWeight: "700",
fontSize: 15,
color: "#000",
paddingBottom: 8,
}}
>
Manage Signature
</div>
<div style={{ display: "flex", flexDirection: "column" }}>
<label
htmlFor="signName"
style={{
fontSize: 12,
position: "relative",
paddingBottom: 5,
}}
>
Signer's Name
{nameWarning && (
<div
className="warning nameWarning"
style={{ fontSize: 12 }}
onAnimationEnd={() => setNameWarning(false)}
>
<i
className="fas fa-exclamation-circle"
style={{ color: "#fab005", fontSize: 15 }}
></i>{" "}
Please fill input field
</div>
)}
</label>
<input
id="signName"
className="signInputManage"
value={signName}
style={{
border: "1px solid #ccc",
borderRadius: 4,
height: 35,
padding: "6px 12px",
marginBottom: 10,
fontSize: 12,
}}
required
onFocus={() => setNameWarning(false)}
onChange={(e) => setSignName(e.target.value)}
/>
<label
htmlFor="imgoverview"
style={{
fontSize: 12,
paddingBottom: 5,
}}
>
Signature/Image
</label>
</div>
<div className="signBlock">
<div>
<div style={{ position: "relative" }}>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
width: "50%",
paddingLeft: 10,
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-around",
alignItems: "center",
gap: 10,
marginBottom: 10,
}}
>
<>
<span
onClick={() => handleSignatureBtn()}
className="signature"
>
Signature
</span>
</>
<span
onClick={() => handleUploadBtn()}
className="imgupload"
>
Upload Image
</span>
<input
type="file"
onChange={onImageChange}
className="filetype"
accept="image/*"
ref={imageRef}
hidden
/>
</div>
</div>
<div style={{ position: "relative" }}>
<div>
{image ? (
<div
style={{
position: "relative",
border: "2px solid #888",
marginBottom: 6,
}}
className="signatureCanvas"
>
<img
alt="preview image"
src={image}
style={{
width: "100%",
height: "100%",
objectFit: "contain",
}}
/>
</div>
) : (
<SignatureCanvas
ref={canvasRef}
penColor={penColor}
canvasProps={{
width: "456px",
height: "180px",
className: "signatureCanvas",
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleSignatureChange(canvasRef.current.toDataURL())
}
dotSize={1}
/>
)}
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
// width: 460,
}}
className="penContainer"
>
<div>
{!image && (
<div
style={{ display: "flex", flexDirection: "row" }}
>
{allColor.map((data, key) => {
return (
<img
alt="black img"
style={{
border: "none",
margin: "5px",
borderBottom:
key == 0 && penColor == "blue"
? "2px solid blue"
: key == 1 && penColor == "red"
? "2px solid red"
: key == 2 && penColor == "black"
? "2px solid black"
: "2px solid white",
}}
onClick={() => {
if (key == 0) {
setPenColor("blue");
} else if (key == 1) {
setPenColor("red");
} else if (key == 2) {
setPenColor("black");
}
}}
key={key}
src={data}
width={20}
height={20}
/>
);
})}
</div>
)}
</div>
<div>
<div
type="button"
className="clearbtn"
onClick={() => handleClear()}
>
Clear
</div>
</div>
</div>
</div>
{warning && (
<div
className="warning signWarning"
style={{ fontSize: 12 }}
>
<i
className="fas fa-exclamation-circle"
style={{ color: "#fab005", fontSize: 15 }}
></i>{" "}
Please upload signature/Image
</div>
)}
</div>
</div>
</div>
<div style={{ position: "relative" }}>
<div style={{ margin: "6px 5px 18px" }}>
<span
// onClick={() => handleSignatureBtn()}
className="signature"
>
Initials
</span>
</div>
<div>
{isInitials ? (
<div
style={{
position: "relative",
border: "2px solid #888",
marginBottom: 6,
}}
className="signatureCanvas"
>
<img
alt="preview image"
src={Initials}
style={{
width: "100%",
height: "100%",
objectFit: "contain",
}}
/>
</div>
) : (
<SignatureCanvas
ref={initailsRef}
penColor={initialPen}
canvasProps={{
width: "456px",
height: "180px",
className: "signatureCanvas",
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleInitialsChange(initailsRef.current.toDataURL())
}
dotSize={1}
/>
)}
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
// width: 460,
}}
className="penContainer"
>
<div>
{!isInitials && (
<div style={{ display: "flex", flexDirection: "row" }}>
{allColor.map((data, key) => {
return (
<img
style={{
border: "none",
margin: "5px",
borderBottom:
key == 0 && initialPen == "blue"
? "2px solid blue"
: key == 1 && initialPen == "red"
? "2px solid red"
: key == 2 && initialPen == "black"
? "2px solid black"
: "2px solid white",
}}
onClick={() => {
if (key == 0) {
setInitialPen("blue");
} else if (key == 1) {
setInitialPen("red");
} else if (key == 2) {
setInitialPen("black");
}
}}
key={key}
src={data}
width={20}
height={20}
/>
);
})}
</div>
)}
</div>
<div>
<div
type="button"
className="clearbtn"
onClick={() => handleClearInitials()}
>
Clear
</div>
</div>
</div>
</div>
{/* {!warning && (
<div className="warning signWarning" style={{ fontSize: 12 }}>
<i
className="fas fa-exclamation-circle"
style={{ color: "#fab005", fontSize: 15 }}
></i>{" "}
Please upload signature/Image
</div>
)} */}
</div>
</div>
<div style={{ paddingTop: 10 }}>
<button
className="customBtn successBtn"
onClick={(e) => handleSubmit(e)}
>
save
</button>
</div>
</div>
{isLoader && (
<div className="loaderContainer">
<div className="loader"></div>
</div>
)}
</div>
</div>
);
};
export default ManageSign;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,58 @@
import React from "react";
import stamp from "../../assests/stamp2.png";
import sign from "../../assests/sign3.png";
import { themeColor } from "../../utils/ThemeColor/backColor";
function DragElement({ type, id }) {
const selectedId = id;
return (
<div>
{selectedId === 3 ? (
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
userSelect: "none",
}}
>
<img
alt="sign img"
style={{
width: "25px",
height: "23px",
background: themeColor(),
}}
src={sign}
/>
<span style={{ color: themeColor(), fontSize: "12px" }}>
Signature
</span>
</div>
) : (
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
userSelect: "none",
}}
>
<img
alt="stamp img"
style={{
width: "25px",
height: "23px",
background: themeColor(),
}}
src={stamp}
/>
<span style={{ color: themeColor(), fontSize: "12px" }}>Stamp</span>
</div>
)}
</div>
);
}
export default DragElement;
@@ -0,0 +1,18 @@
import React from "react";
function HandleError({ handleError }) {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
}}
>
<span style={{ fontSize: "20px", color: "gray" }}>{handleError}</span>
</div>
);
}
export default HandleError;
@@ -0,0 +1,18 @@
import React from "react";
function Nodata() {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "50vh",
}}
>
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
</div>
);
}
export default Nodata;
@@ -0,0 +1,122 @@
import React, { useEffect } from "react";
import axios from "axios";
function DefaultSignature({
themeColor,
defaultSignImg,
setShowAlreadySignDoc,
setDefaultSignImg,
userObjectId,
setIsLoading,
xyPostion,
}) {
useEffect(() => {
getDefaultSignature(userObjectId);
}, []);
//function for fetch default sigature added bu users
const getDefaultSignature = async (userObjectId) => {
await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Signature?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${userObjectId}"}}`,
{
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) {
setDefaultSignImg(res[0].ImageURL);
}
const loadObj = {
isLoad: false,
};
setIsLoading(loadObj);
})
.catch((err) => {
// this.setState({ loading: false });
console.log("axois err ", err);
});
};
const confirmToaddDefaultSign = () => {
if (xyPostion.length > 0) {
const alreadySign = {
status: true,
mssg: "Are you sure you want to sign at requested locations?",
sure: true,
};
setShowAlreadySignDoc(alreadySign);
} else {
alert("please select position!");
}
};
return (
<div className="signerComponent">
<div
style={{
background: themeColor(),
color: "white",
padding: "5px",
fontFamily: "sans-serif",
}}
>
Signature
</div>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
marginTop: "10px",
fontWeight: "600",
}}
>
{defaultSignImg ? (
<>
<p>Your Signature</p>
<div className="defaultSignBox">
<img
alt="default img"
style={{
width: "100%",
height: "100%",
objectFit: "contain",
}}
src={defaultSignImg}
/>
</div>
<button
style={{
background: themeColor(),
color: "white",
marginTop: "20px",
cursor: "pointer",
}}
type="button"
className="finishBtn finishnHover"
onClick={() => confirmToaddDefaultSign()}
>
Auto Sign All
</button>
</>
) : (
<div style={{ margin: "10px" }}>
<span>You didn't add your default signature yet!</span>
</div>
)}
</div>
</div>
);
}
export default DefaultSignature;
@@ -0,0 +1,385 @@
import React, { useState } from "react";
import { saveAs } from "file-saver";
import celebration from "../../assests/newCeleb.gif";
import close from "../../assests/close.png";
import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader";
import axios from "axios";
import { getBase64FromUrl } from "../../utils/Utils";
import { themeColor } from "../../utils/ThemeColor/backColor";
import printModule from "print-js";
import loader from "../../assests/loader2.gif";
function EmailComponent({
isEmail,
pdfUrl,
isCeleb,
setIsEmail,
setSuccessEmail,
signObjId,
pdfName,
sender,
}) {
const [emailCount, setEmailCount] = useState([]);
const [emailValue, setEmailValue] = useState();
const [isLoading, setIsLoading] = useState(false);
//function for send email
const sendEmail = async () => {
setIsLoading(true);
let sendMail, recipent;
for (let i = 0; i < emailCount.length; i++) {
// await axios
// .get(
// `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem("_appName")}_Contactbook?where={"Email":"${emailCount[i]}"}`,
// {
// headers: {
// "Content-Type": "application/json",
// "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
// sessionToken: localStorage.getItem("accesstoken"),
// },
// }
// )
// .then((Listdata) => {
// const json = Listdata.data;
// if (json.results[0]) {
// recipent = json.results[0];
// }
// })
// .catch((err) => {
// console.log("axois err ", err);
// });
try {
console.log("recipients", recipent);
const imgPng =
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png";
// "https://qikinnovation.ams3.digitaloceanspaces.com/mailLogo_2023-08-18T12%3A51%3A31.573Z.png";
let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3/`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
sessionToken: localStorage.getItem("accesstoken"),
};
// const serverUrl = localStorage.getItem("baseUrl");
// const newServer = serverUrl.replaceAll("/", "%2F");
// const serverParams = `${newServer}&${localStorage.getItem(
// "parseAppId"
// )}&${localStorage.getItem("_appName")}`;
// let pdfUrlWeb = `<span><a href=https://qik-ai-org.github.io/Sign-MicroappV2/#/login/${signObjId}/${recipent.Email}/${serverParams} style='cursor: pointer;'> ${pdfName}</a><span>`;
const themeBGcolor = themeColor();
let params = {
pdfName: pdfName,
url: pdfUrl,
recipient: emailCount[i],
subject: `${sender.name} has signed the doc - ${pdfName}`,
from: sender.email,
html:
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=" +
imgPng +
" height='50' style='padding:20px,width:170px,height:40px'/> </div><div style='padding:2px;font-family:system-ui; background-color:" +
themeBGcolor +
";'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document Copy</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document " +
pdfName +
" Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from Open Sign. For any queries regarding this email, please contact the sender " +
sender.email +
" directly. If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p></div></div></body></html>",
//"html":"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color: white;padding-bottom: 20px;'> <div><img src="+imgPng +" height='50' style='padding: 20px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color: #47a3ad;'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + recipent.Name + " has requested you to review and sign" +pdfName+"</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><span>Sender</span><span>" + recipent.Email + " </span></div><div style='display: flex; justify-content: center;margin-top: 10px;'><button style='padding: 8px 15px 8px 15px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;'>Sign here</button></div></div></div><div><p> This is an automated email from Open Sign. For any queries regarding this email, please contact the sender " + recipent.Email + " directly.If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p> </div></div></body> </html>"
};
sendMail = await axios.post(url, params, { headers: headers });
} catch (error) {
console.log("error", error);
setIsLoading(false);
alert("Something went wrong!");
}
}
if (sendMail.data.result.status === "success") {
setIsEmail(false);
setSuccessEmail(true);
setTimeout(() => {
setSuccessEmail(false);
}, 3000);
setIsLoading(false);
} else if (sendMail.data.result.status === "error") {
setIsLoading(false);
alert("Something went wrong!");
} else {
setIsLoading(false);
alert("Something went wrong!");
}
};
//function for remove email
const removeChip = (index) => {
const updateEmailCount = emailCount.filter((data, key) => key !== index);
setEmailCount(updateEmailCount);
};
//function for get email value
const handleEmailValue = (e) => {
const value = e.target.value;
setEmailValue(value);
};
//function for save email in array after press enter
const handleEnterPress = (e) => {
if (e.key === "Enter" && emailValue) {
setEmailCount((prev) => [...prev, emailValue]);
setEmailValue("");
} else if (e === "add" && emailValue) {
setEmailCount((prev) => [...prev, emailValue]);
setEmailValue("");
}
};
// function for print signed pdf
const handleToPrint = async (event) => {
event.preventDefault();
const base64 = await getBase64FromUrl(pdfUrl);
printModule({ printable: base64, type: "pdf", base64: true });
// window.print('https://nxgcreator.s3.ap-south-1.amazonaws.com/exported_file_32_2023-08-22T04%3A59%3A13.432Z.pdf',);
};
//handle download signed pdf
const handleDownloadPdf = () => {
saveAs(pdfUrl, `${pdfName}_signed_by_opensign.qik.ai.pdf`);
};
return (
<div>
{/* isEmail */}
<Modal show={isEmail}>
{isLoading && (
<div
style={{
position: "absolute",
height: "100%",
width: "100%",
display: "flex",
justifyContent: "center",
flexDirection: "column",
alignItems: "center",
zIndex: "20",
backgroundColor: "#e6f2f2",
opacity: 0.8,
}}
>
<img
alt="no img"
src={loader}
style={{ width: "70px", height: "70px" }}
/>
<span style={{ fontSize: "12px", fontWeight: "bold" }}>
This might take some time
</span>
</div>
)}
<ModalHeader style={{ background: themeColor() }}>
<span style={{ color: "white" }}>Email Documents</span>
<div style={{ display: "flex", flexDirection: "row" }}>
<div></div>
<button
onClick={handleToPrint}
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
className="btn btn-primary btn-sm"
>
<i
class="fa fa-print"
style={{
fontSize: "15px",
marginRight: "3px",
color: "white",
}}
aria-hidden="true"
></i>
Print
</button>
<button
className="btn btn-danger btn-sm"
onClick={() => handleDownloadPdf()}
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
marginLeft: "10px",
}}
>
<i
className="fa fa-download"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px",
}}
aria-hidden="true"
></i>
Download
</button>
</div>
</ModalHeader>
<Modal.Body>
{isCeleb && (
<div
style={{
position: "absolute",
marginLeft: "50px",
}}
>
<img
alt="print img"
width={300}
height={250}
// style={styles.gifCeleb}
src={celebration}
/>
</div>
)}
<p
style={{
fontFamily: "system-ui",
verticalAlign: "baseline",
fontWeight: "500",
color: "#403f3e",
fontSize: "15px",
}}
>
Recipients added here will get a copy of the signed document.
</p>
{emailCount.length > 0 ? (
<>
<div className="addEmail">
<div
style={{
display: "flex",
flexDirection: "row",
width: "450px",
flexWrap: "wrap",
}}
>
{emailCount.map((data, ind) => {
return (
<div className="emailChip" key={ind}>
<span
style={{
color: "white",
fontSize: "13px",
marginRight: "20px",
}}
>
{data}
</span>
<img
alt="print img"
onClick={() => removeChip(ind)}
src={close}
width={10}
height={10}
style={{ fontWeight: "600" }}
/>
</div>
);
})}
</div>
{emailCount.length <= 9 && (
<input
type="text"
value={emailValue}
className="addEmailInput"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
required
/>
)}
</div>
</>
) : (
<div>
<input
type="text"
value={emailValue}
className="emailInput"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
placeholder="Add the email addresses"
required
/>
</div>
)}
<span
style={{
cursor: emailValue && "pointer",
}}
onClick={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
>
<i
style={{
backgroundColor: themeColor(),
padding: "2px 10px",
marginTop: "10px",
color: "white",
}}
class="fa fa-plus"
aria-hidden="true"
></i>
</span>
<div
style={{
background: "#e3e2e1",
marginTop: "30px",
padding: "5px",
borderRadius: "3px",
}}
>
<span style={{ fontWeight: "700" }}>Note:</span>
<span style={{ fontSize: "15px" }}>
{" "}
You can only send to ten recipients at a time.
</span>
</div>
</Modal.Body>
<Modal.Footer>
<button
style={{
color: "black",
}}
type="button"
className="finishBtn"
onClick={() => setIsEmail(false)}
>
Close
</button>
<button
disabled={emailCount.length === 0 && true}
style={{
background: themeColor(),
color: "white",
}}
type="button"
className={emailCount.length === 0 ? "defaultBtn" : "finishBtn"}
onClick={() => sendEmail()}
>
Send
</button>
</Modal.Footer>
</Modal>
</div>
);
}
export default EmailComponent;
@@ -0,0 +1,366 @@
import React, { useState } from "react";
import * as Select from "@radix-ui/react-select";
import classnames from "classnames";
function FieldsComponent({
pdfUrl,
sign,
stamp,
dragSignature,
signRef,
handleDivClick,
handleMouseLeave,
isDragSign,
themeColor,
dragStamp,
dragRef,
isDragStamp,
dragSignatureSS,
dragStampSS,
isDragSignatureSS,
isSignYourself,
addPositionOfSignature,
signerPos,
signersdata,
isSelectListId,
setSignerObjId,
setIsSelectId,
setContractName,
isSigners,
}) {
const signStyle = pdfUrl ? "disableSign" : "signatureBtn";
const isMobile = window.innerWidth < 712;
const [isShowSort, setIsShowSort] = useState(false);
const [selectedEmail, setSelectedEmail] = useState("");
const SelectItem = React.forwardRef(
({ children, className, ...props }, forwardedRef) => {
return (
<Select.Item
className={classnames("SelectItem", className)}
{...props}
ref={forwardedRef}
>
<Select.ItemText>{children}</Select.ItemText>
<Select.ItemIndicator className="SelectItemIndicator"></Select.ItemIndicator>
</Select.Item>
);
}
);
console.log("sign",isSignYourself)
return (
<>
<div className="signerComponent">
<div
style={{
background: themeColor(),
padding: "5px",
}}
>
<span className="signedStyle">Fields</span>
</div>
<div className="signLayoutContainer1">
{pdfUrl ? (
<>
<button className={signStyle} disabled={true}>
<span
style={{
fontWeight: "400",
fontSize: "15px",
padding: "3px 20px 0px 20px",
color: "#bfbfbf",
}}
>
Signature
</span>
<img
alt="sign img"
style={{
width: "30px",
height: "28px",
background: "#d3edeb",
}}
src={sign}
/>
</button>
<button className={signStyle} disabled={true}>
<span
style={{
fontWeight: "400",
fontSize: "15px",
padding: "3px 0px 0px 35px",
color: "#bfbfbf",
}}
>
Stamp
</span>
<img
alt="stamp img"
style={{
width: "25px",
height: "28px",
background: "#d3edeb",
}}
src={stamp}
/>
</button>
</>
) : (
<>
<div
ref={(element) => {
dragSignature(element);
if (element) {
signRef.current = element;
// const height = signRef && signRef.current.offsetHeight;
// const width = signRef && signRef.current.offsetWidth;
}
}}
className={signStyle}
onMouseMove={handleDivClick}
onMouseDown={handleMouseLeave}
style={{
opacity: isDragSign ? 0.5 : 1,
boxShadow:
"0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)",
}}
>
<span
style={{
fontWeight: "400",
fontSize: "15px",
padding: "3px 20px 0px 20px",
color: "black",
}}
>
Signature
</span>
<img
alt="sign img"
style={{
width: "30px",
height: "28px",
background: themeColor(),
}}
src={sign}
/>
</div>
<div
ref={(element) => {
dragStamp(element);
dragRef.current = element;
if (isDragStamp) {
// setIsStamp(true);
}
}}
className={!pdfUrl ? signStyle : "disableSign"}
disabled={pdfUrl && true}
onMouseMove={handleDivClick}
onMouseDown={handleMouseLeave}
style={{
opacity: isDragStamp ? 0.5 : 1,
boxShadow:
"0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)",
}}
>
<span
style={{
fontWeight: "400",
fontSize: "15px",
padding: "3px 0px 0px 35px",
color: !pdfUrl ? "black" : "#bfbfbf",
}}
>
Stamp
</span>
<img
alt="stamp img"
style={{
width: "25px",
height: "28px",
background: themeColor(),
}}
src={stamp}
/>
</div>
</>
)}
</div>
</div>
{isMobile && isSignYourself && (
<div
id="navbar"
className="stickyfooter"
style={{ width: window.innerWidth + "px" }}
>
{isSigners && (
<div
style={{
background: "#887abf",
padding: "10px 20px",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<span style={{ fontSize: "18px", fontWeight: "500" }}>
Signer :
</span>
<Select.Root onValueChange={(e) => console.log("value", e)}>
<Select.Trigger
onValueChange={(e) => console.log("value", e)}
className="SelectTrigger"
aria-label="Food"
>
<Select.Value placeholder="Select signer" />
<Select.Icon className="SelectIcon">
<i
style={{
marginTop: "5px",
marginLeft: "5px",
color: "#3b15d1",
fontSize: "20px",
}}
class="fa fa-angle-down"
aria-hidden="true"
></i>
</Select.Icon>
</Select.Trigger>
<Select.Portal>
<Select.Content
className="SelectContent"
style={{ zIndex: "5000" }}
>
<Select.ScrollUpButton className="SelectScrollButton">
<i
style={{
marginTop: "5px",
marginLeft: "5px",
color: "#3b15d1",
fontSize: "20px",
}}
class="fa fa-angle-down"
aria-hidden="true"
></i>
</Select.ScrollUpButton>
<Select.Viewport className="SelectViewport">
<Select.Group>
{signersdata.Signers.map((obj, ind) => {
return (
<SelectItem key={ind} value={selectedEmail}>
{" "}
{obj.Email}
</SelectItem>
);
})}
</Select.Group>
</Select.Viewport>
<Select.ScrollDownButton className="SelectScrollButton">
<i
style={{
marginTop: "5px",
marginLeft: "5px",
color: "#3b15d1",
fontSize: "20px",
}}
class="fa fa-angle-down"
aria-hidden="true"
></i>
</Select.ScrollDownButton>
</Select.Content>
</Select.Portal>
</Select.Root>
</div>
)}
<div
className="signLayoutContainer2"
style={{ backgroundColor: themeColor() }}
>
<div
onClick={() => addPositionOfSignature("onclick", false)}
ref={(element) => {
dragSignatureSS(element);
if (element) {
signRef.current = element;
// const height = signRef && signRef.current.offsetHeight;
// const width = signRef && signRef.current.offsetWidth;
}
}}
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
userSelect: "none",
opacity: isDragSignatureSS ? 0.5 : 1,
backgroundImage: `url(${sign})`,
backgroundSize: "70% 70%",
backgroundRepeat: "no-repeat",
backgroundPosition: "center center",
paddingBottom: "2.2rem",
}}
>
{/* <img
alt="sign img"
style={{
width: "30px",
height: "30px",
background: themeColor(),
}}
src={sign}
/> */}
<span
style={{
color: "white",
fontSize: "12px",
position: "relative",
top: "2.6rem",
}}
>
Signature
</span>
</div>
<div
onClick={() => addPositionOfSignature("onclick", true)}
ref={(element) => {
dragStampSS(element);
dragRef.current = element;
}}
onMouseMove={handleDivClick}
onMouseDown={handleMouseLeave}
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
userSelect: "none",
backgroundImage: `url(${stamp})`,
backgroundSize: "32px 33px",
backgroundRepeat: "no-repeat",
backgroundPosition: "center center",
paddingBottom: "2.2rem",
}}
>
<span
style={{
color: "white",
fontSize: "12px",
position: "relative",
top: "2.6rem",
}}
>
Stamp
</span>
</div>
</div>
</div>
)}
</>
);
}
export default FieldsComponent;
@@ -0,0 +1,660 @@
import React from "react";
import PrevNext from "./prevNext";
import { PDFDownloadLink } from "@react-pdf/renderer";
import Certificate from "../Certificate/Certificate";
import printModule from "print-js";
import { getBase64FromUrl } from "../../utils/Utils";
import { saveAs } from "file-saver";
import "../../css/signature.css";
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
import { useNavigate } from "react-router-dom";
import { themeColor } from "../../utils/ThemeColor/backColor";
function Header({
isPdfRequestFiles,
isPlaceholder,
recipient,
setIsDecline,
pageNumber,
isAlreadySign,
allPages,
changePage,
pdfUrl,
documentStatus,
embedImages,
pdfDetails,
signerPos,
signersdata,
isMailSend,
alertSendEmail,
isSigned,
isCompleted,
isShowHeader,
decline,
currentSigner,
}) {
const isMobile = window.innerWidth < 712;
const navigate = useNavigate();
//for go to previous page
function previousPage() {
changePage(-1);
}
//for go to next page
function nextPage() {
changePage(1);
}
//function for show decline alert
const handleDeclinePdfAlert = async () => {
const currentDecline = {
currnt: "Sure",
isDeclined: true,
};
setIsDecline(currentDecline);
};
//function for print digital sign pdf
const handleToPrint = async (event) => {
event.preventDefault();
const pdf = await getBase64FromUrl(pdfUrl);
printModule({ printable: pdf, type: "pdf", base64: true });
};
//handle download signed pdf
const handleDownloadPdf = () => {
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
saveAs(pdfUrl, `${pdfName}_signed_by_opensign.qik.ai.pdf`);
};
return (
<div
style={{ paddingBottom: "5px", paddingTop: "5px" }}
className="mobileHead"
>
<div className="signatureHeader headerBtn">
<PrevNext
pageNumber={pageNumber}
allPages={allPages}
changePage={changePage}
/>
{recipient ? (
pdfUrl || isAlreadySign.mssg ? (
<div style={{ display: "flex", flexDirection: "row" }}>
{pdfDetails[0] && pdfDetails.length > 0 && (
// <Certificate
// pdfData={completePdfData}
// />
<PDFDownloadLink
document={<Certificate pdfData={pdfDetails} />}
fileName={`completion certificate-${
pdfDetails[0] && pdfDetails[0].Name
}.pdf`}
>
{({ blob, url, loading, error }) =>
loading ? (
"Loading document..."
) : (
<button
type="button"
className="defaultBtn certificateBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
>
<i
class="fa fa-certificate"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px",
}}
aria-hidden="true"
></i>
Certificate
</button>
)
}
</PDFDownloadLink>
)}
<button
onClick={handleToPrint}
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
className="defaultBtn printBtn"
>
<i
class="fa fa-print"
style={{
fontSize: "15px",
marginRight: "3px",
color: "white",
}}
aria-hidden="true"
></i>
Print
</button>
<button
type="button"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
className="defaultBtn downloadBtn"
onClick={() => handleDownloadPdf()}
>
<i
className="fa fa-download"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px",
}}
aria-hidden="true"
></i>
Download
</button>
</div>
) : (
<div style={{ display: "flex", flexDirection: "row" }}>
<button
style={{
background: "#de4337",
}}
className="finishBtn hoverCss"
onClick={() => {
handleDeclinePdfAlert();
}}
>
Decline
</button>
<button
data-tut="reactourThird"
style={{
background: !pdfUrl ? "#188ae2" : "#d3edeb",
}}
className="finishBtn sendHover"
onClick={() => {
if (!pdfUrl) {
embedImages();
}
}}
>
Finish
</button>
</div>
)
) : pdfUrl || (documentStatus && documentStatus.isCompleted) ? (
<div style={{ display: "flex", flexDirection: "row" }}>
<PDFDownloadLink
document={<Certificate pdfData={pdfDetails} />}
fileName={`completion certificate-${
pdfDetails[0] && pdfDetails[0].Name
}.pdf`}
>
{({ blob, url, loading, error }) =>
loading ? (
"Loading document..."
) : (
<button
type="button"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
className="defaultBtn certificateBtn"
>
<i
class="fa fa-certificate"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px",
}}
aria-hidden="true"
></i>
Certificate
</button>
)
}
</PDFDownloadLink>
<button
onClick={handleToPrint}
type="button"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
className="defaultBtn printBtn"
>
<i
class="fa fa-print"
style={{
fontSize: "15px",
marginRight: "3px",
color: "white",
}}
aria-hidden="true"
></i>
Print
</button>
<button
type="button"
className="defaultBtn downloadBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
marginLeft: "10px",
}}
onClick={() => handleDownloadPdf()}
>
<i
className="fa fa-download"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px",
}}
aria-hidden="true"
></i>
Download
</button>
</div>
) : isPlaceholder ? (
<>
{!isMailSend &&
signersdata.Signers &&
signersdata.Signers.length !== signerPos.length && (
<div>
{signerPos.length === 0 ? (
<span style={{ fontSize: "13px", color: "#f5405e" }}>
Add all {signersdata.Signers.length - signerPos.length}{" "}
recipients signature
</span>
) : (
<span style={{ fontSize: "13px", color: "#f5405e" }}>
Add {signersdata.Signers.length - signerPos.length} more
recipients signature
</span>
)}
</div>
)}
<div>
<button
onClick={() => {
navigate(-1);
}}
type="button"
className="defaultBtn backBtn"
>
Back
</button>
<button
data-tut="reactourFour"
style={{
background: !isMailSend ? "#188ae2" : "#d3edeb",
}}
onClick={() => {
alertSendEmail();
}}
className="finishBtn sendHover"
>
Send
</button>
</div>
</>
) : isPdfRequestFiles ? (
isSigned ? (
<div style={{ display: "flex", flexDirection: "row" }}>
{isCompleted.isCertificate && (
<PDFDownloadLink
document={<Certificate pdfData={pdfDetails} />}
fileName={`completion certificate-${
pdfDetails[0] && pdfDetails[0].Name
}.pdf`}
>
{({ blob, url, loading, error }) =>
loading ? (
"Loading document..."
) : (
<button
type="button"
className="defaultBtn certificateBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
>
<i
class="fa fa-certificate"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px",
}}
aria-hidden="true"
></i>
Certificate
</button>
)
}
</PDFDownloadLink>
)}
<button
onClick={handleToPrint}
type="button"
className="defaultBtn printBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
>
<i
class="fa fa-print"
style={{
fontSize: "15px",
marginRight: "3px",
color: "white",
}}
aria-hidden="true"
></i>
Print
</button>
<button
type="button"
className="defaultBtn downloadBtn"
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
}}
onClick={() => handleDownloadPdf()}
>
<i
className="fa fa-download"
style={{
color: "white",
fontSize: "15px",
marginRight: "3px",
}}
aria-hidden="true"
></i>
Download
</button>
</div>
) : (
<div>
<button
onClick={() => {
navigate(-1);
}}
type="button"
className="defaultBtn backBtn"
>
Back
</button>
{currentSigner && (
<>
<button
style={{
background: "#de4337",
}}
className="finishBtn hoverCss"
onClick={() => {
handleDeclinePdfAlert();
}}
>
Decline
</button>
<button
style={{
background: "#188ae2",
}}
type="button"
className="finishBtn sendHover"
onClick={() => {
embedImages();
}}
>
Finish
</button>
</>
)}
</div>
)
) : (
<div>
<button
onClick={() => {
navigate(-1);
}}
type="button"
className="defaultBtn backBtn"
>
Back
</button>
<button
style={{
background: "#188ae2",
}}
type="button"
className="finishBtn sendHover"
onClick={() => {
if (!pdfUrl) {
embedImages();
}
}}
>
Finish
</button>
</div>
)}
</div>
{isMobile && isShowHeader && (
<div
id="navbar"
className="stickyHead"
style={{ width: window.innerWidth - 30 + "px" }}
>
<div className="preBtn2">
<div
onClick={() => {
navigate(-1);
}}
>
<i
className="fa fa-arrow-left"
aria-hidden="true"
style={{ color: themeColor(), cursor: "pointer" }}
></i>
</div>
<div>
<i
onClick={() => {
if (pageNumber > 1) {
previousPage();
}
}}
className="fa fa-backward"
style={{ color: "gray", cursor: "pointer" }}
></i>
<span
style={{
fontSize: "13px",
fontWeight: "600",
marginLeft: "10px",
marginRight: "10px",
}}
>
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
</span>
<i
onClick={() => {
if (pageNumber < allPages) {
nextPage();
}
}}
className="fa fa-forward"
style={{ color: "gray", cursor: "pointer" }}
></i>
</div>
{pdfUrl ? (
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<div
// onClick={() => handleDownloadPdf()}
style={{
color: themeColor(),
border: "none",
fontWeight: "650",
fontSize: "16px",
}}
>
<i class="fa fa-ellipsis-v" aria-hidden="true"></i>
</div>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
<DropdownMenu.Content
className="DropdownMenuContent"
sideOffset={5}
>
<DropdownMenu.Item
className="DropdownMenuItem"
onClick={() => handleDownloadPdf()}
>
<div
style={{
display: "flex",
flexDirection: "row",
}}
>
<i class="fa fa-arrow-down" aria-hidden="true" style={{marginRight:"2px"}}></i>
Download
</div>
</DropdownMenu.Item>
<DropdownMenu.Item className="DropdownMenuItem">
<PDFDownloadLink
document={<Certificate pdfData={pdfDetails} />}
fileName={`completion certificate-${
pdfDetails[0] && pdfDetails[0].Name
}.pdf`}
>
{({ blob, url, loading, error }) =>
<>
{console.log("error",error)}
{loading ? (
"Loading document..."
) : (
<div
style={{
display: "flex",
flexDirection: "row",
}}
>
<i
class="fa fa-certificate"
style={{
fontSize: "15px",
marginRight: "3px",
}}
aria-hidden="true"
></i>
Certificate
</div>
)}
</>
}
</PDFDownloadLink>
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
) : (
<div style={{ display: "flex", justifyContent: "space-around" }}>
{/* current signer is checking user send request and check status of pdf sign than if current
user exist than show finish button else no
*/}
{currentSigner && (
<>
{decline && (
<div
onClick={() => {
handleDeclinePdfAlert();
}}
style={{
color: "red",
border: "none",
fontWeight: "650",
fontSize: "16px",
marginRight: "10px",
}}
>
Decline
</div>
)}
{isPlaceholder ?(
<div
onClick={() => {
alertSendEmail();
}}
style={{
color: themeColor(),
border: "none",
fontWeight: "650",
fontSize: "16px",
}}
>
Send
</div>
):(
<div
onClick={() => {
if (!pdfUrl) {
embedImages();
}
}}
style={{
color: themeColor(),
border: "none",
fontWeight: "650",
fontSize: "16px",
}}
>
Finish
</div>
)}
</>
)}
</div>
)}
</div>
</div>
)}
</div>
);
}
export default Header;
@@ -0,0 +1,28 @@
import React from 'react'
import loader from "../../assests/loader2.gif";
function Loader({isLoading}) {
return (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
flexDirection: "column",
}}
>
<img
alt="no img"
src={loader}
style={{ width: "80px", height: "80px" }}
/>
<span style={{ fontSize: "13px", color: "gray" }}>
{isLoading.message}
</span>
</div>
)
}
export default Loader
@@ -0,0 +1,28 @@
import React from "react";
import Modal from "react-bootstrap/Modal";
import ModalHeader from "react-bootstrap/esm/ModalHeader";
function ModalComponent({ isShow, type }) {
return (
<Modal show={isShow}>
<ModalHeader className="bg-danger" style={{ color: "white" }}>
{type === "pdfFail" ? (
<span>Failed to load pdf!</span>
) : (
<span>Document Expired!</span>
)}
</ModalHeader>
<Modal.Body>
{type === "pdfFail" ? (
<p>Something went wrong failed to load pdf file!</p>
) : (
<p>This Document is no longer available.</p>
)}
</Modal.Body>
</Modal>
);
}
export default ModalComponent;
@@ -0,0 +1,58 @@
import React from "react";
function PrevNext({ pageNumber, allPages, changePage }) {
//for go to previous page
function previousPage() {
changePage(-1);
}
//for go to next page
function nextPage() {
changePage(1);
}
return (
<div>
<div className="preBtn1">
<button
style={{
padding: "3px 20px ",
fontSize: "10px",
background: "#d3edeb",
fontWeight: "600",
border: "0px",
marginRight: "5px",
}}
disabled={pageNumber <= 1}
onClick={previousPage}
>
Prev
</button>
<span
style={{
fontSize: "13px",
fontWeight: "600",
}}
>
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
</span>
<button
style={{
padding: "3px 20px ",
fontSize: "10px",
background: "#d3edeb",
fontWeight: "600",
marginLeft: "5px",
border: "0px",
}}
disabled={pageNumber >= allPages}
onClick={nextPage}
>
Next
</button>
</div>
</div>
);
}
export default PrevNext;
@@ -0,0 +1,96 @@
import React from "react";
import RSC from "react-scrollbars-custom";
import { Document, Page, pdfjs } from "react-pdf";
import { themeColor } from "../../utils/ThemeColor/backColor";
function RenderAllPdfPage({
pdfUrl,
signPdfUrl,
allPages,
setAllPages,
setPageNumber,
setSignBtnPosition,
}) {
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
//set all number of pages after load pdf
function onDocumentLoad({ numPages }) {
setAllPages(numPages);
}
return (
<div className="showPages">
<div
style={{
display: "flex",
flexDirection: "row",
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
backgroundColor: "white",
height:"100%"
}}
>
<div style={{ width: "140px" }}>
<div
style={{
background: themeColor(),
// color:"white"
}}
className="signedStyle"
>
Pages
</div>
<div>
<RSC id="RSC-Example" style={{width:"135px",height:window.innerHeight-130+'px'}} >
<Document
onLoadSuccess={onDocumentLoad}
file={pdfUrl ? pdfUrl : signPdfUrl}
// file="https://api.printnode.com/static/test/pdf/multipage.pdf"
>
{Array.from(new Array(allPages), (el, index) => (
<div
key={index}
style={{
width: "100px",
border: "2px solid #878787",
// padding: "5px",
margin: "10px",
display: "flex",
justifyContent: "center",
alignItems: "center",
contain: "content",
}}
onClick={() => {
setPageNumber(index + 1);
if (setSignBtnPosition) {
setSignBtnPosition([]);
}
}}
>
<Page
key={`page_${index + 1}`}
pageNumber={index + 1}
width={100}
height={100}
scale={1}
renderAnnotationLayer={false}
renderTextLayer={false}
/>
</div>
))}
</Document>
</RSC>
</div>
<hr />
</div>
</div>
</div>
);
}
export default RenderAllPdfPage;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,476 @@
import React from "react";
import { useRef, useState } from "react";
import SignatureCanvas from "react-signature-canvas";
import redPen from "../../assests/redPen.png";
import bluePen from "../../assests/bluePen.png";
import blackPen from "../../assests/blackPen.png";
import Modal from "react-bootstrap/Modal";
import { themeColor } from "../../utils/ThemeColor/backColor";
import { useEffect } from "react";
function SignPad({
isSignPad,
isStamp,
setIsImageSelect,
onSaveSign,
setIsSignPad,
setImage,
isImageSelect,
imageRef,
onImageChange,
onSaveImage,
image,
defaultSign,
setSignature,
}) {
const [penColor, setPenColor] = useState("blue");
const allColor = [bluePen, redPen, blackPen];
const canvasRef = useRef(null);
const [isDefaultSign, setIsDefaultSign] = useState(false);
const [isTab, setIsTab] = useState("signature");
const [isSignImg, setIsSignImg] = useState("");
//function for clear signature
const handleClear = () => {
if (canvasRef.current) {
canvasRef.current.clear();
}
setIsSignImg("");
};
//function for set signature url
const handleSignatureChange = (dataURL) => {
// canvasRef.current.backgroundColor = 'rgb(165, 26, 26)'
setSignature(canvasRef.current.toDataURL());
setIsSignImg(canvasRef.current.toDataURL());
};
//save button component
const SaveBtn = () => {
// console.log("isSign",isSignImg,image)
return (
<div>
{!isStamp && !isImageSelect && (
<button
style={{
color: "black",
}}
type="button"
className="finishBtn saveBtn"
onClick={() => handleClear()}
>
Clear
</button>
)}
<button
onClick={() => {
if (!image) {
if (isDefaultSign) {
setIsSignImg("");
onSaveSign(isDefaultSign);
} else {
setIsSignImg("");
onSaveSign();
}
setPenColor("blue");
} else {
setIsSignImg("");
onSaveImage();
}
setIsSignPad(false);
setIsImageSelect(false);
setIsDefaultSign(false);
setImage();
setIsTab("signature");
}}
style={{
background: themeColor(),
color: "white",
}}
disabled={isSignImg || image || isDefaultSign ? false : true}
type="button"
className={
isSignImg || image ? "finishBtn saveBtn" : "disabledFinish saveBtn"
}
>
Save
</button>
</div>
);
};
useEffect(() => {
// Load the default signature after the component mounts
if (canvasRef.current) {
canvasRef.current.fromDataURL(isSignImg);
}
}, [isTab]);
return (
<div>
{/*isSignPad */}
<Modal show={isSignPad}>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
background: "white",
borderBottom: "1.6px solid #ebe6e6",
marginTop: "15px",
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-around",
alignItems: "end",
gap: 10,
// background: themeColor(),
}}
>
{isStamp ? (
<span style={{ color: themeColor() }} className="signTab">
Upload Image
</span>
) : (
<>
<div>
<span
onClick={() => {
setIsDefaultSign(false);
setIsImageSelect(false);
setIsTab("signature");
setImage();
}}
style={{
color: isTab === "signature" ? themeColor() : "#515252",
marginLeft: "2px",
}}
className="signTab"
>
Signature
</span>
<div
style={{
border:
isTab === "signature"
? "1.5px solid #108783"
: "1.5px solid #ffffff",
}}
></div>
</div>
<div>
<span
onClick={() => {
setIsDefaultSign(false);
setIsImageSelect(true);
setIsTab("uploadImage");
}}
style={{
color: isTab === "uploadImage" ? themeColor() : "#515252",
}}
className="signTab"
>
Upload Image
</span>
<div
style={{
border:
isTab === "uploadImage"
? "1.5px solid #108783"
: "1.5px solid #ffffff",
}}
></div>
</div>
{defaultSign && (
<div>
<span
onClick={() => {
setIsDefaultSign(true);
setIsImageSelect(true);
setIsTab("mysignature");
setImage();
}}
style={{
color:
isTab === "mysignature" ? themeColor() : "#515252",
}}
className="signTab"
>
My Signature
</span>
<div
style={{
border:
isTab === "mysignature"
? "1.5px solid #108783"
: "1.5px solid #ffffff",
}}
></div>
</div>
)}
</>
)}
</div>
<button
style={{
border: "0px",
background: "none",
paddingLeft: "7px",
paddingRight: "7px",
marginRight: "5px",
}}
onClick={() => {
setPenColor("blue");
setIsSignPad(false);
setIsImageSelect(false);
setIsDefaultSign(false);
setImage();
setIsTab("signature");
}}
>
X
</button>
</div>
{/* signature modal */}
<Modal.Body className="modalBody">
{isDefaultSign ? (
<>
<div
style={{
border: "1px solid black",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
marginBottom: 6,
cursor: "pointer",
// background:'rgb(255, 255, 255)'
}}
className="signatureCanvas"
>
<img
alt="stamp img"
style={{
width: "100%",
height: "100%",
background: "rgb(255, 255, 255)",
objectFit: "contain",
}}
src={defaultSign}
/>
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<SaveBtn />
</div>
</>
) : isImageSelect || isStamp ? (
!image ? (
<div
style={{
border: "1px solid black",
display: "flex",
flexDirection: "column",
justifyContent: "center",
alignItems: "center",
marginBottom: 6,
cursor: "pointer",
}}
className="signatureCanvas"
onClick={() => imageRef.current.click()}
>
<input
type="file"
onChange={onImageChange}
className="filetype"
accept="image/*"
ref={imageRef}
hidden
// style={{ display: "none" }}
/>
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
<div className="uploadImg">Upload</div>
</div>
) : (
<>
<div
style={{
// position: "relative",
border: "1px solid black",
marginBottom: 6,
// justifyContent:"center"
overflow: "hidden",
}}
className="signatureCanvas"
>
<img
alt="print img"
ref={imageRef}
// alt="preview image"
src={image.src}
style={{
//overflow:"hidden",
objectFit: "contain",
}}
/>
</div>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<SaveBtn />
</div>
</>
)
) : (
<>
{/* {isSignImg ? (
<div
style={{
position: "relative",
border: "2px solid #888",
marginBottom: 6,
}}
className="signatureCanvas"
>
<img
alt="preview image"
src={isSignImg}
style={{
width: "100%",
height: "100%",
objectFit: "contain",
}}
/>
</div>
) : ( */}
<SignatureCanvas
ref={canvasRef}
penColor={penColor}
canvasProps={{
// width: "460px",
// height: "184px",
// width:"280px",
// height:"112px",
className: "signatureCanvas",
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleSignatureChange(canvasRef.current.toDataURL())
}
dotSize={1}
/>
{/* )} */}
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
marginTop:"4px"
}}
>
<div style={{display:"flex",flexDirection:"row"}}>
{allColor.map((data, key) => {
return (
<img
key={key}
alt="pen img"
style={{
border: "none",
margin: "5px",
borderBottom:
key === 0 && penColor === "blue"
? "2px solid blue"
: key === 1 && penColor === "red"
? "2px solid red"
: key === 2 && penColor === "black"
? "2px solid black"
: "2px solid white",
}}
onClick={() => {
if (key === 0) {
setPenColor("blue");
} else if (key === 1) {
setPenColor("red");
} else if (key === 2) {
setPenColor("black");
}
}}
src={data}
width={20}
height={20}
/>
// </button>
);
})}
</div>
<SaveBtn />
</div>
</>
)}
</Modal.Body>
{/* <Modal.Footer>
{!isStamp && !isImageSelect && (
<button
style={{
color: "black",
}}
type="button"
className="finishBtn"
onClick={() => handleClear()}
>
Clear
</button>
)}
<button
onClick={() => {
if (!image) {
if (isDefaultSign) {
onSaveSign(isDefaultSign);
} else {
onSaveSign();
}
setPenColor("blue");
} else {
onSaveImage();
}
setIsSignPad(false);
setIsImageSelect(false);
setIsDefaultSign(false);
setImage();
}}
style={{
background: themeColor(),
color: "white",
}}
type="button"
className="finishBtn"
>
Save
</button>
</Modal.Footer> */}
</Modal>
</div>
);
}
export default SignPad;
@@ -0,0 +1,68 @@
import React from "react";
import { themeColor } from "../../utils/ThemeColor/backColor";
import "../../css/signature.css";
function Signedby({ pdfDetails }) {
const getFirstLetter = (name) => {
const firstLetter = name.charAt(0);
return firstLetter;
};
return (
<div className="signerComponent">
<div
style={{
background: themeColor(),
// color:"white"
}}
className="signedStyle"
>
Signed By
</div>
<div style={{ marginTop: "2px" }}>
<div
style={{
display: "flex",
flexDirection: "row",
padding: "10px",
background: "#93a3db",
}}
>
<div
className="signerStyle"
style={{
background: "#abd1d0",
width: 20,
height: 20,
display: "flex",
borderRadius: 30 / 2,
justifyContent: "center",
alignItems: "center",
marginRight: "20px",
marginTop: "5px",
}}
>
<span
style={{
fontSize: "8px",
textAlign: "center",
fontWeight: "bold",
}}
>
{" "}
{getFirstLetter(pdfDetails.ExtUserPtr.Name)}
</span>
</div>
<div style={{ display: "flex", flexDirection: "column" }}>
<span className="userName">{pdfDetails.ExtUserPtr.Name}</span>
<span className="useEmail">{pdfDetails.ExtUserPtr.Email}</span>
</div>
</div>
</div>
</div>
);
}
export default Signedby;
@@ -0,0 +1,163 @@
import React, { useState } from "react";
import check from "../../assests/checkBox.png";
import { themeColor } from "../../utils/ThemeColor/backColor";
function SignerListPlace({
signerPos,
signersdata,
isSelectListId,
setSignerObjId,
setIsSelectId,
setContractName
}) {
const color = [
"#93a3db",
"#e6c3db",
"#c0e3bc",
"#bce3db",
"#b8ccdb",
"#ceb8db",
"#ffccff",
"#99ffcc",
"#cc99ff",
"#ffcc99",
"#66ccff",
"#ffffcc",
];
const nameColor = [
"#304fbf",
"#7d5270",
"#5f825b",
"#578077",
"#576e80",
"#6d527d",
"#cc00cc",
"#006666",
"#cc00ff",
"#ff9900",
"#336699",
"#cc9900",
];
const [isHover, setIsHover] = useState();
//function for onhover signer name change background color
const onHoverStyle = (ind) => {
const style = {
background: color[ind % color.length],
padding: "10px",
marginTop: "2px",
display: "flex",
flexDirection: "row",
borderBottom: "1px solid #e3e1e1",
};
return style;
};
//function for onhover signer name remove background color
const nonHoverStyle = (ind) => {
const style = {
// width:"250px",
padding: "10px",
marginTop: "2px",
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
};
return style;
};
const getFirstLetter = (name) => {
const firstLetter = name.charAt(0);
return firstLetter;
};
return (
<div >
<div
style={{
background: themeColor(),
padding: "5px",
}}
>
<span className="signedStyle">Reicipents</span>
</div>
<div className="signerList">
{signersdata.Signers &&
signersdata.Signers.map((obj, ind) => {
return (
<div
data-tut="reactourFirst"
onMouseEnter={() => setIsHover(ind)}
onMouseLeave={() => setIsHover(null)}
key={ind}
style={
isHover === ind || isSelectListId === ind
? onHoverStyle(ind)
: nonHoverStyle(ind)
}
onClick={() => {
setSignerObjId(obj.objectId);
setIsSelectId(ind);
setContractName(obj.className)
}}
>
<div
style={{
display: "flex",
flexDirection: "row",
}}
>
<div
className="signerStyle"
style={{
background: nameColor[ind % nameColor.length],
width: 20,
height: 20,
display: "flex",
borderRadius: 30 / 2,
justifyContent: "center",
alignItems: "center",
marginRight: "20px",
marginTop: "5px",
}}
>
<span
style={{
fontSize: "8px",
textAlign: "center",
fontWeight: "bold",
}}
>
{" "}
{getFirstLetter(obj.Name)}
</span>
</div>
<div style={{ display: "flex", flexDirection: "column" }}>
<span className="userName">{obj.Name}</span>
<span className="useEmail">{obj.Email}</span>
</div>
</div>
{signerPos.map((data, key) => {
return (
data.signerObjId === obj.objectId && (
<div key={key}>
<img alt="no img" src={check} width={20} height={20} />
</div>
)
);
})}
<hr />
</div>
);
})}
</div>
</div>
);
}
export default SignerListPlace;
@@ -0,0 +1,310 @@
import React, { useState } from "react";
import signLogo from "../assests/mailLogo.png";
import "../css/LoginPage.css";
import loader from "../assests/loader2.gif";
import axios from "axios";
import { useParams } from "react-router-dom";
import { themeColor } from "../utils/ThemeColor/backColor";
import { useEffect } from "react";
import { useNavigate } from "react-router-dom";
// import { useHistory } from "react-router-dom/cjs/react-router-dom.min";
function Login() {
const { id, userMail, serverUrl,serverId } = useParams();
let navigate = useNavigate();
// const history = useHistory();
const [email, setEmail] = useState(userMail);
const [OTP, setOTP] = useState("");
const [EnterOTP, setEnterOtp] = useState(false);
const [loading, setLoading] = useState(false);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
handleServerUrl();
}, []);
//https://qik-ai-org.github.io/Sign-MicroappV2/#/login/LqgGeZHd17/raktima.c@qik.ai/https:%2F%2Fserver3.qik.ai%2Fdefaultssty%2F&defaultssty&contracts
// login/LqgGeZHd17/raktima.c@qik.ai/https:%2F%2Fserver3.qik.ai%2Fdefaultssty&defaultssty&contracts
//function generate serverUrl and parseAppId from url and save it in local storage
const handleServerUrl = () => {
// console.log("params", serverUrl);
//split url in array from '&'
localStorage.clear();
const checkSplit = serverUrl.split("&");
const server = checkSplit[0];
const parseId = checkSplit[1];
const appName = checkSplit[2];
// console.log("appName", appName);
const newServer = server.replaceAll("%2F", "/");
localStorage.setItem("baseUrl", newServer);
localStorage.setItem("parseAppId", parseId);
localStorage.setItem("_appName", appName);
setIsLoading(false);
// console.log("checkSPlit", newServer, parseId, appName);
};
const handleChange = (event) => {
const { value } = event.target;
setOTP(value);
};
//send email OTP function
const SendOtp = async (e) => {
const serverUrl =
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
const parseId =
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
// console.log("server",serverUrl)
if (serverUrl && localStorage) {
setLoading(true);
e.preventDefault();
setEmail(email);
try {
// const { baseUrl, parseAppId, mobile } = this.state;
let url = `${serverUrl}functions/SendOTPMailV1/`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseId,
};
let body = {
email: email.toString(),
// appId: {
// __type: "Pointer",
// className: "w_appinfo",
// objectId: localStorage.getItem("_app_objectId"),
// },
};
let Otp = await axios.post(url, body, { headers: headers });
if (Otp) {
setLoading(false);
setEnterOtp(true);
}
} catch (error) {
// this.setState({ loading: false });
}
} else {
alert("something went wrong!");
}
};
//verify OTP send on via email
const VerifyOTP = async (e) => {
e.preventDefault();
const serverUrl =
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
const parseId =
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
if (OTP) {
setLoading(true);
try {
// AuthLoginAs
let url = `${serverUrl}functions/AuthLoginAsMail/`;
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseId,
};
let body = {
email: email,
// email,
otp: OTP,
};
let user = await axios.post(url, body, { headers: headers });
// console.log("user", user.data.result);
if (user.data.result === "Invalid Otp") {
alert("Invalid Otp");
setLoading(false);
}else if(user.data.result === "user not found!"){
alert("User not found!");
setLoading(false);
}
else {
let _user = user.data.result;
localStorage.setItem("UserInformation", JSON.stringify(_user));
// localStorage.setItem("userEmail", email);
localStorage.setItem("username", _user.name);
// console.log("session token", _user.sessionToken);
localStorage.setItem("accesstoken", _user.sessionToken);
setLoading(false);
//navigate user to on signature page
// history.push(`/recipientSignPdf/${id}/${_user.phone}`);
navigate(`/recipientSignPdf/${id}/${_user.phone}`);
}
} catch (error) {}
} else {
alert("Please Enter OTP!");
}
};
return (
<React.Fragment>
{isLoading ? (
<div
style={{
display: "flex",
justifyContent: "center",
alignItems: "center",
height: "100vh",
flexDirection: "column",
}}
>
<img
alt="no img"
src={loader}
style={{ width: "80px", height: "80px" }}
/>
<span style={{ fontSize: "13px", color: "gray" }}>
{isLoading.message}
</span>
</div>
) : (
<div
style={{
margin: "10px",
border: "0.5px solid #c5c7c9",
padding: "30px",
boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px",
// box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
}}
>
<div className="main_head">
<div className="main-logo">
<img alt="sign img" src="https://qikinnovation.ams3.digitaloceanspaces.com/logo.png" width="100%" />
</div>
</div>
{!EnterOTP ? (
<form>
<div className="row">
<div className="col-sm-6 KLO">
<h2>Welcome Back !</h2>
<span className="KNLO">
Verification code is sent to your email
</span>
<div className="card card-box">
<div className="card-body">
<input
type="email"
className="form-control"
name="mobile"
value={email}
disabled
height={30}
style={{ fontSize: "20px", fontWeight: "600" }}
/>
<br />
</div>
</div>
<div
className="col-md-4 col-sm-4"
style={{
textAlign: "center",
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
{loading ? (
<button
className="btn btn-info loadinBtn "
type="button"
style={{ marginBottom: "4px", width: "210px" }}
disabled
>
<span
className="spinner-border spinner-border-sm "
role="status"
aria-hidden="true"
></span>
Loading...
</button>
) : (
<button
className="btn btn-sm otpButton"
onClick={(e) => SendOtp(e)}
style={{
marginBottom: "4px",
width: "210px",
background: themeColor(),
color: "white",
fontWeight: "600",
}}
>
Send OTP
</button>
)}
</div>
</div>
</div>
</form>
) : (
<form>
<div className="row">
<div className="col-sm-6 KLO">
<h2>Welcome Back !</h2>
<span className="KNLO">You will get a OTP via Email</span>
<div className="card card-box">
<div className="card-body">
<label>Enter Verification Code</label>
<input
type="number"
className="form-control"
name="OTP"
value={OTP}
min="4"
max="4"
onChange={handleChange}
/>
<br />
</div>
</div>
<div
className="col-md-4 col-sm-4"
style={{ textAlign: "center" }}
>
{loading ? (
<button
className="btn btn-info "
type="button"
style={{ marginBottom: "4px", width: "210px" }}
disabled
>
<span
className="spinner-border spinner-border-sm "
role="status"
aria-hidden="true"
></span>
Loading...
</button>
) : (
<button
type="button"
onClick={(e) => VerifyOTP(e)}
className="btn btn-info login-btn"
>
Verify
</button>
)}
</div>
</div>
</div>
</form>
)}
</div>
)}
</React.Fragment>
);
}
export default Login;
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,49 @@
import React from "react";
import { Routes, Route } from "react-router-dom";
import SignYourselfPdf from "./Component/SignYourselfPdf";
import RecipientSignPdf from "./Component/recipientSignPdf";
import PlaceHolderSign from "./Component/placeHolderSign";
import ManageSign from "./Component/ManageSign";
import Login from "./Component/login";
import DraftDocument from "./Component/DraftDocument";
import PdfRequestFiles from "./Component/PdfRequestFiles";
import LegaDrive from "./Component/LegaDrive/LegaDrive";
// `AppRoutes` is used to define route path of app and
// it expose to host app, check moduleFederation.config.js for more
function AppRoutes() {
return (
<div>
<Routes>
{/* TODO: Check with images and other assets */}
<Route index element={<div>Microapp Home page route </div>} />
{/* signyouself route with rowlevel data */}
<Route path="/signaturePdf" element={<SignYourselfPdf />} />
{/* signyouself route with no rowlevel data using docId from url */}
<Route path="/signaturePdf/:docId" element={<SignYourselfPdf />} />
{/* recipient signature route with no rowlevel data using docId from url */}
<Route
path="/recipientSignPdf/:id/:userPhone"
element={<RecipientSignPdf />}
/>
{/* recipient placeholder set route with rowlevel data */}
<Route path="/placeHolderSign" element={<PlaceHolderSign />} />{" "}
{/* recipient placeholder set route with no rowlevel data using docId from url*/}
<Route path="/placeHolderSign/:docId" element={<PlaceHolderSign />} />
{/*Add default signature of user route */}
<Route path="/managesign" element={<ManageSign />} />
{/* login page route */}
<Route path="/login/:id/:userMail/:serverUrl" element={<Login />} />
{/* draft document route to handle and navigate route page accordiing to document status */}
<Route path="/draftDocument" element={<DraftDocument />} />
{/* for user signature (need your sign route) with row level data */}
<Route path="/pdfRequestFiles" element={<PdfRequestFiles />} />
{/* for user signature (need your sign route) with no row level data */}
<Route path="/pdfRequestFiles/:docId" element={<PdfRequestFiles />} />
{/* lega drive route */}
<Route path="/legadrive" element={<LegaDrive />} />
</Routes>
</div>
);
}
export default AppRoutes;
Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 574 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 259 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 569 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 804 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

+7
View File
@@ -0,0 +1,7 @@
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
@@ -0,0 +1,151 @@
.react-tel-input .form-control {
width: 100%;
height: 45px;
margin-top: 4px;
}
.fakeimg {
height: 200px;
background: #aaa;
}
.GTRY {
border: 1px solid #dee2e6;
margin-top: 75px;
padding-bottom: 20px;
background-color: #fff;
}
.main_head {
width: 100%;
height: 66px;
background-color: #fff;
margin-bottom: 52px;
padding-top: 10px;
}
.main-logo {
width: 250px;
height: 66px;
display: inline-block;
}
.card-box {
background: #fff;
min-height: 50px;
box-shadow: 0 20px 20px rgba(0, 0, 0, 0.1);
position: relative;
margin-bottom: 20px;
transition: 0.5s;
border: 1px solid #f2f2f2;
border-radius: 7px;
margin-top: 10px;
}
.LKJH {
display: flex;
}
.GTR {
text-align: left;
}
.JUI {
text-align: right;
}
.btn-info {
color: #fff;
background-color: #15b4e9;
border-color: #15b4e9;
}
.btn-info:hover {
color: #fff;
background-color: #15b4e9;
border-color: #15b4e9;
}
.btn-reg {
color: #15b4e9;
background-color: #ffffff;
border-color: #15b4e9;
}
.btn-reg:hover {
color: #15b4e9;
background-color: #ffffff;
border-color: #15b4e9;
}
.SYTU {
display: flex;
}
.MLKI {
float: right;
margin-bottom: 12px;
}
.login-btn {
width: 100% !important;
display: block !important;
}
@media only screen and (max-width: 667px) {
.MLKI {
float: inherit;
}
.login-btn {
width: 210px !important;
}
}
.MLKI a {
color: #212529;
}
.KNLO {
color: #878787;
}
.form-check-label {
margin-left: 17px;
margin-bottom: 12px;
}
input:focus {
border-color: #ccc !important;
}
@media only screen and (max-width: 600px) {
.KLO1 {
display: none;
}
.MLKI a {
font-size: 12px;
}
.form-check-label {
font-size: 12px;
margin-bottom: 14px;
}
.MKUY {
text-align: center;
padding-top: 10px;
}
.main_head {
margin-bottom: 12px;
padding-top: 10px;
border-bottom: 1px dashed #eeeeee;
}
}
@@ -0,0 +1,225 @@
.mainDiv {
position: relative;
}
.successBtn {
background: #3ac9d6;
border: 1px solid #3ac9d6;
}
.warning {
position: absolute;
padding: 8px;
border: 1px solid black;
background: white;
width: 300px;
border-radius: 5px;
animation: inAnimation 2s ease-in-out;
z-index: 1;
}
.nameWarning {
position: absolute;
bottom: -70px;
left: 10px;
}
.nameWarning::before {
content: '';
width: 0px;
height: 0px;
border-style: outset;
border-width: 0px 10px 10px 10px;
border-color: transparent transparent black transparent;
display: inline-block;
position: absolute;
top: -29%;
left: 0;
right: 75%;
margin: 0 auto;
}
.signWarning {
bottom: 70px;
left: 50px;
}
.signWarning::before {
content: '';
width: 0px;
height: 0px;
border-style: outset;
border-width: 0px 10px 10px 10px;
border-color: transparent transparent black transparent;
display: inline-block;
position: absolute;
top: -29%;
left: 0;
right: 75%;
margin: 0 auto;
}
.successBox {
z-index: 1;
position: absolute;
top: 5%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 13px;
animation: inAnimation 2s ease-in-out;
}
@keyframes inAnimation {
0% {
opacity: 0;
visibility: hidden;
}
25% {
opacity: 1;
visibility: visible;
}
50% {
opacity: 1;
visibility: visible;
}
75% {
opacity: 1;
visibility: visible;
}
100% {
opacity: 0;
visibility: hidden;
}
}
.signature {
color: white;
cursor: pointer;
padding: 10px 14px 10px;
background: #15b4e9;
font-size: 12px;
font-weight: 600;
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
}
.signature:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
background: #13a8da;
color: white;
}
.imgupload {
color: white;
cursor: pointer;
padding: 10px 14px 10px;
background: #15b4e9;
font-size: 12px;
font-weight: 600;
border-radius: 2px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
min-width: 105px;
}
.imgupload:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
background: #13a8da;
color: white;
}
.loaderContainer {
position: fixed;
inset: 0%;
width: 100%;
height: 100svh;
background: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7));
display: flex;
align-items: center;
justify-content: center;
}
.loader {
width: 70px;
height: 70px;
border-top: 4px solid #1b8ef4;
border-left: 4px solid #1b8ef4;
border-radius: 80%;
animation: spin 0.5s linear infinite;
}
@keyframes spin {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
.customBtn {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
padding: 10px 14px 10px;
color: white;
font-weight: 600;
font-size: 12px;
text-transform: uppercase;
border-radius: 2px;
margin-left: 10px;
width: 100px;
}
.clearbtn {
font-size: 15px;
}
.clearbtn:hover {
text-decoration: underline;
text-underline-offset: 2px;
color: blue;
}
.successBtn:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
background: #1ab6ce;
color: white;
}
.resetBtn {
background: #188ae2;
margin-left: 10;
border: 1px solid #188ae2;
}
.resetBtn:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
background: #177ecd;
color: white;
}
.signBlock {
display: flex;
flex-direction: row;
gap: 12px;
}
.signInputManage{
width: 50%;
}
@media (max-width: 815px) {
.signBlock {
display: flex;
flex-direction: column;
}
.signInputManage{
width: 100%;
}
}
@@ -0,0 +1,723 @@
/* html, body {margin: 0; height: 100%; overflow: hidden} */
/* #04b565 */
/* div {
margin: 0px;
font-family:system-ui;
} */
.signatureCanvas {
border: 2px solid #888;
background-color: rgb(255, 255, 255);
width: 460px;
height: 184px;
}
.penContainer{
width: 460px;
}
.signatureBtn {
border: 1.5px solid #47a3ad;
margin-bottom: 10px;
border-radius: 3px;
display: flex;
padding: 0px;
justify-content: space-between;
background: white;
transition-duration: 0.4s;
cursor: all-scroll;
width: 150px;
height: 30px;
color: black;
/* transform: translate(); */
}
/* .signatureBtn:hover {
background-color:#47a3ad;
color: white;
} */
.disableSign {
border: none;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
margin-bottom: 10px;
border-radius: 3px;
display: flex;
padding: 0px;
justify-content: space-between;
background: #d3edeb;
transition-duration: 0.4s;
cursor: pointer;
color: white;
font-weight: 600;
}
.emailInput {
padding: 10px;
border: 1.5px solid gray;
border-radius: 4px;
width: 100%;
font-size: 15px;
padding-bottom: 20px;
}
.emailInput:focus {
outline: none;
border: 1.5px solid #47a3ad;
}
.addEmail {
padding: "0px";
border: 1.5px solid #47a3ad;
border-radius: 4px;
width: 100%;
font-size: 15px;
}
.addEmail,
.emailInput {
outline: none;
}
.addEmailInput{
border: none;
outline: none;
}
.emailChip {
background-color: #47a3ad;
margin: 4px;
border-radius: 10px;
padding: 5px 10px;
}
.addEmailInput {
padding: 10px;
border-radius: 4px;
width: 100%;
font-size: 15px;
}
.addEmailInput:focus {
outline: none;
border: none;
}
.finishBtn {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
padding: 3px 30px;
color: white;
font-weight: 500 !important;
font-size: 14px !important;
border: none;
margin-left: 10px;
}
.finishBtn:focus {
border: none;
outline: none;
}
.finishBtn:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
color: white;
}
.saveBtn {
padding: 3px 18px !important;
}
.disabledFinish {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
padding: 3px 30px;
color: white;
font-weight: 600;
font-size: 14px;
border: none;
margin-left: 10px;
}
.sendHover:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
color: white;
}
.defaultSignBox {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
width: 180px;
height: 111px;
padding: 8px 20px;
color: white;
font-weight: 600;
font-size: 14px;
border: none;
border-radius: 2px;
margin-left: 10px;
}
.defaultBtn {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
padding: 3px 26px;
color: black;
font-weight: 500;
font-size: 14px;
border: 1px solid gray;
border-radius: 2px;
margin-left: 10px;
}
.backBtn {
background-color: white;
}
.backBtn:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
}
.defaultBtn:focus {
border: none;
outline: none;
}
.downloadBtn {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
padding: 3px 15px !important;
background-color: rgb(241 79 79);
border: none !important;
color: white !important;
}
.downloadBtn:hover {
box-shadow: 0 2px 4px rgba(154, 36, 36, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
}
.printBtn {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
padding: 3px 15px !important;
background: #188ae2;
border: none !important;
color: white !important;
}
.printBtn:hover {
box-shadow: 0 2px 4px rgba(23, 48, 137, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
}
.certificateBtn {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
padding: 3px 15px !important;
background: #08bc66;
border: none !important;
color: white !important;
}
.certificateBtn:hover {
box-shadow: 0 2px 4px rgba(15, 150, 87, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
}
.signerList {
overflow-y: scroll;
max-height: 180px;
}
.signerList::-webkit-scrollbar {
display: none;
/* for Chrome, Safari, and Opera */
}
.showScroll {
height: 100%;
overflow: scroll;
}
.showScroll::-webkit-scrollbar {
display: none;
/* for Chrome, Safari, and Opera */
}
.hideScroll {
height: 100%;
overflow: scroll;
}
.signedStyle {
color: white;
padding: 5px;
font-family: sans-serif;
font-size: 15px !important;
}
.userName {
font-size: 12px !important;
font-weight: bold !important;
color: #424242 !important;
width: 100px;
white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis;
}
.useEmail {
font-size: 10px;
color: #424242;
font-weight: 500;
width: 100px;
white-space: nowrap;
overflow: hidden !important;
text-overflow: ellipsis;
}
.spanTagHead {
color: white !important;
font-size: 17px;
font-weight: 500;
}
.pTagBody {
font-size: 15px !important;
}
.signTab {
cursor: pointer !important;
font-weight: 400 !important;
margin-left: 10px !important;
font-size: 15px !important;
}
.draggable-button {
padding: 10px 20px;
background: #3498db;
color: #fff;
border: none;
cursor: grab;
transition: transform 0.2s;
}
.draggable-button.dragging {
opacity: 0.5;
/* Reduce opacity while dragging */
transform: scale(1.1);
/* Apply a scaling effect while dragging */
}
.signatureContainer {
display: flex;
flex-direction: row;
justify-content: space-between;
background-color: #ebebeb;
/* max-height: 800px; */
/* overflow: auto; */
}
.signatureHeader {
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
margin-top: 5px;
}
.signerComponent {
/* box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; */
width: 180px;
background-color: white;
height: 100%;
}
.modalBody {
padding: 1rem !important;
padding-top: 2rem !important;
}
.signLayoutContainer1 {
padding: 30px;
display: flex;
flex-direction: column;
align-items: center
}
.signLayoutContainer2 {
display: none;
}
.preBtn1 {
display: flex;
align-items: center;
}
.preBtn2 {
display: none;
}
.headerBtn2 {
display: none;
}
.uploadImgLogo {
font-size: 50px;
}
.DropdownMenuContent,
.DropdownMenuSubContent {
min-width: 130px;
background-color: #887abf;
border: none;
padding: 5px;
animation-duration: 400ms;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
will-change: transform, opacity;
z-index: 30 !important;
}
.DropdownMenuContent[data-side='top'],
.DropdownMenuSubContent[data-side='top'] {
animation-name: slideDownAndFade;
}
.DropdownMenuContent[data-side='right'],
.DropdownMenuSubContent[data-side='right'] {
animation-name: slideLeftAndFade;
}
.DropdownMenuContent[data-side='bottom'],
.DropdownMenuSubContent[data-side='bottom'] {
animation-name: slideUpAndFade;
}
.DropdownMenuContent[data-side='left'],
.DropdownMenuSubContent[data-side='left'] {
animation-name: slideRightAndFade;
}
.DropdownMenuItem {
font-size: 13px;
line-height: 1;
color: black;
background-color: #887abf;
display: flex;
align-items: center;
height: 25px;
padding: 0 5px;
position: relative;
padding-left: 25px;
user-select: none;
outline: none;
border: none;
}
.SelectTrigger {
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 4px;
padding: 0 15px;
font-size: 13px;
line-height: 1;
height: 35px;
gap: 5px;
border: none;
background-color: #887abf;
color: black
}
option{
overflow-y:scroll;
}
.SelectTrigger:hover {
border: none;
outline: none;
}
.SelectTrigger:focus {
/* box-shadow: 0 0 0 2px black; */
border: none;
outline: none;
}
.SelectTrigger[data-placeholder] {
color: black;
}
.SelectIcon {
color: Var(--violet-11);
}
.SelectContent {
overflow: hidden;
background-color: white;
border-radius: 6px;
box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2);
}
.SelectViewport {
padding: 5px;
}
.SelectItem {
font-size: 13px;
line-height: 1;
color: var(--violet-11);
border-radius: 3px;
display: flex;
align-items: center;
height: 25px;
padding: 0 35px 0 25px;
position: relative;
user-select: none;
z-index: 10 !important;
}
.SelectItem[data-disabled] {
color: var(--mauve-8);
pointer-events: none;
}
.SelectItem[data-highlighted] {
outline: none;
background-color: var(--violet-9);
color: var(--violet-1);
}
.SelectLabel {
padding: 0 25px;
font-size: 12px;
line-height: 25px;
color: var(--mauve-11);
}
.SelectSeparator {
height: 1px;
background-color: var(--violet-6);
margin: 5px;
}
.SelectItemIndicator {
position: absolute;
left: 0;
width: 25px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.SelectScrollButton {
display: flex;
align-items: center;
justify-content: center;
height: 25px;
background-color: white;
color: var(--violet-11);
cursor: default;
}
@media screen and (max-width:767px) {
.showPages {
display: none;
}
.signatureContainer {
display: flex;
flex-direction: column;
}
.signerComponent {
display: none;
}
.preBtn1 {
display: none;
}
.preBtn2 {
display: flex;
align-items: center;
justify-content: space-between;
background-color: #ebebeb;
padding: 5px 10px;
}
#navbar {
overflow: hidden;
z-index: 10;
}
/* Navbar links */
#navbar a {
float: left;
display: block;
color: #f2f2f2;
text-align: center;
padding: 14px;
text-decoration: none;
}
#navbar a.active {
background-color: #4caf50;
color: white;
}
/* Page content */
.content {
padding: 16px;
}
/* The sticky class is added to the navbar
with JS when it reaches its scroll position */
.stickyHead {
position: fixed;
top: 50px;
left: 0.9rem;
}
.stickyfooter {
position: fixed;
bottom: 0px;
right: 0rem;
}
/* Add some top padding to the page content
to prevent sudden quick movement (as the
navigation bar gets a new position at the top of the
page (position:fixed and top:0) */
.stickyHead+.content {
padding-top: 60px;
}
.signLayoutContainer2 {
display: flex;
flex-direction: row;
justify-content: space-around;
margin-top: 5px;
padding: 2px 5px 10px 5px;
position: sticky;
align-items: center;
}
.headerBtn {
display: none;
}
.headerBtn2 {
display: flex;
flex-direction: column;
justify-content: space-between;
margin-top: 5px;
}
.mobileHead {
display: flex;
}
}
@media screen and (max-width:487px) and (min-width:351px) {
.signatureCanvas {
width: 300px;
height: 120px;
}
.penContainer{
width: 300px;
}
.uploadImgLogo {
font-size: 30px;
}
.hidePdf {
display: none;
}
.mobileHead {
display: flex;
}
}
@media screen and (max-width:350px) and (min-width:311px) {
.signatureCanvas {
width: 280px;
height: 112px;
}
.penContainer{
width: 280px;
}
.hidePdf {
display: none;
}
.signTab {
font-weight: 500 !important;
font-size: 10px !important;
}
.uploadImgLogo {
font-size: 25px;
}
.uploadImg {
font-size: 10px !important;
}
.mobileHead {
display: flex;
}
}
@media screen and (max-width:310px) {
.signatureCanvas {
width: 230px;
height: 92px;
}
.penContainer{
width: 230px;
}
.hidePdf {
display: none;
}
.signTab {
font-weight: 500 !important;
font-size: 10px !important;
}
.uploadImgLogo {
font-size: 20px;
}
.uploadImg {
font-size: 10px !important;
}
.mobileHead {
display: flex;
}
}
@@ -0,0 +1 @@
import("./bootstrap")
@@ -0,0 +1,7 @@
export const themeColor =()=>{
return "#47a3ad";
}
export const iconColor =()=>{
return "#686968"
}
@@ -0,0 +1,280 @@
import axios from "axios";
export async function getBase64FromUrl(url) {
const data = await fetch(url);
const blob = await data.blob();
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
const pdfBase = this.result;
const removeBase64Prefix = "data:application/octet-stream;base64,";
const suffixbase64 = pdfBase.replace(removeBase64Prefix, "");
resolve(suffixbase64);
};
});
}
export async function getBase64FromIMG(url) {
const data = await fetch(url);
const blob = await data.blob();
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
const pdfBase = this.result;
resolve(pdfBase);
};
});
}
export function getHostUrl() {
const hostUrl = window.location.href;
/// const hostUrl = "https://contracts-defaultssty.qik.ai/#/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive";
// const hostUrl = "https://contracts-defaultssty.qik.ai/#/"
// const hostUrl = "https://lionfish-app-75ly7.ondigitalocean.app/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive"
//const hostUrl = "https://app.opensignlabs.com/rpmf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/draftDocument";
if (hostUrl) {
const urlSplit = hostUrl.split("/");
const concatUrl = urlSplit[3] + "/" + urlSplit[4];
if (urlSplit) {
const desireUrl = "/" + concatUrl;
if (desireUrl) {
return desireUrl + "/";
}
}
} else {
return "/";
}
}
//function for upload stamp or image
export function onSaveImage(xyPostion, index, signKey, imgWH, image) {
const updateFilter = xyPostion[index].pos.filter(
(data, ind) =>
data.key === signKey && data.Width && data.Height && data.SignUrl
);
if (updateFilter.length > 0) {
let newWidth, nweHeight;
const aspectRatio = imgWH.width / imgWH.height;
const getXYdata = xyPostion[index].pos;
if (aspectRatio === 1) {
newWidth = aspectRatio * 100;
nweHeight = aspectRatio * 100;
} else if (aspectRatio < 2) {
newWidth = aspectRatio * 100;
nweHeight = 100;
} else if (aspectRatio > 2 && aspectRatio < 4) {
newWidth = aspectRatio * 70;
nweHeight = 70;
} else if (aspectRatio > 4) {
newWidth = aspectRatio * 40;
nweHeight = 40;
} else if (aspectRatio > 5) {
newWidth = aspectRatio * 10;
nweHeight = 10;
}
const getPosData = getXYdata;
const addSign = getPosData.map((url, ind) => {
if (url.key === signKey) {
return {
...url,
Width: newWidth,
Height: nweHeight,
SignUrl: image.src,
ImageType: image.imgType,
};
}
return url;
});
const newUpdateUrl = xyPostion.map((obj, ind) => {
if (ind === index) {
return { ...obj, pos: addSign };
}
return obj;
});
return newUpdateUrl;
// setXyPostion(newUpdateUrl);
} else {
const getXYdata = xyPostion[index].pos;
const getPosData = getXYdata;
const aspectRatio = imgWH.width / imgWH.height;
let newWidth, newHeight;
if (aspectRatio === 1) {
newWidth = aspectRatio * 100;
newHeight = aspectRatio * 100;
} else if (aspectRatio < 2) {
newWidth = aspectRatio * 100;
newHeight = 100;
} else if (aspectRatio > 2 && aspectRatio < 4) {
newWidth = aspectRatio * 70;
newHeight = 70;
} else if (aspectRatio > 4) {
newWidth = aspectRatio * 40;
newHeight = 40;
} else if (aspectRatio > 5) {
newWidth = aspectRatio * 10;
newHeight = 10;
}
const addSign = getPosData.map((url, ind) => {
if (url.key === signKey) {
return {
...url,
Width: newWidth,
Height: newHeight,
SignUrl: image.src,
ImageType: image.imgType,
};
}
return url;
});
const newUpdateUrl = xyPostion.map((obj, ind) => {
if (ind === index) {
return { ...obj, pos: addSign };
}
return obj;
});
return newUpdateUrl;
// setXyPostion(newUpdateUrl);
}
}
//function for save button to save signature or image url
export function onSaveSign(xyPostion, index, signKey, signatureImg) {
const updateFilter = xyPostion[index].pos.filter(
(data) => data.key === signKey && data.SignUrl
);
if (updateFilter.length > 0) {
const getXYdata = xyPostion[index].pos;
// updateFilter[0].SignUrl = signatureImg;
const getPosData = getXYdata;
const addSign = getPosData.map((url, ind) => {
if (url.key === signKey) {
return {
...url,
Width: 150,
Height: 60,
SignUrl: signatureImg,
};
}
return url;
});
const newUpdateUrl = xyPostion.map((obj, ind) => {
if (ind === index) {
return { ...obj, pos: addSign };
}
return obj;
});
return newUpdateUrl;
} else {
const getXYdata = xyPostion[index].pos;
const getPosData = getXYdata;
const addSign = getPosData.map((url, ind) => {
if (url.key === signKey) {
return { ...url, SignUrl: signatureImg, Width: 150, Height: 60 };
}
return url;
});
const newUpdateUrl = xyPostion.map((obj, ind) => {
if (ind === index) {
return { ...obj, pos: addSign };
}
return obj;
});
return newUpdateUrl;
}
}
//function for getting contract_User details
export const contractUsers = async (objectId) => {
const result = await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Users?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${objectId}"}}`,
{
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;
return res;
})
.catch((err) => {
return "Error: Something went wrong!";
});
return result;
};
//function for getting contrscts_contactbook details
export const contactBook = async (objectId) => {
const result = await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}_Contactbook?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${objectId}"}}`,
{
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;
return res;
})
.catch((err) => {
return "Error: Something went wrong!";
});
return result;
};
export const contactBookName = async (userPhone, className) => {
const result = await axios
.get(
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
"_appName"
)}${className}?where={"Phone":"${userPhone}"}`,
{
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;
return json;
})
.catch((err) => {
return "Error: Something went wrong!";
});
return result;
};
@@ -0,0 +1,10 @@
export const toDataUrl = (file) => {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = (e) => {
resolve(e.target.result);
};
});
};
@@ -0,0 +1,68 @@
import { useState } from "react";
import axios from "axios";
export const useFileUpload = () => {
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [_fileupload, setFileUpload] = useState("");
const [fileload, setfileload] = useState(false);
const [percentage, setpercentage] = useState(0);
const onChange = (e) => {
try {
let files = e.target.files;
if (typeof files[0] !== "undefined") {
fileUpload(files[0]);
} else {
alert("Please select file.");
return false;
}
} catch (error) {
alert(error.message);
return false;
}
};
const fileUpload = async (file) => {
setfileload(true);
let image_url = parseBaseUrl.replace("/app", "");
const url = `${image_url}image_upload`;
const formData = new FormData();
formData.append("file", file);
const config = {
headers: {
"content-type": "multipart/form-data",
"X-Parse-Application-Id": parseAppId,
},
onUploadProgress: function (progressEvent) {
var percentCompleted = Math.round(
(progressEvent.loaded * 100) / progressEvent.total
);
setpercentage(percentCompleted);
},
};
try {
await axios
.post(url, formData, config)
.then((res) => {
if (res.data.status === "Error") {
alert(res.data.message);
}
setFileUpload(res.data.imageUrl);
setfileload(false);
setpercentage(0);
})
.catch((err) => {
alert(`${err.message}`);
setfileload(false);
setpercentage(0);
});
} catch (error) {
alert(error.message);
setfileload(false);
setpercentage(0);
}
};
return { onChange, _fileupload, fileload, percentage, setFileUpload };
};