mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-17 21:25:54 +02:00
feat: add debug pdf page
This commit is contained in:
+85
@@ -30,6 +30,7 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-draggable": "^4.4.6",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-konva": "^18.2.10",
|
||||
"react-pdf": "^7.4.0",
|
||||
"react-rnd": "^10.4.1",
|
||||
"react-router-dom": "^6.16.0",
|
||||
@@ -6442,6 +6443,14 @@
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-reconciler": {
|
||||
"version": "0.28.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-reconciler/-/react-reconciler-0.28.8.tgz",
|
||||
"integrity": "sha512-SN9c4kxXZonFhbX4hJrZy37yw9e7EIxcpHCxQv5JUS18wDE5ovkQKlqQEkufdJCCMfuI9BnjUJvhYeJ9x5Ra7g==",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-transition-group": {
|
||||
"version": "4.4.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.7.tgz",
|
||||
@@ -12523,6 +12532,17 @@
|
||||
"set-function-name": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/its-fine": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/its-fine/-/its-fine-1.1.1.tgz",
|
||||
"integrity": "sha512-v1Ia1xl20KbuSGlwoaGsW0oxsw8Be+TrXweidxD9oT/1lAh6O3K3/GIM95Tt6WCiv6W+h2M7RB1TwdoAjQyyKw==",
|
||||
"dependencies": {
|
||||
"@types/react-reconciler": "^0.28.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jake": {
|
||||
"version": "10.8.7",
|
||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz",
|
||||
@@ -14685,6 +14705,26 @@
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/konva": {
|
||||
"version": "9.3.2",
|
||||
"resolved": "https://registry.npmjs.org/konva/-/konva-9.3.2.tgz",
|
||||
"integrity": "sha512-I4CFGVbWKpzgYi1I0pmoHz8iYfmGc/A61yfltzcuBHMFuBwDsR2VnQo4+eFQ1dGyEAmHcdvTumJ871KqkhuGng==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/lavrton"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/konva"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/lavrton"
|
||||
}
|
||||
],
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/language-subtag-registry": {
|
||||
"version": "0.3.22",
|
||||
"resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
|
||||
@@ -17904,6 +17944,36 @@
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz",
|
||||
"integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
|
||||
},
|
||||
"node_modules/react-konva": {
|
||||
"version": "18.2.10",
|
||||
"resolved": "https://registry.npmjs.org/react-konva/-/react-konva-18.2.10.tgz",
|
||||
"integrity": "sha512-ohcX1BJINL43m4ynjZ24MxFI1syjBdrXhqVxYVDw2rKgr3yuS0x/6m1Y2Z4sl4T/gKhfreBx8KHisd0XC6OT1g==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/lavrton"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/konva"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/lavrton"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/react-reconciler": "^0.28.2",
|
||||
"its-fine": "^1.1.1",
|
||||
"react-reconciler": "~0.29.0",
|
||||
"scheduler": "^0.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"konva": "^8.0.1 || ^7.2.5 || ^9.0.0",
|
||||
"react": ">=18.0.0",
|
||||
"react-dom": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-lifecycles-compat": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
|
||||
@@ -17950,6 +18020,21 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/react-reconciler": {
|
||||
"version": "0.29.0",
|
||||
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz",
|
||||
"integrity": "sha512-wa0fGj7Zht1EYMRhKWwoo1H9GApxYLBuhoAuXN0TlltESAjDssB+Apf0T/DngVqaMyPypDmabL37vw/2aRM98Q==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"react-dom": "^18.2.0",
|
||||
"react-draggable": "^4.4.6",
|
||||
"react-helmet": "^6.1.0",
|
||||
"react-konva": "^18.2.10",
|
||||
"react-pdf": "^7.4.0",
|
||||
"react-rnd": "^10.4.1",
|
||||
"react-router-dom": "^6.16.0",
|
||||
|
||||
@@ -0,0 +1,432 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import RenderAllPdfPage from "./component/renderAllPdfPage";
|
||||
import "../css/./signature.css";
|
||||
import { pdfNewWidthFun } from "../utils/Utils";
|
||||
import "../css/AddUser.css";
|
||||
import Title from "./component/Title";
|
||||
import ModalUi from "../premitives/ModalUi";
|
||||
import RenderDebugPdf from "./component/RenderDebugPdf";
|
||||
import { pdfjs } from "react-pdf";
|
||||
import Alert from "../premitives/Alert";
|
||||
|
||||
function processDimensions(x, y, width, height) {
|
||||
if (width < 0) {
|
||||
x -= Math.abs(width);
|
||||
width = Math.abs(width);
|
||||
}
|
||||
|
||||
if (height < 0) {
|
||||
y -= Math.abs(height);
|
||||
height = Math.abs(height);
|
||||
}
|
||||
|
||||
return {
|
||||
x: Math.floor(x),
|
||||
y: Math.floor(y),
|
||||
width: Math.floor(width),
|
||||
height: Math.floor(height)
|
||||
};
|
||||
}
|
||||
const DebugUi = () => {
|
||||
const divRef = useRef(null);
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const [pdf, setPdf] = useState("");
|
||||
const [isModal, setIsModal] = useState(true);
|
||||
const [allPages, setAllPages] = useState(null);
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
const [pdfNewWidth, setPdfNewWidth] = useState();
|
||||
const [containerWH, setContainerWH] = useState();
|
||||
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
|
||||
const [pdfLoadFail, setPdfLoadFail] = useState({
|
||||
status: false,
|
||||
type: "load"
|
||||
});
|
||||
const [pdfDetails, setPdfDetails] = useState({
|
||||
name: "",
|
||||
pdftype: "",
|
||||
totalPages: "",
|
||||
currentPage: 1,
|
||||
x: 0,
|
||||
y: 0,
|
||||
base64: ""
|
||||
});
|
||||
const [hoverCoordinates, setHoverCoordinates] = useState({ x: 0, y: 0 });
|
||||
const [drawing, setDrawing] = useState(false);
|
||||
const [pdfDimension, setPdfDimension] = useState({ width: 0, height: 0 });
|
||||
const [annotations, setAnnotations] = useState([]);
|
||||
const [newAnnotation, setNewAnnotation] = useState([]);
|
||||
const [copied, setCopied] = useState(false);
|
||||
useEffect(() => {
|
||||
if (divRef.current) {
|
||||
const pdfWidth = pdfNewWidthFun(divRef);
|
||||
setPdfNewWidth(pdfWidth);
|
||||
setContainerWH({
|
||||
width: divRef.current.offsetWidth,
|
||||
height: divRef.current.offsetHeight
|
||||
});
|
||||
}
|
||||
}, [divRef.current]);
|
||||
|
||||
useEffect(() => {
|
||||
if (pdf && pdf.name) {
|
||||
const fetchPdfMetadata = async () => {
|
||||
try {
|
||||
const pdfDataURL = URL.createObjectURL(pdf); // Convert File to data URL
|
||||
console.log("pdfDataURL ", pdfDataURL);
|
||||
const pdfInfo = await pdfjs.getDocument({ url: pdfDataURL }).promise;
|
||||
const pdfType = await inferPdfType(pdfInfo);
|
||||
setPdfDetails((prevDetails) => ({
|
||||
...prevDetails,
|
||||
pdftype: pdfType
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error("Error fetching PDF metadata:", error);
|
||||
}
|
||||
};
|
||||
|
||||
fetchPdfMetadata();
|
||||
}
|
||||
}, [pdf]);
|
||||
|
||||
const inferPdfType = async (pdf) => {
|
||||
try {
|
||||
const firstPage = await pdf.getPage(1);
|
||||
const scale = 1;
|
||||
const { width, height } = firstPage.getViewport({ scale });
|
||||
setPdfDimension({ width: width, height: height });
|
||||
|
||||
// Assuming a standard DPI of 72, you can adjust this value if needed
|
||||
const dpi = 72;
|
||||
|
||||
const widthInInches = width / dpi;
|
||||
const heightInInches = height / dpi;
|
||||
|
||||
const isA1 = widthInInches > 23.39 && heightInInches > 16.54;
|
||||
const isA2 = widthInInches > 16.54 && heightInInches > 11.69;
|
||||
const isA3 = widthInInches > 11.69 && heightInInches > 8.27;
|
||||
const isA4 = widthInInches > 8.27 && heightInInches > 5.83;
|
||||
const isLegal = widthInInches > 8.5 && heightInInches > 14;
|
||||
const isLetter = widthInInches > 8.5 && heightInInches > 11;
|
||||
const isLedger = widthInInches > 11 && heightInInches > 17;
|
||||
|
||||
if (isA1) return "A1";
|
||||
if (isA2) return "A2";
|
||||
if (isA3) return "A3";
|
||||
if (isA4) return "A4";
|
||||
if (isLegal) return "Legal";
|
||||
if (isLetter) return "Letter";
|
||||
if (isLedger) return "Ledger";
|
||||
|
||||
return "Unknown";
|
||||
} catch (error) {
|
||||
console.error("Error getting page dimensions:", error);
|
||||
return "Unknown";
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
setIsModal(false);
|
||||
setPdfDetails((prevData) => ({ ...prevData, name: pdf?.name }));
|
||||
};
|
||||
|
||||
//function for get pdf page details
|
||||
const pageDetails = async ({ numPages }) => {
|
||||
const load = {
|
||||
status: true
|
||||
};
|
||||
setPdfDetails((prevDetails) => ({ ...prevDetails, totalPages: numPages }));
|
||||
setPdfLoadFail(load);
|
||||
};
|
||||
|
||||
const handleMouseMoveDiv = (event) => {
|
||||
setHoverCoordinates({
|
||||
x: event.nativeEvent.offsetX,
|
||||
y: event.nativeEvent.offsetY
|
||||
});
|
||||
};
|
||||
const handleMouseDown = (event) => {
|
||||
if (newAnnotation.length === 0) {
|
||||
const { x, y } = event.target.getStage().getPointerPosition();
|
||||
setNewAnnotation([{ x, y, width: 0, height: 0, key: "0" }]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseUp = (event) => {
|
||||
if (newAnnotation.length === 1) {
|
||||
const sx = newAnnotation[0].x;
|
||||
const sy = newAnnotation[0].y;
|
||||
const { x, y } = event.target.getStage().getPointerPosition();
|
||||
const result = processDimensions(sx, sy, x - sx, y - sy);
|
||||
const annotationToAdd = { ...result, key: annotations.length + 1 };
|
||||
annotations.push(annotationToAdd);
|
||||
setNewAnnotation([]);
|
||||
setAnnotations(annotations);
|
||||
setPdfDetails((prevDetails) => ({
|
||||
...prevDetails,
|
||||
x: result.x,
|
||||
y: result.y
|
||||
}));
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseMove = (event) => {
|
||||
if (newAnnotation.length === 1) {
|
||||
const sx = newAnnotation[0].x;
|
||||
const sy = newAnnotation[0].y;
|
||||
const { x, y } = event.target.getStage().getPointerPosition();
|
||||
setNewAnnotation([
|
||||
{
|
||||
x: sx,
|
||||
y: sy,
|
||||
width: x - sx,
|
||||
height: y - sy,
|
||||
key: "0"
|
||||
}
|
||||
]);
|
||||
}
|
||||
};
|
||||
|
||||
const annotationsToDraw = [...annotations, ...newAnnotation];
|
||||
|
||||
const handlePageLoadSuccess = (page) => {
|
||||
setPdfDetails((prevDetails) => ({
|
||||
...prevDetails,
|
||||
currentPage: page.pageNumber
|
||||
}));
|
||||
};
|
||||
|
||||
const copytoclipboard = (text) => {
|
||||
navigator.clipboard.writeText(text);
|
||||
setCopied(true);
|
||||
setTimeout(() => {
|
||||
setCopied(false);
|
||||
}, 1500); // Reset copied state after 1.5 seconds
|
||||
};
|
||||
const handleFileChange = (files) => {
|
||||
const file = files[0];
|
||||
setPdf(file);
|
||||
|
||||
if (file && file.type === "application/pdf") {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onloadend = () => {
|
||||
const base64String = reader.result.split(",")[1];
|
||||
setPdfDetails((prevdata) => ({ ...prevdata, base64: base64String }));
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
};
|
||||
const handleDelete = (key) => {
|
||||
const updateAnnotations = annotations.filter((x) => x.key !== key);
|
||||
setAnnotations(updateAnnotations);
|
||||
};
|
||||
return (
|
||||
<div>
|
||||
{copied && <Alert type="success">Copied</Alert>}
|
||||
<Title title={"Debug Pdf"} />
|
||||
{!isModal && (
|
||||
<div className="signatureContainer" ref={divRef}>
|
||||
{/* this component used to render all pdf pages in left side */}
|
||||
<RenderAllPdfPage
|
||||
signPdfUrl={pdf}
|
||||
allPages={allPages}
|
||||
setAllPages={setAllPages}
|
||||
setPageNumber={setPageNumber}
|
||||
pageNumber={pageNumber}
|
||||
/>
|
||||
{/* pdf render view */}
|
||||
<div
|
||||
style={{
|
||||
marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px",
|
||||
marginRight: !isMobile && pdfOriginalWidth > 500 && "20px"
|
||||
}}
|
||||
>
|
||||
<div data-tut="reactourThird">
|
||||
{containerWH && (
|
||||
<RenderDebugPdf
|
||||
pdfUrl={pdf}
|
||||
pageDetails={pageDetails}
|
||||
pageNumber={pageNumber}
|
||||
pdfOriginalWidth={pdfOriginalWidth}
|
||||
pdfNewWidth={pdfNewWidth}
|
||||
setPdfLoadFail={setPdfLoadFail}
|
||||
pdfLoadFail={pdfLoadFail}
|
||||
handlePageLoadSuccess={handlePageLoadSuccess}
|
||||
handleMouseMove={handleMouseMove}
|
||||
handleMouseUp={handleMouseUp}
|
||||
handleMouseDown={handleMouseDown}
|
||||
hoverCoordinates={hoverCoordinates}
|
||||
annotations={annotationsToDraw}
|
||||
pdfDimension={pdfDimension}
|
||||
handleMouseMoveDiv={handleMouseMoveDiv}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ backgroundColor: "white", width: 220 }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 18,
|
||||
fontWeight: 500,
|
||||
padding: "10px 12px",
|
||||
borderBottom: "1px solid grey"
|
||||
}}
|
||||
>
|
||||
PDF details
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
Name: {pdfDetails?.name}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
Pdf type: {pdfDetails?.pdftype}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
Total Pages: {pdfDetails?.totalPages}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
Current Page: {pdfDetails?.currentPage}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
Base64 : {pdfDetails?.base64.slice(0, 10)}...
|
||||
<span
|
||||
style={{
|
||||
borderRadius: 4,
|
||||
padding: "3px 5px",
|
||||
border: "1px solid gray",
|
||||
fontSize: 12,
|
||||
margin: 2,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
onClick={() => copytoclipboard(pdfDetails?.base64)}
|
||||
>
|
||||
<i className="fa-solid fa-copy"></i>
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 18,
|
||||
fontWeight: 500,
|
||||
padding: "10px 12px",
|
||||
borderBottom: "1px solid grey"
|
||||
}}
|
||||
>
|
||||
Last click
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
x co-ordinate: {pdfDetails?.x}
|
||||
</div>
|
||||
<div style={{ fontSize: 14, padding: "5px 12px" }}>
|
||||
y co-ordinate: {pdfDetails?.y}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
fontSize: 18,
|
||||
fontWeight: 500,
|
||||
padding: "10px 12px",
|
||||
borderBottom: "1px solid grey",
|
||||
borderTop: "1px solid grey"
|
||||
}}
|
||||
>
|
||||
Annotation
|
||||
</div>
|
||||
<ul
|
||||
style={{
|
||||
listStyle: "none",
|
||||
padding: 10,
|
||||
height: 500,
|
||||
overflowY: "auto",
|
||||
scrollbarWidth: 5
|
||||
}}
|
||||
>
|
||||
{annotations.map((coord, index) => (
|
||||
<li key={index}>
|
||||
<span style={{ fontSize: 13, fontWeight: 500 }}>{`Box ${
|
||||
index + 1
|
||||
}:`}</span>
|
||||
<code
|
||||
style={{ fontSize: 12, color: "black", cursor: "pointer" }}
|
||||
>
|
||||
{` ["x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`}
|
||||
</code>
|
||||
<span
|
||||
style={{
|
||||
borderRadius: 4,
|
||||
padding: "3px 5px",
|
||||
border: "1px solid gray",
|
||||
fontSize: 12,
|
||||
margin: 2,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
onClick={() =>
|
||||
copytoclipboard(
|
||||
`["x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`
|
||||
)
|
||||
}
|
||||
>
|
||||
<i className="fa-solid fa-copy"></i>
|
||||
</span>
|
||||
<span
|
||||
style={{
|
||||
borderRadius: 4,
|
||||
padding: "3px 5px",
|
||||
border: "1px solid gray",
|
||||
fontSize: 12,
|
||||
margin: 2,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
onClick={() => handleDelete(coord.key)}
|
||||
>
|
||||
<i className="fa-solid fa-trash-can"></i>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ModalUi title={"Select PDF"} isOpen={isModal}>
|
||||
<form onSubmit={handleSubmit} style={{ margin: "10px" }}>
|
||||
<input
|
||||
type="file"
|
||||
onChange={(e) => handleFileChange(e.target.files)}
|
||||
style={{
|
||||
width: "100%",
|
||||
border: "1px solid grey",
|
||||
borderRadius: "4px",
|
||||
padding: "5px",
|
||||
fontSize: 12
|
||||
}}
|
||||
accept=".pdf"
|
||||
required
|
||||
/>
|
||||
<div style={{ borderTop: "1px solid grey", margin: "10px 0" }}></div>
|
||||
<button
|
||||
style={{
|
||||
background: "#32a3ac",
|
||||
borderRadius: "2px",
|
||||
boxShadow:
|
||||
"0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18)",
|
||||
border: "none",
|
||||
textTransform: "uppercase",
|
||||
fontSize: "13px",
|
||||
fontWeight: "600",
|
||||
padding: "0.375rem 0.75rem",
|
||||
textAlign: "center",
|
||||
color: "#ffffff",
|
||||
outline: "none"
|
||||
}}
|
||||
type="submit"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
</form>
|
||||
</ModalUi>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DebugUi;
|
||||
@@ -0,0 +1,83 @@
|
||||
import React from "react";
|
||||
import { Document, Page, pdfjs } from "react-pdf";
|
||||
import { Stage, Layer, Rect } from "react-konva";
|
||||
const RenderDebugPdf = (props) => {
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
style={{
|
||||
position: "sticky",
|
||||
top: 0,
|
||||
padding: 10,
|
||||
zIndex: 1,
|
||||
backgroundColor: "white",
|
||||
border: "1px solid grey",
|
||||
margin: "5px 0"
|
||||
}}
|
||||
>
|
||||
{`Co-ordinates: X - ${props.hoverCoordinates.x}, Y - ${props.hoverCoordinates.y}`}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
flex: 1,
|
||||
position: "relative",
|
||||
border: "1px solid grey",
|
||||
overflow: "auto"
|
||||
}}
|
||||
onMouseMove={props.handleMouseMoveDiv}
|
||||
>
|
||||
<Document
|
||||
onLoadError={(e) => {
|
||||
const load = {
|
||||
status: false,
|
||||
type: "failed"
|
||||
};
|
||||
props.setPdfLoadFail(load);
|
||||
}}
|
||||
loading={"Loading Document.."}
|
||||
onLoadSuccess={props.pageDetails}
|
||||
ref={props.pdfRef}
|
||||
file={props.pdfUrl}
|
||||
>
|
||||
<Page
|
||||
onLoadSuccess={props.handlePageLoadSuccess}
|
||||
pageNumber={props.pageNumber}
|
||||
renderAnnotationLayer={false}
|
||||
renderTextLayer={false}
|
||||
onGetAnnotationsError={(error) => {
|
||||
console.log("annotation error", error);
|
||||
}}
|
||||
/>
|
||||
</Document>
|
||||
|
||||
<Stage
|
||||
onMouseMove={props.handleMouseMove}
|
||||
onMouseDown={props.handleMouseDown}
|
||||
onMouseUp={props.handleMouseUp}
|
||||
width={props.pdfDimension.width}
|
||||
height={props.pdfDimension.height}
|
||||
style={{ position: "absolute", top: 0, left: 0 }}
|
||||
>
|
||||
<Layer>
|
||||
{props.annotations.map((value) => {
|
||||
return (
|
||||
<Rect
|
||||
x={value.x}
|
||||
y={value.y}
|
||||
width={value.width}
|
||||
height={value.height}
|
||||
fill="transparent"
|
||||
stroke="black"
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</Layer>
|
||||
</Stage>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default RenderDebugPdf;
|
||||
@@ -10,7 +10,7 @@ import LegaDrive from "./Component/LegaDrive/LegaDrive";
|
||||
import PageNotFound from "./Component/PageNotFound";
|
||||
import TemplatePlaceHolder from "./Component/TemplatePlaceholder";
|
||||
import Parse from "parse";
|
||||
import GuestLogin from "./premitives/GuestLogin";
|
||||
import DebugUi from "./Component/DebugUi";
|
||||
Parse.serverURL = localStorage.getItem("baseUrl");
|
||||
Parse.initialize(localStorage.getItem("parseAppId"));
|
||||
// `AppRoutes` is used to define route path of app and
|
||||
@@ -51,8 +51,7 @@ function AppRoutes() {
|
||||
<Route path="/legadrive" element={<LegaDrive />} />
|
||||
{/* Page Not Found */}
|
||||
<Route path="/template/:templateId" element={<TemplatePlaceHolder />} />
|
||||
<Route path="/guestlogin" element={<GuestLogin />} />
|
||||
|
||||
<Route path="/debugpdf" element={<DebugUi />} />
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
</Routes>
|
||||
</div>
|
||||
|
||||
@@ -5,20 +5,47 @@ const Alert = ({ children, type }) => {
|
||||
function theme(color) {
|
||||
switch (color) {
|
||||
case "success":
|
||||
return "border-[#c3e6cb] bg-[#d4edda] text-[#155724]";
|
||||
return {
|
||||
border: `1px solid #c3e6cb`, // Border color
|
||||
backgroundColor: "#d4edda", // Background color
|
||||
color: "#155724" // Text color
|
||||
};
|
||||
|
||||
case "info":
|
||||
return "border-[#adcdeb] bg-[#c1daf0] text-[#153756]";
|
||||
return {
|
||||
border: `1px solid #adcdeb`, // Border color
|
||||
backgroundColor: "#c1daf0", // Background color
|
||||
color: "#153756" // Text color
|
||||
};
|
||||
case "danger":
|
||||
return "border-[#f0a8a8] bg-[#f4bebe] text-[#c42121]";
|
||||
return {
|
||||
border: `1px solid #f0a8a8`, // Border color
|
||||
backgroundColor: "#f4bebe", // Background color
|
||||
color: "#c42121" // Text color
|
||||
};
|
||||
default:
|
||||
return "border-[#d6d6d6] bg-[#d9d9d9] text-[#575757]";
|
||||
return {
|
||||
border: `1px solid #d6d6d6`, // Border color
|
||||
backgroundColor: "#d9d9d9", // Background color
|
||||
color: "#575757" // Text color
|
||||
};
|
||||
}
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{children && (
|
||||
<div
|
||||
className={`z-40 fixed top-20 left-1/2 transform -translate-x-1/2 border-[1px] text-sm ${textcolor} rounded py-[.75rem] px-[1.25rem] `}
|
||||
style={{
|
||||
...textcolor,
|
||||
position: "fixed",
|
||||
top: "20px",
|
||||
left: "50%",
|
||||
transform: "translateX(-50%)",
|
||||
fontSize: "0.875rem", // Corresponds to text-sm in Tailwind CSS
|
||||
borderRadius: "5px", // Rounded corners
|
||||
padding: "10px 15px", // Padding
|
||||
zIndex: 40
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
|
||||
@@ -1,294 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import ModalUi from './ModalUi'
|
||||
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 GuestSign from "./GuestSign";
|
||||
|
||||
function GuestLogin({children, userdetails}) {
|
||||
const { id, userMail, contactBookId, serverUrl } = useParams();
|
||||
let navigate = useNavigate();
|
||||
const [email, setEmail] = useState(userMail || "prafull.navkar@nxglabs.com");
|
||||
const [OTP, setOTP] = useState("");
|
||||
const [EnterOTP, setEnterOtp] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
handleServerUrl();
|
||||
}, []);
|
||||
|
||||
//function generate serverUrl and parseAppId from url and save it in local storage
|
||||
const handleServerUrl = () => {
|
||||
//split url in array from '&'
|
||||
localStorage.clear();
|
||||
// const checkSplit = serverUrl?.split("&");
|
||||
// const server = checkSplit?.[0];
|
||||
// const parseId = checkSplit?.[1];
|
||||
// const appName = checkSplit?.[2];
|
||||
|
||||
// const newServer = server.replaceAll("%2F", "/");
|
||||
// localStorage.setItem("baseUrl", newServer);
|
||||
// localStorage.setItem("parseAppId", parseId);
|
||||
// localStorage.setItem("_appName", appName);
|
||||
|
||||
localStorage.setItem("baseUrl", "https://staging-app.opensignlabs.com/api/app/");
|
||||
localStorage.setItem("parseAppId", "opensignstgn");
|
||||
localStorage.setItem("_appName", "contracts");
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
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");
|
||||
if (serverUrl && localStorage) {
|
||||
setLoading(true);
|
||||
e.preventDefault();
|
||||
setEmail(email);
|
||||
|
||||
try {
|
||||
let url = `${serverUrl}functions/SendOTPMailV1/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId
|
||||
};
|
||||
let body = {
|
||||
email: email.toString()
|
||||
};
|
||||
let Otp = await axios.post(url, body, { headers: headers });
|
||||
|
||||
if (Otp) {
|
||||
setLoading(false);
|
||||
setEnterOtp(true);
|
||||
}
|
||||
} catch (error) {
|
||||
alert("something went wrong!");
|
||||
}
|
||||
} 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 {
|
||||
let url = `${serverUrl}functions/AuthLoginAsMail/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId
|
||||
};
|
||||
let body = {
|
||||
email: email,
|
||||
otp: OTP
|
||||
};
|
||||
let user = await axios.post(url, body, { headers: headers });
|
||||
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;
|
||||
const parseId = localStorage.getItem("parseAppId");
|
||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||
localStorage.setItem(
|
||||
`Parse/${parseId}/currentUser`,
|
||||
JSON.stringify(_user)
|
||||
);
|
||||
localStorage.setItem("username", _user.name);
|
||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||
//save isGuestSigner true in local to handle login flow header in mobile view
|
||||
localStorage.setItem("isGuestSigner", true);
|
||||
setLoading(false);
|
||||
// uKymQWaYL6
|
||||
navigate(
|
||||
`/loadmf/signmicroapp/recipientSignPdf/${id}/${contactBookId}`
|
||||
);
|
||||
}
|
||||
} catch (error) {}
|
||||
} else {
|
||||
alert("Please Enter OTP!");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: "2rem" }}>
|
||||
<ModalUi isOpen>
|
||||
<>
|
||||
{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"
|
||||
}}
|
||||
>
|
||||
<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 ? (
|
||||
<div >
|
||||
<div >
|
||||
<span className="welcomeText">Welcome Back !</span>
|
||||
<br />
|
||||
<span className="KNLO">
|
||||
Verification code is sent to your email
|
||||
</span>
|
||||
<div className="card card-box" style={{ borderRadius: "0px" }}>
|
||||
<div className="card-body">
|
||||
<input
|
||||
type="email"
|
||||
name="mobile"
|
||||
value={email}
|
||||
disabled
|
||||
className="loginInput"
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div className="btnContainer">
|
||||
{loading ? (
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
disabled
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
className="verifyBtn"
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white",
|
||||
marginLeft: "0px !important"
|
||||
}}
|
||||
onClick={(e) => SendOtp(e)}
|
||||
>
|
||||
Send OTP
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div >
|
||||
<div >
|
||||
<span className="welcomeText">Welcome Back !</span>
|
||||
<br />
|
||||
<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="loginInput"
|
||||
name="OTP"
|
||||
value={OTP}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{loading ? (
|
||||
<button
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
type="button"
|
||||
disabled
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => VerifyOTP(e)}
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
>
|
||||
Verify
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
</ModalUi>
|
||||
<div><GuestSign /></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default GuestLogin;
|
||||
Reference in New Issue
Block a user