Compare commits

..
97 changed files with 5500 additions and 33398 deletions
+12
View File
@@ -0,0 +1,12 @@
# Clone the repo and rename this file to .env if you want to run the frontend react app locally for some quick contributions to the project.
# When used as it is, this env config will connect to our hosted UAT backend
# Note that any data in staging will get cleared from time to time and you may have to sign up again and again
# Set it to the URL form where the app home page will be accessed
PUBLIC_URL=http://localhost:3000
# Set it to true if you want to generate the Sourcemap for debugging
GENERATE_SOURCEMAP=false
# Set it to the URL from where APIs will be accessible, for local development it should be localhost:3000/api/app (use your local port number instead)
REACT_APP_SERVERURL=https://staging-app.opensignlabs.com/api/app
# A 12 character long random app identifier. The value of this should be same as APP_ID which is a variable used by backend API.
REACT_APP_APPID=opensign
+545 -552
View File
File diff suppressed because it is too large Load Diff
+7 -10
View File
@@ -4,7 +4,6 @@
"private": true,
"dependencies": {
"@formkit/auto-animate": "^0.8.2",
"@lottiefiles/dotlottie-react": "^0.6.4",
"@radix-ui/themes": "^3.0.5",
"@react-pdf/renderer": "^3.4.4",
"@reduxjs/toolkit": "^2.2.5",
@@ -47,8 +46,7 @@
"regex-parser": "^2.3.0",
"serve": "^14.2.3",
"styled-components": "^4.4.1",
"web-vitals": "^4.0.1",
"ws": "^8.17.1"
"web-vitals": "^4.0.1"
},
"scripts": {
"start": "serve -s build",
@@ -91,16 +89,15 @@
"commitizen": "^4.3.0",
"daisyui": "^4.12.2",
"eslint": "^8.57.0",
"eslint-plugin-prettier": "^5.1.3",
"eslint-plugin-react": "^7.34.3",
"lint-staged": "^15.2.7",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.34.1",
"lint-staged": "^15.2.5",
"postcss": "^8.4.38",
"prettier": "^3.3.2",
"pretty-quick": "^4.0.0",
"prettier": "^2.8.8",
"pretty-quick": "^3.3.1",
"tailwindcss": "^3.4.4"
},
"overrides": {
"nth-check": "$nth-check",
"ws":"$ws"
"nth-check": "$nth-check"
}
}
File diff suppressed because it is too large Load Diff
+36 -3
View File
@@ -1,20 +1,53 @@
<!DOCTYPE html>
<html lang="en" data-theme="opensigncss">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<!-- <link rel="icon" type="image/png"
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC"
sizes="40x40" /> -->
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css"
integrity="sha512-z3gLpd7yknf1YoNbCzqRKc4qyor8gaKU1qmn+CShxbuBusANI9QpRohGBreCFkKxLhei6S9CQXFEbbKuqLg0DA=="
crossorigin="anonymous" referrerpolicy="no-referrer" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
<link rel="stylesheet" href="/css/fonts.css" />
<title>OpenSign™</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
View File
@@ -32,6 +32,7 @@ const GenerateToken = lazy(() => import("./pages/GenerateToken"));
const Webhook = lazy(() => import("./pages/Webhook"));
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
const AppLoader = () => {
return (
<div className="flex justify-center items-center h-[100vh]">
Binary file not shown.

After

Width:  |  Height:  |  Size: 316 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 234 KiB

+13 -40
View File
@@ -113,15 +113,9 @@ const BulkSendUi = (props) => {
let Placeholders = [...props.item.Placeholders];
// Initialize an empty array to store updated documents
let Documents = [];
// Loop through each form
forms.forEach((form) => {
//checking if user enter email which already exist as a signer then add user in a signers array
let existSigner = [];
form.fields.map((data) => {
if (data.signer) {
existSigner.push(data.signer);
}
});
// Map through the copied Placeholders array to update email values
const updatedPlaceholders = Placeholders.map((placeholder) => {
// Find the field in the current form that matches the placeholder Id
@@ -129,44 +123,23 @@ const BulkSendUi = (props) => {
(element) => parseInt(element.fieldId) === placeholder.Id
);
// If a matching field is found, update the email value in the placeholder
const signer = field?.signer?.objectId ? field.signer : "";
const signer = field?.signer?.objectId ? field.signer : {};
if (field) {
if (signer) {
return {
...placeholder,
signerObjId: field?.signer?.objectId || "",
signerPtr: signer
};
} else {
return {
...placeholder,
email: field.email,
signerObjId: field?.signer?.objectId || "",
signerPtr: signer
};
}
return {
...placeholder,
email: field.email,
signerObjId: field?.signer?.objectId || "",
signerPtr: signer
};
}
// If no matching field is found, keep the placeholder as is
return placeholder;
});
// Push a new document object with updated Placeholders into the Documents array
if (existSigner?.length > 0) {
Documents.push({
...props.item,
Placeholders: updatedPlaceholders,
Signers: props.item.Signers
? [...props.item.Signers, ...existSigner]
: [...existSigner]
});
} else {
Documents.push({
...props.item,
Placeholders: updatedPlaceholders
});
}
Documents.push({ ...props.item, Placeholders: updatedPlaceholders });
});
//console.log("Documents ", Documents);
// console.log("Documents ", Documents);
await batchQuery(Documents);
};
@@ -232,7 +205,7 @@ const BulkSendUi = (props) => {
onClick={() => handleRemoveForm(index)}
className="absolute right-3 top-1 text-[red] border-[1px] border-[red] rounded-lg w-[1.7rem] h-[1.7rem]"
>
<i className="fa-light fa-trash"></i>
<i className="fa-solid fa-trash"></i>
</button>
)}
<div ref={formRef}></div>
@@ -244,13 +217,13 @@ const BulkSendUi = (props) => {
onClick={handleAddForm}
className="op-btn op-btn-primary focus:outline-none"
>
<i className="fa-light fa-plus"></i> <span>Add new</span>
<i className="fa-solid fa-plus"></i> <span>Add new</span>
</button>
<button
type="submit"
className="op-btn op-btn-secondary focus:outline-none"
>
<i className="fa-light fa-paper-plane"></i>{" "}
<i className="fa-solid fa-paper-plane"></i>{" "}
<span>Send</span>
</button>
</div>
+2 -2
View File
@@ -58,10 +58,10 @@ const Footer = () => {
<button
className={`${
showButton ? "block" : "hidden"
} fixed bottom-4 right-4 px-3 p-2 text-xl op-bg-secondary text-white rounded focus:outline-none`}
} fixed bottom-4 right-4 px-3 p-2 text-xl bg-blue-500 text-white rounded focus:outline-none`}
onClick={scrollToTop}
>
<i className="fa-light fa-angle-up"></i>
<i className="fa-solid fa-angle-up"></i>
</button>
</>
);
@@ -70,9 +70,9 @@ const FullScreenButton = () => {
className="text-base-content p-2 text-sm focus:outline-none"
>
{isFullScreen ? (
<i className="fa-light fa-compress"></i>
<i className="fa-solid fa-compress"></i>
) : (
<i className="fa-light fa-maximize"></i>
<i className="fa fa-maximize"></i>
)}
</button>
</div>
+10 -14
View File
@@ -96,10 +96,10 @@ const Header = ({ showSidebar }) => {
<div className="op-navbar bg-base-100 shadow">
<div className="flex-none">
<button
className="op-btn op-btn-square op-btn-ghost focus:outline-none hover:bg-transparent op-btn-sm no-animation"
className="op-btn op-btn-square op-btn-ghost focus:outline-none"
onClick={showSidebar}
>
<i className="fa-light fa-bars text-xl text-base-content"></i>
<i className="fa-solid fa-bars text-xl text-base-content"></i>
</button>
</div>
<div className="flex-1 ml-2">
@@ -115,7 +115,7 @@ const Header = ({ showSidebar }) => {
{!isSubscribe && (
<div>
<button
className="text-xs md:text-sm shadow op-btn op-btn-outline op-btn-sm md:op-btn-md op-btn-accent"
className="text-xs bg-[#002864] p-2 text-white rounded shadow"
onClick={() => navigate("/subscription")}
>
Upgrade Now
@@ -151,16 +151,12 @@ const Header = ({ showSidebar }) => {
</div>
)}
<div className="op-dropdown op-dropdown-end" id="profile-menu">
<div
tabIndex={0}
role="button"
className="op-btn op-btn-ghost op-btn-xs w-[10px] h-[20px] hover:bg-transparent"
>
<div tabIndex={0} role="button" className="op-btn op-btn-ghost">
<i
tabIndex={0}
role="button"
onClick={toggleDropdown}
className="fa-light fa-angle-down text-base-content"
className="fa-solid fa-angle-down text-base-content"
></i>
</div>
<ul
@@ -169,7 +165,7 @@ const Header = ({ showSidebar }) => {
>
<li onClick={() => openInNewTab("https://docs.opensignlabs.com")}>
<span>
<i className="fa-light fa-book"></i> Docs
<i className="fa-solid fa-book"></i> Docs
</span>
</li>
<li
@@ -179,7 +175,7 @@ const Header = ({ showSidebar }) => {
}}
>
<span>
<i className="fa-light fa-user"></i> Profile
<i className="fa-regular fa-user"></i> Profile
</span>
</li>
<li
@@ -189,7 +185,7 @@ const Header = ({ showSidebar }) => {
}}
>
<span>
<i className="fa-light fa-lock"></i> Change Password
<i className="fa-solid fa-lock"></i> Change Password
</span>
</li>
<li
@@ -198,12 +194,12 @@ const Header = ({ showSidebar }) => {
}}
>
<span>
<i className="fa-light fa-id-card"></i> Console
<i className="fa-regular fa-id-card"></i> Console
</span>
</li>
<li onClick={closeDropdown}>
<span>
<i className="fa-light fa-arrow-right-from-bracket"></i> Log Out
<i className="fa-solid fa-arrow-right-from-bracket"></i> Log Out
</span>
</li>
</ul>
+15 -25
View File
@@ -1,6 +1,6 @@
import React from "react";
import { Document, Page } from "react-pdf";
import { Stage, Layer, Rect, Text } from "react-konva";
import { Stage, Layer, Rect } from "react-konva";
const RenderDebugPdf = (props) => {
return (
<div>
@@ -13,7 +13,11 @@ const RenderDebugPdf = (props) => {
>
<Document
onLoadError={() => {
props.setPdfLoadFail(false);
const load = {
status: false,
type: "failed"
};
props.setPdfLoadFail(load);
}}
loading={"Loading Document.."}
onLoadSuccess={props.pageDetails}
@@ -43,30 +47,16 @@ const RenderDebugPdf = (props) => {
{props.annotations
.filter((value) => value.page === props.pageNumber)
.map((value) => {
const textX = value.x + value.width / 3;
const textY = value.y + value.height / 2.5;
return (
<React.Fragment key={value.key}>
<Rect
x={value.x}
y={value.y}
width={value.width}
height={value.height}
fill="#cbe9ed"
stroke="black"
/>
<Text
x={textX}
y={textY}
text={
value?.key > 0 ? "box " + value.key.toString() : "box"
}
fontSize={16}
fill="black"
align="center"
verticalAlign="middle"
/>
</React.Fragment>
<Rect
key={value.key}
x={value.x}
y={value.y}
width={value.width}
height={value.height}
fill="transparent"
stroke="black"
/>
);
})}
</Layer>
@@ -1,4 +1,5 @@
import React from "react";
import "../../styles/loader.css";
import { useNavigate } from "react-router-dom";
import { openInNewTab } from "../../constant/Utils";
@@ -31,11 +32,13 @@ const DashboardButton = (props) => {
<span className="rounded-full bg-base-content bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
<i
className={`${
props.Icon ? props.Icon : "fa-light fa-info"
props.Icon ? props.Icon : "fa fa-solid fa-info"
} text-[25px] lg:text-[30px]`}
></i>
</span>
<div className=" text-lg ml-3 text-base-content">{props.Label}</div>
<div className="op-card-title text-lg ml-3 text-base-content">
{props.Label}
</div>
</div>
</div>
);
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react";
import axios from "axios";
import Parse from "parse";
import getReplacedHashQuery from "../../constant/getReplacedHashQuery";
import "../../styles/loader.css";
import { useNavigate } from "react-router-dom";
import Tooltip from "../../primitives/Tooltip";
@@ -261,14 +262,21 @@ const DashboardCard = (props) => {
}
}
body = str;
const response = await axios.post(url, body, { headers: headers });
if (response.data.result.length > 0) {
setresponse(response.data.result[0][props.FilterData.key]);
setLoading(false);
} else {
setresponse("0");
setLoading(false);
}
await axios
.post(url, body, { headers: headers })
.then((response) => {
try {
if (response.data.result.length > 0) {
setresponse(response.data.result[0][props.FilterData.key]);
setLoading(false);
} else {
setresponse("0");
setLoading(false);
}
} catch (error) {
setLoading(false);
}
});
} catch (error) {
setLoading(false);
}
@@ -331,10 +339,10 @@ const DashboardCard = (props) => {
}`}
>
<div className="flex items-center justify-start gap-5 text-white">
<span className="rounded-full bg-base-300 bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
<span className="rounded-full bg-black bg-opacity-20 w-[60px] h-[60px] self-start flex justify-center items-center">
<i
className={`${
props.Icon ? props.Icon : "fa-light fa-info"
props.Icon ? props.Icon : "fa fa-solid fa-info"
} text-[25px] lg:text-[30px]`}
></i>
</span>
@@ -7,13 +7,13 @@ const buttonList = [
label: "Sign yourself",
redirectId: "sHAnZphf69",
redirectType: "Form",
icon: "fa-light fa-pen-nib"
icon: "fas fa-pen-nib"
},
{
label: "Request signature",
redirectId: "8mZzFxbG1z",
redirectType: "Form",
icon: "fa-light fa-paper-plane"
icon: "fa-solid fa-paper-plane"
}
];
const GetDashboard = (props) => {
@@ -1,5 +1,7 @@
import React, { useState, useEffect, useRef } from "react";
import folder from "../../assets/images/folder.png";
import "../../styles/opensigndrive.css";
import pdfLogo from "../../assets/images/pdf3.png";
import axios from "axios";
import * as ContextMenu from "@radix-ui/react-context-menu";
import { saveAs } from "file-saver";
@@ -17,10 +19,10 @@ function DriveBody(props) {
const [selectDoc, setSelectDoc] = useState();
const [isDeleteDoc, setIsDeleteDoc] = useState(false);
const contextMenu = [
{ type: "Download", icon: "fa-light fa-arrow-down" },
{ type: "Rename", icon: "fa-light fa-font" },
{ type: "Move", icon: "fa-light fa-file-export" },
{ type: "Delete", icon: "fa-light fa-trash" }
{ type: "Download", icon: "fa-solid fa-arrow-down" },
{ type: "Rename", icon: "fa-solid fa-font" },
{ type: "Move", icon: "fa-solid fa-file-export" },
{ type: "Delete", icon: "fa-solid fa-trash" }
];
const navigate = useNavigate();
@@ -313,22 +315,17 @@ function DriveBody(props) {
const signerName = getSignersName.join(", ");
return (
<span className="text-[12px] font-medium w-[90%] break-words">
{signerName}
</span>
<span className="statusSpan w-[90%] break-words">{signerName}</span>
);
};
return listType === "table" ? (
data.Type === "Folder" ? (
<tr onClick={() => handleOnclikFolder(data)}>
<td className="cursor-pointer flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[26px] h-[26px] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
<td className="cursor-pointer flex items-center">
<i
className="fa fa-folder mr-[8px] text-[26px] text-[#f0ad26]"
aria-hidden="true"
></i>
<span className="text-[12px] font-medium">{data.Name}</span>
</td>
<td>_</td>
@@ -338,14 +335,8 @@ function DriveBody(props) {
</tr>
) : (
<tr onClick={() => checkPdfStatus(data)}>
<td className="cursor-pointer flex items-center gap-2">
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
className="w-[26px] h-[26px] fill-current op-text-primary"
>
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
</svg>
<td className="cursor-pointer flex items-center">
<i className="fa fa-file-pdf mr-[8px] text-[26px] text-[#ed4d0e]"></i>
<span className="text-[12px] font-medium">{data.Name}</span>
</td>
<td>{createddate}</td>
@@ -357,29 +348,23 @@ function DriveBody(props) {
e.stopPropagation();
handleMenuItemClick("Download", data);
}}
className="fa-light fa-download mr-[8px] op-text-primary"
className="fa fa-download mr-[8px] text-[#ed280e]"
aria-hidden="true"
></i>
</td>
</tr>
)
) : listType === "list" && data.Type === "Folder" ? (
<div key={ind} className="relative w-[100px] h-[100px] mx-2 my-3">
<div key={ind} className="icon-container">
<ContextMenu.Root>
<ContextMenu.Trigger className="flex flex-col justify-center items-center">
{/* folder */}
<div
data-tut={props.dataTutSeventh}
onClick={() => handleOnclikFolder(data)}
className="cursor-pointer"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[100px] h-[100px] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
<ContextMenu.Trigger className="ContextMenuTrigger">
<div data-tut={props.dataTutSeventh}>
<img
alt="folder"
onClick={() => handleOnclikFolder(data)}
src={folder}
className="w-full h-full"
/>
{rename === data.objectId ? (
<input
onFocus={() => {
@@ -400,7 +385,7 @@ function DriveBody(props) {
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
/>
) : (
<span className="fileName">{data.Name}</span>
<span className="foldName">{data.Name}</span>
)}
</div>
</ContextMenu.Trigger>
@@ -415,7 +400,7 @@ function DriveBody(props) {
onClick={() => handleMenuItemClick("Rename", data)}
className="ContextMenuItem"
>
<i className="fa-light fa-font mr-[8px]"></i>
<i className="fa-solid fa-font mr-[8px]"></i>
<span>Rename</span>
</ContextMenu.Item>
</ContextMenu.Content>
@@ -427,65 +412,58 @@ function DriveBody(props) {
<HoverCard.Trigger asChild>
<div>
<ContextMenu.Root>
<div className="relative w-[100px] h-[100px] mx-2 my-3">
<ContextMenu.Trigger className="flex flex-col justify-center items-center">
{/* pdf */}
<div
data-tut={props.dataTutSixth}
<div className="icon-container">
<ContextMenu.Trigger className="ContextMenuTrigger">
<img
alt="PDF"
className="w-full h-full"
src={pdfLogo}
onClick={() => checkPdfStatus(data)}
className="cursor-pointer"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
className="w-[100px] h-[100px] fill-current op-text-primary"
>
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
</svg>
{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)}
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
/>
) : (
<span className="fileName">{data.Name}</span>
)}
</div>
data-tut={props.dataTutSixth}
/>
{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)}
className="w-[100px] border-[1.5px] border-black rounded-sm text-[10px]"
/>
) : (
<span className="fileName">{data.Name}</span>
)}
</ContextMenu.Trigger>
{status === "Completed" ? (
<div className="status-badge completed">
<i className="fa-light fa-check-circle"></i>
<i className="fas fa-check-circle"></i>
</div>
) : status === "Declined" ? (
<div className="status-badge declined">
<i className="fa-light fa-thumbs-down"></i>
<i className="fa fa-thumbs-down"></i>
</div>
) : status === "Expired" ? (
<div className="status-badge expired">
<i className="fa-light fa-hourglass-end"></i>
<i className="fa fa-hourglass-end"></i>
</div>
) : status === "Draft" ? (
<div className="status-badge draft">
<i className="fa-light fa-file"></i>
<i className="fa fa-file"></i>
</div>
) : (
status === "In Progress" && (
<div className="status-badge in-progress">
<i className="fa-light fa-paper-plane"></i>
<i className="fa fa-paper-plane"></i>
</div>
)
)}
@@ -517,17 +495,21 @@ function DriveBody(props) {
<HoverCard.Portal>
<HoverCard.Content className="HoverCardContent" sideOffset={5}>
<strong className="text-[13px]">Title: </strong>
<span className="text-[12px] font-medium mb-0"> {data.Name}</span>
<span className="statusSpan" style={{ marginBottom: "0px" }}>
{" "}
{data.Name}
</span>
<br />
<strong className="text-[13px]">Status: </strong>
<span className="text-[12px] font-medium"> {status}</span>
<span className="statusSpan"> {status}</span>
<br />
<strong className="text-[13px]">Created Date: </strong>
<span className="text-[12px] font-medium">{createddate}</span>
<span className="statusSpan">{createddate}</span>
<br />
{signerExist && (
<>
<strong className="text-[13px]">Signers: </strong>
{/* <span className="statusSpan">kjefjjnejkfnkbjs bbfjkdsbjbfjkbjk kscbjkbjkb</span> */}
{signersName()}
</>
)}
@@ -3,9 +3,13 @@ import React from "react";
function BorderResize({ right, top }) {
return (
<div
className={`${right ? `-right-[12px]` : "-right-[1px]"} ${
top ? `-bottom-[11px]` : "-bottom-[1px]"
} absolute inline-block w-[14px] h-[14px] hover:cursor-sw-resize border-r-[3px] border-b-[3px] border-[#188ae2]`}
className="borderResize"
style={{
right: right ? right + "px" : "-1px",
bottom: top ? top + "px" : "-1px",
borderRight: "3px solid #188ae2",
borderBottom: "3px solid #188ae2"
}}
></div>
);
}
@@ -205,14 +205,14 @@ function DropdownWidgetOption(props) {
/>
<i
className="fa-light fa-rectangle-xmark text-[25px] ml-[10px] text-accent cursor-pointer"
className="fa-solid fa-rectangle-xmark text-[25px] ml-[10px] text-error"
onClick={() => handleDeleteInput(index)}
></i>
</div>
))}
<i
onClick={handleAddInput}
className="fa-light fa-square-plus text-[25px] ml-[10px] op-text-primary cursor-pointer"
className="fa-solid fa-square-plus text-[25px] ml-[10px] text-primary"
></i>
<div>
{props.type === "checkbox" && !props.isSignYourself && (
@@ -61,7 +61,7 @@ const EditTemplate = ({ template, onSuccess }) => {
<div className="max-h-[300px] md:max-h-[400px] overflow-y-scroll p-[10px]">
<div className="text-base-content">
<form onSubmit={handleSubmit}>
<div className="mb-[0.35rem]">
<div>
<label htmlFor="name" className="text-[13px]">
File
</label>
@@ -69,7 +69,7 @@ const EditTemplate = ({ template, onSuccess }) => {
{getFileName(template.URL)}
</div>
</div>
<div className="mb-[0.35rem]">
<div className="form-section">
<label htmlFor="name" className="text-[13px]">
Name
<span className="text-[13px] text-[red]"> *</span>
@@ -83,7 +83,7 @@ const EditTemplate = ({ template, onSuccess }) => {
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-[0.35rem]">
<div className="form-section">
<label htmlFor="Note" className="text-[13px]">
Note
</label>
@@ -96,7 +96,7 @@ const EditTemplate = ({ template, onSuccess }) => {
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-[0.35rem]">
<div className="form-section">
<label htmlFor="Description" className="text-[13px]">
Description
</label>
@@ -109,7 +109,7 @@ const EditTemplate = ({ template, onSuccess }) => {
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<div className="mb-[0.35rem]">
<div className="form-section">
<label className="text-[13px]">Send In Order</label>
<div className="flex items-center gap-[8px] ml-[8px] mb-[5px]">
<input
@@ -138,7 +138,7 @@ const EditTemplate = ({ template, onSuccess }) => {
{!isEnableSubscription && (
<PremiumAlertHeader
message={
"Auto reminder is free in beta, this feature will incur a fee later."
"Disable Auto reminder is free in beta, this feature will incur a fee later."
}
/>
)}
+137 -127
View File
@@ -1,11 +1,11 @@
import React, { useState } from "react";
import { saveAs } from "file-saver";
import celebration from "../../assets/images/newCeleb.gif";
import axios from "axios";
import { getBase64FromUrl } from "../../constant/Utils";
import { themeColor } from "../../constant/const";
import printModule from "print-js";
import Loader from "../../primitives/Loader";
import ModalUi from "../../primitives/ModalUi";
function EmailComponent({
isEmail,
@@ -21,6 +21,7 @@ function EmailComponent({
const [emailList, setEmailList] = useState([]);
const [emailValue, setEmailValue] = useState();
const [isLoading, setIsLoading] = useState(false);
const [isEmailCelebration, setIsEmailCelebration] = useState(false);
//function for send email
const sendEmail = async () => {
setIsLoading(true);
@@ -61,6 +62,10 @@ function EmailComponent({
" target=_blank>here</a> </p></div></div></body></html>"
};
sendMail = await axios.post(url, params, { headers: headers });
setIsEmailCelebration(true);
setTimeout(() => {
setIsEmailCelebration(false);
}, 3000);
} catch (error) {
console.log("error", error);
setIsLoading(false);
@@ -165,141 +170,146 @@ function EmailComponent({
<div>
{/* isEmail */}
{isEmail && (
<ModalUi isOpen showHeader={false}>
{isLoading && (
<div className="absolute w-full h-full flex flex-col justify-center items-center z-[20] bg-[#e6f2f2]/70">
<Loader />
<span className="text-[12px] text-base-content">
This might take some time
</span>
</div>
)}
<div className="flex justify-between items-center py-[10px] px-[20px] border-b-[1px] border-base-content">
<span className="text-base-content font-semibold">
Successfully signed!
</span>
<div className="flex flex-row">
<div></div>
{!isAndroid && (
<div className="modaloverlay">
<div className="modalcontainer">
{isLoading && (
<div className="absolute w-full h-full flex flex-col justify-center items-center z-[20] bg-[#e6f2f2] bg-opacity-80">
<Loader />
<span className="text-[12px] font-bold">
This might take some time
</span>
</div>
)}
<div style={{ background: "#32a3ac" }} className="modalheader">
<span className="text-white">Successfully signed!</span>
<div className="flex flex-row">
<div></div>
{!isAndroid && (
<button
onClick={handleToPrint}
className="op-btn op-btn-neutral op-btn-sm text-[15px]"
>
<i className="fa fa-print" aria-hidden="true"></i>
Print
</button>
)}
<button
onClick={handleToPrint}
className="op-btn op-btn-neutral op-btn-sm text-[15px]"
className="op-btn op-btn-primary op-btn-sm text-[15px] ml-2"
onClick={() => handleDownloadPdf()}
>
<i className="fa-light fa-print" aria-hidden="true"></i>
Print
<i className="fa fa-download" aria-hidden="true"></i>
Download
</button>
</div>
</div>
<div className="h-full p-[20px]">
{isEmailCelebration && (
<div className="absolute w-[100%] flex justify-center items-center">
<img alt="celeb" width={300} height={250} src={celebration} />
</div>
)}
<p className="font-medium text-[15px] mb-[5px] text-base-content align-baseline">
Recipients added here will get a copy of the signed document.
</p>
{emailList.length > 0 ? (
<>
<div className="addEmail">
<div className="flex flex-row flex-wrap">
{emailList.map((data, ind) => {
return (
<div
className="flex flex-row items-center bg-[#47a3ad] m-[4px] rounded-md py-[5px] px-[10px]"
key={ind}
>
<span className="text-white text-[13px]">
{data}
</span>
<span
className="text-white text-[13px] font-semibold ml-[7px] cursor-pointer"
onClick={() => removeChip(ind)}
>
<i className="fa-solid fa-xmark"></i>
</span>
</div>
);
})}
</div>
{emailList.length <= 9 && (
<input
type="text"
value={emailValue}
className="p-[10px] pb-[20px] rounded w-full text-[15px] bg-white outline-none"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
required
/>
)}
</div>
</>
) : (
<div>
<input
type="text"
value={emailValue}
className="p-[10px] pb-[20px] rounded w-full text-[15px] outline-none bg-white border-2 border-[#47a3ad]"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
placeholder="Add the email addresses"
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
required
/>
</div>
)}
<button
className="op-btn op-btn-primary op-btn-sm text-[15px] ml-2"
onClick={() => handleDownloadPdf()}
className={`${
emailValue ? "cursor-pointer" : "cursor-default"
} op-btn op-btn-primary op-btn-sm m-2 shadow-md`}
onClick={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
>
<i className="fa-light fa-download" aria-hidden="true"></i>
Download
<i className="fa fa-plus" aria-hidden="true"></i>
</button>
<div className="bg-[#e3e2e1] mt-[10px] p-[5px] rounded">
<span className="font-bold">Note: </span>
<span className="text-[15px]">
You can only send to ten recipients at a time.
</span>
</div>
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
<button
type="button"
className="op-btn op-btn-primary"
onClick={() => emailList.length > 0 && sendEmail()}
>
Send
</button>
<button
type="button"
className="op-btn op-btn-ghost ml-2"
onClick={() => {
setIsEmail(false);
setEmailValue("");
setEmailList([]);
}}
>
Close
</button>
</div>
</div>
<div className="h-full p-[20px]">
<p className="font-medium text-[15px] mb-[5px] text-base-content align-baseline">
Recipients added here will get a copy of the signed document.
</p>
{emailList.length > 0 ? (
<>
<div className="p-0 border-[1.5px] op-border-primary rounded w-full text-[15px]">
<div className="flex flex-row flex-wrap">
{emailList.map((data, ind) => {
return (
<div
className="flex flex-row items-center op-bg-primary m-[4px] rounded-md py-[5px] px-[10px]"
key={ind}
>
<span className="text-base-100 text-[13px]">
{data}
</span>
<span
className="text-base-100 text-[13px] font-semibold ml-[7px] cursor-pointer"
onClick={() => removeChip(ind)}
>
<i className="fa-light fa-xmark"></i>
</span>
</div>
);
})}
</div>
{emailList.length <= 9 && (
<input
type="text"
value={emailValue}
className="p-[10px] pb-[20px] rounded w-full text-[15px] bg-transparent outline-none"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
required
/>
)}
</div>
</>
) : (
<div>
<input
type="text"
value={emailValue}
className="p-[10px] pb-[20px] rounded w-full text-[15px] outline-none bg-transparent border-[1.5px] op-border-primary"
onChange={handleEmailValue}
onKeyDown={handleEnterPress}
placeholder="Add the email addresses"
onBlur={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
required
/>
</div>
)}
<button
className={`${
emailValue ? "cursor-pointer" : "cursor-default"
} op-btn op-btn-primary op-btn-sm m-2 shadow-md`}
onClick={() => {
if (emailValue) {
handleEnterPress("add");
}
}}
>
<i className="fa-light fa-plus" aria-hidden="true"></i>
</button>
<div className="bg-[#e3e2e1] mt-[10px] p-[5px] rounded">
<span className="font-bold">Note: </span>
<span className="text-[15px]">
You can only send to ten recipients at a time.
</span>
</div>
<hr className="w-full my-[15px] bg-base-content" />
<button
type="button"
className="op-btn op-btn-secondary"
onClick={() => emailList.length > 0 && sendEmail()}
>
Send
</button>
<button
type="button"
className="op-btn op-btn-ghost ml-2"
onClick={() => {
setIsEmail(false);
setEmailValue("");
setEmailList([]);
}}
>
Close
</button>
</div>
</ModalUi>
</div>
)}
</div>
);
+47 -56
View File
@@ -29,6 +29,7 @@ function Header({
isShowHeader,
decline,
currentSigner,
dataTut4,
alreadySign,
isSignYourself,
setIsEmail,
@@ -52,7 +53,7 @@ function Header({
};
return (
<div className="flex py-[5px]">
<div style={{ padding: "5px 0px 5px 0px" }} className="mobileHead">
{isMobile && isShowHeader ? (
<div
id="navbar"
@@ -66,7 +67,7 @@ function Header({
<div className="flex justify-between items-center py-[5px] px-[10px] ">
<div onClick={() => navigate(-1)}>
<i
className="fa-light fa-arrow-left text-base-content"
className="fa fa-arrow-left text-base-content"
aria-hidden="true"
></i>
</div>
@@ -79,10 +80,7 @@ function Header({
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<div className="op-link op-link-primary no-underline text-[16px] font-semibold pr-[3px] pl-[5px]">
<i
className="fa-light fa-ellipsis-v"
aria-hidden="true"
></i>
<i className="fa fa-ellipsis-v" aria-hidden="true"></i>
</div>
</DropdownMenu.Trigger>
<DropdownMenu.Portal>
@@ -98,7 +96,7 @@ function Header({
>
<div className="flex flex-row">
<i
className="fa-light fa-arrow-down mr-[3px]"
className="fa fa-arrow-down mr-[2px]"
aria-hidden="true"
></i>
Download
@@ -116,7 +114,7 @@ function Header({
>
<div className="border-none bg-[#fff]">
<i
className="fa-light fa-award mr-[3px]"
className="fa-solid fa-award mr-[2px]"
aria-hidden="true"
></i>
Certificate
@@ -130,7 +128,7 @@ function Header({
>
<div className="flex flex-row">
<i
className="fa-light fa-envelope mr-[3px]"
className="fa fa-envelope mr-[2px]"
aria-hidden="true"
></i>
Mail
@@ -145,7 +143,7 @@ function Header({
>
<div className="flex flex-row">
<i
className="fa-light fa-print mr-[3px]"
className="fa fa-print mr-[2px]"
aria-hidden="true"
></i>
Print
@@ -179,7 +177,7 @@ function Header({
className={`${
isMailSend ? "" : "op-link-primary"
} op-link no-underline font-[650] text-[14px]`}
data-tut="headerArea"
data-tut={dataTut4}
>
{completeBtnTitle ? completeBtnTitle : "Send"}
</div>
@@ -200,9 +198,9 @@ function Header({
)}
<DropdownMenu.Root>
<DropdownMenu.Trigger asChild>
<div className="font-[650] text-[18px] px-2 ml-[4px] text-base-content no-underline">
<div className="font-[650] text-[18px] px-2 ml-[4px] op-link op-link-info no-underline">
<i
className="fa-light fa-ellipsis-v"
className="fa fa-ellipsis-v"
aria-hidden="true"
></i>
</div>
@@ -223,7 +221,7 @@ function Header({
}
>
<i
className="fa-light fa-arrow-down mr-[3px]"
className="fa fa-arrow-down mr-[5px]"
aria-hidden="true"
></i>
<span className="font-[500]">Download</span>
@@ -238,7 +236,7 @@ function Header({
</div>
</div>
) : (
<div className="flex flex-wrap justify-between items-center w-full gap-y-1 ml-1">
<div className="flex flex-wrap justify-between items-center mt-[5px]">
<PrevNext
pageNumber={pageNumber}
allPages={allPages}
@@ -269,22 +267,22 @@ function Header({
{setIsEditTemplate && (
<button
onClick={() => setIsEditTemplate(true)}
className="outline-none border-none text-center mr-[3px]"
className="outline-none border-none text-center mr-[5px]"
>
<i className="fa-light fa-gear fa-lg"></i>
<i className="fa-solid fa-gear fa-lg"></i>
</button>
)}
<button
onClick={() => navigate(-1)}
type="button"
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
className="op-btn op-btn-ghost op-btn-sm mr-[5px]"
>
Back
</button>
<button
disabled={isMailSend && true}
data-tut="headerArea"
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
data-tut="reactourFour"
className="op-btn op-btn-primary op-btn-sm mr-[5px]"
onClick={() => alertSendEmail()}
>
{completeBtnTitle
@@ -304,10 +302,10 @@ function Header({
onClick={() =>
handleDownloadCertificate(pdfDetails, setIsDownloading)
}
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
className="op-btn op-btn-secondary op-btn-sm mr-[5px] shadow"
>
<i
className="fa-light fa-award py-[3px]"
className="fa-solid fa-award py-[3px]"
aria-hidden="true"
></i>
<span className="hidden lg:block">Certificate</span>
@@ -317,26 +315,20 @@ function Header({
<button
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
type="button"
className="op-btn op-btn-neutral op-btn-sm mr-[3px] shadow"
className="op-btn op-btn-neutral op-btn-sm mr-[5px] shadow"
>
<i
className="fa-light fa-print py-[3px]"
aria-hidden="true"
></i>
<i className="fa fa-print py-[3px]" aria-hidden="true"></i>
<span className="hidden lg:block">Print</span>
</button>
<button
type="button"
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
className="op-btn op-btn-primary op-btn-sm mr-[5px] shadow"
onClick={() =>
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
}
>
<i
className="fa-light fa-download py-[3px]"
aria-hidden="true"
></i>
<i className="fa fa-download py-[3px]" aria-hidden="true"></i>
<span className="hidden lg:block">Download</span>
</button>
</div>
@@ -345,21 +337,21 @@ function Header({
<button
onClick={() => navigate(-1)}
type="button"
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
className="op-btn op-btn-ghost op-btn-sm mr-[5px]"
>
Back
</button>
{currentSigner && (
<>
<button
className="op-btn op-btn-secondary op-btn-sm mr-[3px] shadow"
className="op-btn op-btn-secondary op-btn-sm mr-[5px] shadow"
onClick={() => handleDeclinePdfAlert()}
>
Decline
</button>
<button
type="button"
className="op-btn op-btn-primary op-btn-sm mr-[3px] shadow"
className="op-btn op-btn-primary op-btn-sm mr-[5px] shadow"
onClick={() => embedWidgetsData()}
>
Finish
@@ -370,10 +362,7 @@ function Header({
role="button"
className="op-btn op-btn-info op-btn-sm shadow"
>
<i
className="fa-light fa-ellipsis-v"
aria-hidden="true"
></i>
<i className="fa fa-ellipsis-v" aria-hidden="true"></i>
</div>
<ul
tabIndex={0}
@@ -390,7 +379,7 @@ function Header({
>
<span className="font-semibold text-[12px]">
<i
className="fa-light fa-arrow-down"
className="fa fa-arrow-down"
aria-hidden="true"
></i>{" "}
Download
@@ -410,37 +399,37 @@ function Header({
onClick={() =>
handleDownloadCertificate(pdfDetails, setIsDownloading)
}
className="op-btn op-btn-secondary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
className="op-btn op-btn-secondary op-btn-sm font-medium text-[13px] mr-[5px] shadow"
>
<i className="fa-light fa-award" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Certificate</span>
<i className="fa-solid fa-award" aria-hidden="true"></i>
<span className="hidden lg:block">Certificate</span>
</button>
)}
<button
onClick={(e) => handleToPrint(e, pdfUrl, setIsDownloading)}
type="button"
className="op-btn op-btn-neutral op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
className="op-btn op-btn-neutral op-btn-sm font-medium text-[13px] mr-[5px] shadow"
>
<i className="fa-light fa-print" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Print</span>
<i className="fa fa-print" aria-hidden="true"></i>
<span className="hidden lg:block">Print</span>
</button>
<button
type="button"
className="op-btn op-btn-primary op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
className="op-btn op-btn-primary op-btn-sm font-medium text-[13px] mr-[5px] shadow"
onClick={() =>
handleDownloadPdf(pdfDetails, pdfUrl, setIsDownloading)
}
>
<i className="fa-light fa-download" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Download</span>
<i className="fa fa-download" aria-hidden="true"></i>
<span className="hidden lg:block">Download</span>
</button>
<button
type="button"
className="op-btn op-btn-info op-btn-sm gap-0 font-medium text-[12px] mr-[3px] shadow"
className="op-btn op-btn-info op-btn-sm font-medium text-[13px] mr-[5px] shadow"
onClick={() => setIsEmail(true)}
>
<i className="fa-light fa-envelope" aria-hidden="true"></i>
<span className="hidden lg:block ml-1">Mail</span>
<i className="fa fa-envelope" aria-hidden="true"></i>
<span className="hidden lg:block">Mail</span>
</button>
</div>
) : (
@@ -448,13 +437,13 @@ function Header({
<button
onClick={() => navigate(-1)}
type="button"
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
className="op-btn op-btn-ghost op-btn-sm mr-[5px]"
>
Back
</button>
<button
type="button"
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
className="op-btn op-btn-primary op-btn-sm mr-[5px]"
onClick={() => {
if (!pdfUrl) {
embedWidgetsData();
@@ -485,8 +474,10 @@ function Header({
{isDownloading === "certificate"}{" "}
<p>
Your completion certificate is being generated. Please wait
momentarily. If the download doesn&apos;t start shortly, click the
button again.
momentarily.
</p>
<p>
If the download doesn&apos;t start shortly, click the button again.
</p>
</div>
</ModalUi>
@@ -1,53 +0,0 @@
import React from "react";
function PdfZoom(props) {
const onClickZoomIn = () => {
props.setScale(props.scale + 0.1 * props.scale);
props.setZoomPercent(props.zoomPercent + 10);
};
const onClickZoomOut = () => {
if (props.zoomPercent > 0) {
if (props.zoomPercent === 10) {
props.setScale(1);
} else {
props.setScale(props.scale - 0.1 * props.scale);
}
props.setZoomPercent(props.zoomPercent - 10);
}
};
const handleReset = () => {
props.setScale(1);
props.setZoomPercent(0);
};
return (
// md:mt-[41px] xl:mt-[63px]mt=[]
<span className="hidden md:flex flex-col gap-1 text-center md:w-[5%] mt-[50px] 2xl:mt-[63px]">
<span
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
onClick={onClickZoomIn}
title="Zoom in"
>
<i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px]"></i>
</span>
<span
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
onClick={handleReset}
title="Reset"
>
<i className="fa-light fa-magnifying-glass-arrows-rotate text-gray-500 2xl:text-[30px]"></i>
</span>
<span
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px]"
onClick={onClickZoomOut}
style={{
cursor: props.zoomPercent > 0 ? "pointer" : "default"
}}
title="Zoom out"
>
<i className="fa-light fa-magnifying-glass-minus text-gray-500 2xl:text-[30px]"></i>
</span>
</span>
);
}
export default PdfZoom;
+41 -138
View File
@@ -5,7 +5,7 @@ import { Rnd } from "react-rnd";
import {
defaultWidthHeight,
handleCopyNextToWidget,
isTabAndMobile,
isMobile,
onChangeInput,
radioButtonWidget,
textInputWidget,
@@ -88,10 +88,8 @@ const getDefaultdate = (selectedDate, format = "dd-MM-yyyy") => {
const getDefaultFormat = (dateFormat) => dateFormat || "MM/dd/yyyy";
function Placeholder(props) {
const [placeholderBorder, setPlaceholderBorder] = useState({ w: 0, h: 0 });
const [isDraggingEnabled, setDraggingEnabled] = useState(true);
const [isShowDateFormat, setIsShowDateFormat] = useState(false);
const [containerScale, setContainerScale] = useState();
const [selectDate, setSelectDate] = useState({
date:
props.pos.type === "date"
@@ -121,14 +119,6 @@ function Placeholder(props) {
width: null,
height: null
});
useEffect(() => {
const getPdfPageWidth = props.pdfOriginalWH.find(
(data) => data.pageNumber === props.pageNumber
);
setContainerScale(props.containerWH.width / getPdfPageWidth.width);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [props.containerWH.width, props.pdfOriginalWH]);
const dateFormatArr = [
"L",
"DD-MM-YYYY",
@@ -303,27 +293,12 @@ function Placeholder(props) {
props?.setShowDropdown(true);
} else if (props.pos.type === "checkbox") {
props?.setIsCheckbox(true);
} else if (
[
textInputWidget,
textWidget,
"name",
"company",
"job title",
"email"
].includes(props.pos.type)
) {
props.handleTextSettingModal(true);
} else {
props?.handleNameModal && props?.handleNameModal(true);
props?.handleNameModal(true);
}
if (props.data && props?.pos?.type !== textWidget) {
props.setSignerObjId(props?.data?.signerObjId);
props.setUniqueId(props?.data?.Id);
} else if (props.data && props.pos.type === textWidget) {
props.setTempSignerId(props.uniqueId);
props.setUniqueId(props?.data?.Id);
if (props.isPlaceholder && props.type !== textWidget) {
props.setUniqueId(props.data.Id);
}
props.setSignKey(props.pos.key);
props.setWidgetType(props.pos.type);
@@ -400,15 +375,7 @@ function Placeholder(props) {
<>
{(props.isPlaceholder || props.isSignYourself) && (
<>
{[
"checkbox",
textInputWidget,
textWidget,
"name",
"company",
"job title",
"email"
].includes(props.pos.type) && props.isSignYourself ? (
{props.pos.type === "checkbox" && props.isSignYourself ? (
<i
onClick={(e) => {
e.stopPropagation();
@@ -418,7 +385,7 @@ function Placeholder(props) {
e.stopPropagation();
handleOnClickSettingIcon();
}}
className="fa-light fa-gear icon"
className="fa-solid fa-gear settingIcon"
style={{
color: "#188ae2",
right: "29px",
@@ -428,7 +395,9 @@ function Placeholder(props) {
) : (
((!props?.pos?.type && props.pos.isStamp) ||
(props?.pos?.type &&
!["date", "signature"].includes(props.pos.type) &&
!["date", textWidget, "signature"].includes(
props.pos.type
) &&
!props.isSignYourself)) && (
<i
onClick={(e) => {
@@ -439,12 +408,8 @@ function Placeholder(props) {
e.stopPropagation();
handleOnClickSettingIcon();
}}
className="fa-light fa-gear icon"
style={{
color: "#188ae2",
right: props?.pos?.type === textWidget ? "32px" : "47px",
top: "-19px"
}}
className="fa-solid fa-gear settingIcon"
style={{ color: "#188ae2", right: "47px", top: "-19px" }}
></i>
)
)}
@@ -452,7 +417,7 @@ function Placeholder(props) {
{props.pos.type !== textWidget && !props.isSignYourself && (
<i
data-tut="assignSigner"
className="fa-light fa-user icon"
className="fa-regular fa-user signUserIcon"
onClick={(e) => {
e.stopPropagation();
props.handleLinkUser(props.data.Id);
@@ -476,7 +441,11 @@ function Placeholder(props) {
top: "-19px",
right: props.isPlaceholder ? "60px" : "44px"
}}
className={`${isShowDateFormat ? "show" : ""} dropdown icon`}
className={
isShowDateFormat
? "dropdown signUserIcon show"
: "dropdown signUserIcon"
}
onClick={(e) => {
setIsShowDateFormat(!isShowDateFormat);
e.stopPropagation();
@@ -495,7 +464,7 @@ function Placeholder(props) {
}}
>
<i
className="fa-light fa-gear icon"
className="fa-solid fa-gear settingIcon"
style={{
color: "#188ae2",
fontSize: "14px"
@@ -523,7 +492,8 @@ function Placeholder(props) {
setSelectDate(data);
handleSaveDate(data);
}}
className="dropdown-item text-[13px]"
className="dropdown-item itemColor"
style={{ fontSize: "12px" }}
>
{data?.date ? data?.date : "nodata"}
</span>
@@ -533,13 +503,13 @@ function Placeholder(props) {
</div>
)}
<i
className="fa-light fa-copy icon"
className="fa-regular fa-copy signCopy"
onClick={(e) => handleCopyPlaceholder(e)}
onTouchEnd={(e) => handleCopyPlaceholder(e)}
style={{ color: "#188ae2", right: "12px", top: "-18px" }}
></i>
<i
className="fa-light fa-circle-xmark icon"
className="fa-regular fa-circle-xmark signCloseBtn"
onClick={(e) => {
e.stopPropagation();
@@ -565,61 +535,6 @@ function Placeholder(props) {
)
);
};
const xPos = (pos, signYourself) => {
const getPdfPageWidth = props.pdfOriginalWH.find(
(data) => data.pageNumber === props.pageNumber
);
const containerScale = props.containerWH.width / getPdfPageWidth?.width;
const resizePos = pos.xPosition;
if (signYourself) {
return resizePos * containerScale * props.scale;
} else {
//checking both condition mobile and desktop view
if (pos.isMobile && pos.scale) {
if (props.scale > 1) {
return resizePos * pos.scale * containerScale * props.scale;
} else {
return resizePos * pos.scale * containerScale;
}
} else {
// if (pos.scale === containerScale) {
// return resizePos * pos.scale * props.scale;
// } else {
return resizePos * containerScale * props.scale;
// }
}
}
};
const yPos = (pos, signYourself) => {
const getPdfPageWidth = props.pdfOriginalWH.find(
(data) => data.pageNumber === props.pageNumber
);
const containerScale = props.containerWH.width / getPdfPageWidth.width;
const resizePos = pos.yPosition;
if (signYourself) {
return resizePos * containerScale * props.scale;
} else {
//checking both condition mobile and desktop view
if (pos.isMobile && pos.scale) {
if (props.scale > 1) {
return resizePos * pos.scale * containerScale * props.scale;
} else {
return resizePos * pos.scale * containerScale;
}
}
// else if (pos.scale === containerScale) {
// if (props.scale > 1) {
// return resizePos * pos.scale * props.scale;
// } else {
// return resizePos * pos.scale;
// }
// }
else {
return resizePos * containerScale * props.scale;
}
}
};
return (
<Rnd
@@ -705,20 +620,8 @@ function Placeholder(props) {
setDraggingEnabled(true);
props.setIsResize && props.setIsResize(true);
}}
onResizeStop={(e, direction, ref) => {
onResizeStop={() => {
props.setIsResize && props.setIsResize(false);
props.handleSignYourselfImageResize &&
props.handleSignYourselfImageResize(
ref,
props.pos.key,
props.xyPostion,
props.setXyPostion,
props.index,
containerScale,
props.scale,
props.data && props.data.Id,
props.isResize
);
}}
disableDragging={
props.isNeedSign
@@ -731,15 +634,21 @@ function Placeholder(props) {
props.handleStop &&
props.handleStop(event, dragElement, props.data?.Id, props.pos?.key)
}
position={{
x: xPos(props.pos, props.isSignYourself),
y: yPos(props.pos, props.isSignYourself)
default={{
x: props.xPos(props.pos, props.isSignYourself),
y: props.yPos(props.pos, props.isSignYourself)
}}
onResize={(e, direction, ref) => {
setPlaceholderBorder({
w: ref.offsetWidth / (props.scale * containerScale),
h: ref.offsetHeight / (props.scale * containerScale)
});
props.handleSignYourselfImageResize &&
props.handleSignYourselfImageResize(
ref,
props.pos.key,
props.xyPostion,
props.setXyPostion,
props.index,
props.data && props.data.Id,
false
);
}}
onClick={() => handleOnClickPlaceholder()}
>
@@ -768,23 +677,20 @@ function Placeholder(props) {
pos={props.pos}
isPlaceholder={props.isPlaceholder}
getCheckboxRenderWidth={getCheckboxRenderWidth}
scale={props.scale}
containerScale={containerScale}
placeholderBorder={placeholderBorder}
/>
)}
{isTabAndMobile ? (
{isMobile ? (
<div
// className="sm:inline-block md:inline-block lg:hidden "
className="flex items-stretch"
style={{
left: xPos(props.pos, props.isSignYourself),
top: yPos(props.pos, props.isSignYourself),
left: props.xPos(props.pos, props.isSignYourself),
top: props.yPos(props.pos, props.isSignYourself),
width:
props.pos.type === radioButtonWidget ||
props.pos.type === "checkbox"
? "auto"
: props.posWidth(props.pos, props.isSignYourself),
// "auto", //props.posWidth(props.pos, props.isSignYourself),
// height: props.posHeight(props.pos, props.isSignYourself),
height:
props.pos.type === radioButtonWidget ||
props.pos.type === "checkbox"
@@ -793,7 +699,6 @@ function Placeholder(props) {
zIndex: "10"
}}
onTouchEnd={() => handleOnClickPlaceholder()}
onClick={() => handleOnClickPlaceholder()}
>
{props.pos.key === props.selectWidgetId && <PlaceholderIcon />}
@@ -818,7 +723,6 @@ function Placeholder(props) {
setStartDate={setStartDate}
startDate={startDate}
handleSaveDate={handleSaveDate}
xPos={props.xPos}
/>
</div>
) : (
@@ -845,7 +749,6 @@ function Placeholder(props) {
setStartDate={setStartDate}
startDate={startDate}
handleSaveDate={handleSaveDate}
xPos={props.xPos}
/>
</>
)}
@@ -11,34 +11,23 @@ function PlaceholderBorder(props) {
const getResizeBorderExtraWidth = resizeBorderExtraWidth();
const defaultWidth = defaultWidthHeight(props.pos.type).width;
const defaultHeight = defaultWidthHeight(props.pos.type).height;
const width = () => {
const getWidth =
props.placeholderBorder.w || props.pos.Width || defaultWidth;
return (
getWidth * props.scale * props.containerScale + getResizeBorderExtraWidth
);
};
const height = () => {
const getHeight =
props.placeholderBorder.h || props.pos.Height || defaultHeight;
return (
getHeight * props.scale * props.containerScale + getResizeBorderExtraWidth
);
};
const handleMinWidth = () => {
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
return props.getCheckboxRenderWidth.width + getResizeBorderExtraWidth;
} else {
return width();
return props.pos.Width
? props.pos.Width + getResizeBorderExtraWidth
: defaultWidth + getResizeBorderExtraWidth;
}
};
const handleMinHeight = () => {
if (props.pos.type === "checkbox" || props.pos.type === radioButtonWidget) {
return props.getCheckboxRenderWidth.height + getResizeBorderExtraWidth;
} else {
return height();
return props.pos.Height
? props.pos.Height + getResizeBorderExtraWidth
: defaultHeight + getResizeBorderExtraWidth;
}
};
return (
@@ -47,7 +36,7 @@ function PlaceholderBorder(props) {
onTouchEnd={() =>
props.pos.type === textWidget && props?.setDraggingEnabled(true)
}
className="absolute inline-block w-[14px] h-[14px] hover:cursor-sw-resize"
className="borderResize"
style={{
borderColor: themeColor,
borderStyle: "dashed",
@@ -5,6 +5,7 @@ import { randomId, textWidget } from "../../constant/Utils";
function PlaceholderCopy(props) {
const copyType = ["All pages", "All pages but last", "All pages but first"];
const [selectCopyType, setSelectCopyType] = useState("");
//function for get copy placeholder position
const getCopyPlaceholderPosition = (
type,
@@ -2,6 +2,7 @@ import React, { useEffect, useState, forwardRef, useRef } from "react";
import {
getMonth,
getYear,
isMobile,
onChangeHeightOfTextArea,
onChangeInput,
radioButtonWidget,
@@ -13,10 +14,7 @@ import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
import "../../styles/signature.css";
import RegexParser from "regex-parser";
const textWidgetCls =
"w-full h-full md:min-w-full md:min-h-full z-[999] text-[12px] rounded-[2px] border-[1px] border-[#007bff] overflow-hidden resize-none outline-none text-base-content item-center bg-base-100 whitespace-pre-wrap";
const selectWidgetCls =
"w-full h-full absolute left-0 top-0 border-[1px] border-[#007bff] rounded-[2px] focus:outline-none bg-base-100 text-base-content";
function PlaceholderType(props) {
const type = props?.pos?.type;
const [selectOption, setSelectOption] = useState("");
@@ -139,13 +137,13 @@ function PlaceholderType(props) {
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
<div
className={`${selectWidgetCls} overflow-hidden`}
style={{ fontSize: calculateFontSize() }}
className="inputPlaceholder"
style={{ overflow: "hidden", fontSize: calculateFontSize() }}
onClick={onClick}
ref={ref}
>
{value}
<i className="fa-light fa-calendar ml-[5px]"></i>
<i className="fa-regular fa-calendar" style={{ marginLeft: "5px" }}></i>
</div>
));
ExampleCustomInput.displayName = "ExampleCustomInput";
@@ -306,13 +304,17 @@ function PlaceholderType(props) {
case "signature":
return props.pos.SignUrl ? (
<img
alt="signature"
alt="signimg"
draggable="false"
src={props.pos.SignUrl}
className="w-full h-full "
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
/>
) : (
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
{props?.handleUserName &&
props?.handleUserName(
props?.data?.Id,
@@ -324,13 +326,17 @@ function PlaceholderType(props) {
case "stamp":
return props.pos.SignUrl ? (
<img
alt="stamp"
alt="signimg"
draggable="false"
src={props.pos.SignUrl}
className="w-full h-full"
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
/>
) : (
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
{props?.handleUserName &&
props?.handleUserName(
props?.data?.Id,
@@ -411,20 +417,19 @@ function PlaceholderType(props) {
false
);
}}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap", color: "initial" }}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: "12px"
fontSize: calculateFontSize()
}}
>
<span>{type}</span>
@@ -433,8 +438,9 @@ function PlaceholderType(props) {
case "dropdown":
return props.data?.signerObjId === props.signerObjId ? (
<select
className={`${selectWidgetCls} text-[12px]`}
className="inputPlaceholder"
id="myDropdown"
style={{ fontSize: "12px", color: "initial" }}
value={selectOption}
onChange={(e) => {
setSelectOption(e.target.value);
@@ -454,7 +460,7 @@ function PlaceholderType(props) {
{props?.pos?.options?.name}
</option>
{props.pos?.options?.values?.map((data, ind) => {
{props.pos?.options?.values.map((data, ind) => {
return (
<option key={ind} value={data}>
{data}
@@ -464,7 +470,7 @@ function PlaceholderType(props) {
</select>
) : (
<div
className={selectWidgetCls}
className="inputPlaceholder"
style={{ fontSize: calculateFontSize() }}
>
{props.pos?.options?.name ? props.pos.options.name : type}
@@ -473,13 +479,17 @@ function PlaceholderType(props) {
case "initials":
return props.pos.SignUrl ? (
<img
alt="initials"
alt="signimg"
draggable="false"
src={props.pos.SignUrl}
className="w-full h-full"
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
/>
) : (
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
{props?.handleUserName &&
props?.handleUserName(
props?.data?.Id,
@@ -510,20 +520,19 @@ function PlaceholderType(props) {
isDefault
);
}}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap", color: "initial" }}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: "12px"
fontSize: calculateFontSize()
}}
>
<span>{type}</span>
@@ -550,20 +559,19 @@ function PlaceholderType(props) {
false
);
}}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap", color: "initial" }}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: "12px"
fontSize: calculateFontSize()
}}
>
<span>{type}</span>
@@ -590,20 +598,19 @@ function PlaceholderType(props) {
false
);
}}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap", color: "initial" }}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: "12px"
fontSize: calculateFontSize()
}}
>
<span>{type}</span>
@@ -648,7 +655,8 @@ function PlaceholderType(props) {
}
onBlur={handleInputBlur}
closeOnScroll={true}
className={`${selectWidgetCls} outline-[#007bff]`}
className="inputPlaceholder"
style={{ outlineColor: "#007bff" }}
selected={
props?.startDate
? props?.startDate
@@ -671,13 +679,17 @@ function PlaceholderType(props) {
case "image":
return props.pos.SignUrl ? (
<img
alt="image"
alt="signimg"
draggable="false"
src={props.pos.SignUrl}
className="w-full h-full"
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
/>
) : (
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
<div style={{ fontSize: 11, color: "black", justifyContent: "center" }}>
{props?.handleUserName &&
props?.handleUserName(
props?.data?.Id,
@@ -708,20 +720,19 @@ function PlaceholderType(props) {
false
);
}}
className={textWidgetCls}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
}}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{ whiteSpace: "pre-wrap", color: "initial" }}
cols="50"
/>
) : (
<div
style={{
color: "black",
fontSize: "12px"
fontSize: calculateFontSize()
}}
>
<span>{type}</span>
@@ -734,9 +745,11 @@ function PlaceholderType(props) {
return (
<div key={ind} className="flex items-center text-center gap-0.5">
<input
className={`${
ind === 0 ? "mt-0" : "mt-[5px]"
} ${"w-[15px] h-[15px]"} flex justify-center op-radio`}
className={`${ind === 0 ? "mt-0" : "mt-[5px]"} ${
props?.pos?.Width
? `w-[${props?.pos?.Width}px] h-[${props?.pos?.Width}px]`
: "w-[15px] h-[15px]"
} flex justify-center op-radio`}
type="radio"
disabled={
props.isNeedSign &&
@@ -778,28 +791,41 @@ function PlaceholderType(props) {
false
);
}}
className={textWidgetCls}
className={
isMobile
? "labelTextArea labelWidthMobile"
: "labelTextArea labelWidthDesktop"
}
style={{
fontSize: props.pos.options?.fontSize
? props.pos.options?.fontSize + "px"
: "12px",
color: props.pos.options?.fontColor || "black"
whiteSpace: "pre-wrap",
overflow: "hidden",
color: "initial"
}}
cols="50"
/>
);
default:
return props.pos.SignUrl ? (
<div className="pointer-events-none">
<div style={{ pointerEvents: "none" }}>
<img
alt="image"
alt="signimg"
draggable="false"
src={props.pos.SignUrl}
className="w-full h-full"
style={{
width: "99%",
height: "100%",
objectFit: "contain"
}}
/>
</div>
) : (
<div className="text-[11px] w-full h-full text-black flex flex-col justify-center items-center">
<div
style={{
fontSize: "10px",
color: "black",
justifyContent: "center"
}}
>
{props.pos.isStamp ? <div>stamp</div> : <div>signature</div>}
{props?.handleUserName &&
props?.handleUserName(props?.data?.Id, props?.data?.Role)}
+7 -7
View File
@@ -13,27 +13,27 @@ function PrevNext({ pageNumber, allPages, changePage }) {
return (
<div className="flex items-center">
<button
className="op-btn op-btn-neutral op-btn-xs md:op-btn-sm font-semibold text-xs"
className="op-btn op-btn-secondary op-btn-xs md:op-btn-sm font-semibold text-xs"
disabled={pageNumber <= 1}
onClick={previousPage}
>
<span className="block lg:hidden">
<i className="fa-light fa-backward" aria-hidden="true"></i>
<i className="fa fa-backward" aria-hidden="true"></i>
</span>
<span className="lg:block hidden 2xl:text-[30px]">Prev</span>
<span className="lg:block hidden">Prev</span>
</button>
<span className="text-xs text-base-content font-medium mx-2 2xl:text-[30px]">
<span className="text-xs text-base-content font-medium mx-2">
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
</span>
<button
className="op-btn op-btn-neutral op-btn-xs md:op-btn-sm font-semibold text-xs"
className="op-btn op-btn-secondary op-btn-xs md:op-btn-sm font-semibold text-xs"
disabled={pageNumber >= allPages}
onClick={nextPage}
>
<span className="block lg:hidden">
<i className="fa-light fa-forward" aria-hidden="true"></i>
<i className="fa fa-forward" aria-hidden="true"></i>
</span>
<span className="lg:block hidden 2xl:text-[30px]">Next</span>
<span className="lg:block hidden">Next</span>
</button>
</div>
);
@@ -15,6 +15,7 @@ const RecipientList = (props) => {
const [isEdit, setIsEdit] = useState(false);
//function for onhover signer name change background color
const inputRef = useRef(null);
const isWidgetExist = (Id) => {
return props.signerPos.some((x) => x.Id === Id);
};
@@ -71,6 +72,7 @@ const RecipientList = (props) => {
props.setRoleName(remainingItems[index]?.Role);
props.setBlockColor(remainingItems[index]?.blockColor);
};
return (
<>
{props.signersdata.length > 0 &&
@@ -89,7 +91,7 @@ const RecipientList = (props) => {
onDrop={(e) =>
props.sendInOrder && !isMobile && handleChangeSequence(e, ind)
}
data-tut="recipientArea"
data-tut="reactourFirst"
onMouseEnter={() => setIsHover(ind)}
onMouseLeave={() => setIsHover(null)}
className={`${
@@ -131,7 +133,7 @@ const RecipientList = (props) => {
>
<span className="text-white uppercase font-bold text-center text-[12px]">
{isWidgetExist(obj.Id) ? (
<i className="fa-light fa-check"></i>
<i className="fa-solid fa-check"></i>
) : (
<>
{obj.Name
@@ -143,7 +145,7 @@ const RecipientList = (props) => {
</div>
<div
className={`${
obj.Name ? "flex-col" : "flex-row"
obj?.Name ? "flex-col" : "flex-row"
} flex items-center`}
>
{obj.Name ? (
@@ -173,7 +175,7 @@ const RecipientList = (props) => {
{isEdit?.[obj.Id] && props.handleRoleChange ? (
<input
ref={inputRef}
className="bg-transparent p-[3px]"
className="bg-transparent p-[3px"
value={obj.Role}
onChange={(e) => props.handleRoleChange(e, obj.Id)}
onBlur={() => {
@@ -188,9 +190,7 @@ const RecipientList = (props) => {
}}
/>
) : (
<span className="text-[13px] 2xl:text-[25px]">
{obj.Role}
</span>
<span className="p-[3px]">{obj.Role}</span>
)}
</span>
)}
@@ -209,7 +209,7 @@ const RecipientList = (props) => {
</div>
</div>
{isMobile && props.sendInOrder && (
<div className="flex flex-row items-center gap-[5px] mr-2">
<div className="flex flex-row items-center gap-[5px]">
<div
onClick={(e) => {
if (ind !== 0) {
@@ -249,9 +249,9 @@ const RecipientList = (props) => {
props.isSelectListId === ind
? "text-[#424242]"
: "text-base-content"
} cursor-pointer`}
} cursor-pointer ml-[5px]`}
>
<i className="fa-light fa-trash-can 2xl:text-[30px]"></i>
<i className="fa-regular fa-trash-can"></i>
</div>
)}
<hr />
@@ -1,6 +1,6 @@
import React, { useEffect, useRef, useState } from "react";
import React, { useState } from "react";
import RSC from "react-scrollbars-custom";
import { Document, Page } from "react-pdf";
import { useSelector } from "react-redux";
function RenderAllPdfPage({
signPdfUrl,
@@ -33,22 +33,7 @@ function RenderAllPdfPage({
}
}
}
const pageContainer = useRef();
const isHeader = useSelector((state) => state.showHeader);
const [pageWidth, setPageWidth] = useState("");
useEffect(() => {
const updateSize = () => {
if (pageContainer.current) {
setPageWidth(pageContainer.current.offsetWidth);
}
};
// Use setTimeout to wait for the transition to complete
const timer = setTimeout(updateSize, 100); // match the transition duration
return () => clearTimeout(timer);
}, [isHeader, pageContainer]);
//'function `addSignatureBookmark` is used to display the page where the user's signature is located.
const addSignatureBookmark = (index) => {
const ispageNumber = signPageNumber.includes(index + 1);
@@ -57,55 +42,68 @@ function RenderAllPdfPage({
<div className="absolute z-20 top-[1px] -right-[13px] -translate-x-1/2 -translate-y-1/2">
<i
style={{ color: bookmarkColor || "red" }}
className="fa-light fa-bookmark"
className="fa-solid fa-bookmark"
></i>
</div>
)
);
};
return (
<div ref={pageContainer} className="hidden w-[20%] bg-base-100 md:block">
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
Pages
</div>
<div
className={`flex h-[90%] flex-col items-center m-2
autoSignScroll hide-scrollbar max-h-[100vh] `}
>
<Document
loading={"Loading Document.."}
onLoadSuccess={onDocumentLoad}
file={signPdfUrl}
>
{Array.from(new Array(allPages), (el, index) => (
<div
key={index}
className={`${
pageNumber - 1 === index ? "border-[red]" : "border-[#878787]"
} border-2 m-[10px] flex justify-center items-center relative`}
onClick={() => {
setPageNumber(index + 1);
if (setSignBtnPosition) {
setSignBtnPosition([]);
}
<div>
<div className=" hidden md:flex flex-row bg-base-100 h-full">
<div className="w-[140px]">
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
Pages
</div>
<div>
<RSC
id="RSC-Example"
style={{
width: "135px",
height: window.innerHeight - 130 + "px"
}}
>
{signerPos && addSignatureBookmark(index)}
<Document
loading={"Loading Document.."}
onLoadSuccess={onDocumentLoad}
file={signPdfUrl}
>
{Array.from(new Array(allPages), (el, index) => (
<div
key={index}
className={`${
pageNumber - 1 === index
? "border-[red]"
: "border-[#878787]"
} border-2 w-[100px] m-[10px] flex justify-center items-center relative`}
onClick={() => {
setPageNumber(index + 1);
if (setSignBtnPosition) {
setSignBtnPosition([]);
}
}}
>
{signerPos && addSignatureBookmark(index)}
<div className="relative z-[1] overflow-hidden">
<Page
key={`page_${index + 1}`}
pageNumber={index + 1}
width={pageWidth - 60}
scale={1}
renderAnnotationLayer={false}
renderTextLayer={false}
/>
</div>
</div>
))}
</Document>
<div className="relative z-[1] overflow-hidden">
<Page
key={`page_${index + 1}`}
pageNumber={index + 1}
width={100}
height={100}
scale={1}
renderAnnotationLayer={false}
renderTextLayer={false}
/>
</div>
</div>
))}
</Document>
</RSC>
</div>
<hr />
</div>
</div>
</div>
);
+227 -163
View File
@@ -11,6 +11,8 @@ import Alert from "../../primitives/Alert";
function RenderPdf({
pageNumber,
pdfOriginalWidth,
pdfNewWidth,
drop,
signerPos,
successEmail,
@@ -24,13 +26,15 @@ function RenderPdf({
pdfDetails,
xyPostion,
pdfUrl,
numPages,
pageDetails,
pdfRequest,
setCurrentSigner,
signerObjectId,
signedSigners,
pdfLoad,
setPdfLoad,
setPdfLoadFail,
placeholder,
pdfLoadFail,
setSignerPos,
setXyPostion,
index,
@@ -53,90 +57,165 @@ function RenderPdf({
unSignedWidgetId,
setIsCheckbox,
handleNameModal,
handleTextSettingModal,
setTempSignerId,
uniqueId,
pdfOriginalWH,
scale
uniqueId
}) {
const isMobile = window.innerWidth < 767;
const newWidth = containerWH.width;
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
const isGuestSigner = localStorage.getItem("isGuestSigner");
// handle signature block width and height according to screen
const posWidth = (pos, signYourself) => {
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
);
const containerScale = containerWH.width / getPdfPageWidth.width || 1;
const defaultWidth = defaultWidthHeight(pos.type).width;
const posWidth = pos.Width ? pos.Width : defaultWidth;
let width;
if (signYourself) {
return posWidth * scale * containerScale;
width = posWidth;
return width;
} else {
if (pos.isMobile && pos.scale) {
if (pos.IsResize) {
if (scale > 1) {
return posWidth * pos.scale * containerScale * scale;
if (isMobile) {
if (!pos.isMobile) {
if (pos.IsResize) {
width = posWidth ? posWidth : defaultWidth;
return width;
} else {
return posWidth * containerScale;
width = (posWidth || defaultWidth) / scale;
return width;
}
} else {
if (scale > 1) {
return posWidth * pos.scale * containerScale * scale;
} else {
return posWidth * pos.scale * containerScale;
}
width = posWidth;
return width;
}
} else {
return posWidth * scale * containerScale;
if (pos.isMobile) {
if (pos.IsResize) {
width = posWidth ? posWidth : defaultWidth;
return width;
} else {
width = (posWidth || defaultWidth) * pos.scale;
return width;
}
} else {
width = posWidth ? posWidth : defaultWidth;
return width;
}
}
}
};
const posHeight = (pos, signYourself) => {
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
);
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
let height;
const posHeight = pos.Height;
const defaultHeight = defaultWidthHeight(pos.type).height;
const posHeight = pos.Height || defaultWidthHeight(pos.type).height;
if (signYourself) {
return posHeight * scale * containerScale;
height = posHeight ? posHeight : defaultHeight;
return height;
} else {
if (pos.isMobile && pos.scale) {
if (pos.IsResize) {
if (scale > 1) {
return posHeight * pos.scale * containerScale * scale;
if (isMobile) {
if (!pos.isMobile) {
if (pos.IsResize) {
height = posHeight ? posHeight : defaultHeight;
return height;
} else {
return posHeight * containerScale;
height = (posHeight || defaultHeight) / scale;
return height;
}
} else {
if (scale > 1) {
return posHeight * pos.scale * containerScale * scale;
} else {
return posHeight * pos.scale * containerScale;
}
height = posHeight ? posHeight : defaultHeight;
return height;
}
} else {
return posHeight * scale * containerScale;
if (pos.isMobile) {
if (pos.IsResize) {
height = posHeight ? posHeight : defaultHeight;
return height;
} else {
height = (posHeight || defaultHeight) * pos.scale;
return height;
}
} else {
height = posHeight ? posHeight : defaultHeight;
return height;
}
}
}
};
const xPos = (pos, signYourself) => {
const resizePos = pos.xPosition;
if (signYourself) {
return resizePos;
} else {
//checking both condition mobile and desktop view
if (isMobile) {
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
if (!pos.isMobile) {
return resizePos / scale;
}
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
else {
return resizePos * (pos.scale / scale);
}
} else {
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
if (pos.isMobile) {
return pos.scale && resizePos * pos.scale;
}
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
else {
return resizePos;
}
}
}
};
const yPos = (pos, signYourself) => {
const resizePos = pos.yPosition;
if (signYourself) {
return resizePos;
} else {
//checking both condition mobile and desktop view
if (isMobile) {
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
if (!pos.isMobile) {
return resizePos / scale;
}
//pos.isMobile true -- placeholder save from mobile view(small device) handle position in mobile view(small screen) view divided by scale
else {
return resizePos * (pos.scale / scale);
}
} else {
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
if (pos.isMobile) {
return pos.scale && resizePos * pos.scale;
}
//else placeholder save from desktop(bigscreen) and show in desktop(bigscreen)
else {
return resizePos;
}
}
}
};
//function for render placeholder block over pdf document
const checkSignedSigners = (data) => {
const checkSignedSignes = (data) => {
let checkSign = [];
//condition to handle quick send flow and using normal request sign flow
checkSign = signedSigners
? signedSigners?.filter(
(sign) =>
sign?.Id === data?.Id || sign?.objectId === data?.signerObjId
)
: [];
checkSign = signedSigners.filter(
(sign) => sign?.Id === data?.Id || sign?.objectId === data?.signerObjId
);
if (data.signerObjId === signerObjectId) {
setCurrentSigner(true);
}
const handleAllUserName = (Id, Role, type) => {
return (
<React.Fragment>
<div className="text-black text-[8px] font-bold">
<div className="text-black text-[8px] font-medium">
{
pdfDetails[0].Signers?.find(
(signer) => signer.objectId === data.signerObjId
@@ -152,6 +231,7 @@ function RenderPdf({
</React.Fragment>
);
};
return (
checkSign.length === 0 &&
data.placeHolder.map((placeData, key) => {
@@ -178,6 +258,8 @@ function RenderPdf({
isShowDropdown={true}
isNeedSign={true}
isSignYourself={false}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
handleUserName={handleAllUserName}
@@ -189,11 +271,6 @@ function RenderPdf({
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
setCurrWidgetsDetails={setCurrWidgetsDetails}
uniqueId={uniqueId}
scale={scale}
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
/>
</React.Fragment>
)
@@ -204,7 +281,6 @@ function RenderPdf({
})
);
};
//function for render placeholder block over pdf document
const handleUserName = (Id, Role, type) => {
if (Id) {
@@ -240,25 +316,26 @@ function RenderPdf({
);
}
};
return (
<>
{successEmail && <Alert type={"success"}>Email sent successfully!</Alert>}
{isMobile ? (
{isMobile && scale ? (
<div
data-tut="reactourForth"
className={`${
isGuestSigner ? "30px" : ""
} border-[0.1px] border-[#ebe8e8]`}
style={{
border: "0.1px solid #ebe8e8",
marginTop: isGuestSigner && "30px"
}}
ref={drop}
id="container"
>
{containerWH?.width &&
pdfOriginalWH.length > 0 &&
{pdfLoadFail.status &&
(pdfRequest
? signerPos.map((data, key) => {
return (
<React.Fragment key={key}>
{checkSignedSigners(data)}
{checkSignedSignes(data)}
</React.Fragment>
);
})
@@ -297,6 +374,8 @@ function RenderPdf({
handleLinkUser={handleLinkUser}
handleUserName={handleUserName}
isSignYourself={false}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
isDragging={isDragging}
@@ -312,13 +391,6 @@ function RenderPdf({
handleNameModal={handleNameModal}
setTempSignerId={setTempSignerId}
uniqueId={uniqueId}
handleTextSettingModal={
handleTextSettingModal
}
scale={scale}
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
/>
</React.Fragment>
);
@@ -350,10 +422,13 @@ function RenderPdf({
index={index}
xyPostion={xyPostion}
setXyPostion={setXyPostion}
pdfOriginalWidth={pdfOriginalWidth}
containerWH={containerWH}
setIsSignPad={setIsSignPad}
isShowBorder={true}
isSignYourself={true}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
pdfDetails={pdfDetails[0]}
@@ -366,12 +441,6 @@ function RenderPdf({
setIsCheckbox={setIsCheckbox}
setValidateAlert={setValidateAlert}
setCurrWidgetsDetails={setCurrWidgetsDetails}
handleTextSettingModal={
handleTextSettingModal
}
scale={scale}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
/>
)
);
@@ -383,9 +452,7 @@ function RenderPdf({
{/* this component for render pdf document is in middle of the component */}
<div className="flex items-center justify-center">
<Document
onLoadError={() => {
setPdfLoad(false);
}}
onLoadError={() => setPdfLoadFail(true)}
loading={"Loading Document.."}
onLoadSuccess={pageDetails}
// ref={pdfRef}'
@@ -402,16 +469,19 @@ function RenderPdf({
: pdfDetails[0].URL
}
>
<Page
key={index}
pageNumber={pageNumber}
width={containerWH.width}
renderAnnotationLayer={false}
renderTextLayer={false}
onGetAnnotationsError={(error) => {
console.log("annotation error", error);
}}
/>
{Array.from(new Array(numPages), (el, index) => (
<Page
key={index}
pageNumber={pageNumber}
width={containerWH.width}
height={containerWH.height}
renderAnnotationLayer={false}
renderTextLayer={false}
onGetAnnotationsError={(error) => {
console.log("annotation error", error);
}}
/>
))}
</Document>
</div>
</div>
@@ -420,31 +490,29 @@ function RenderPdf({
style={{
position: "relative",
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
height: window.innerHeight + "px",
zIndex: 0
width:
pdfOriginalWidth > pdfNewWidth ? pdfNewWidth : pdfOriginalWidth,
height: window.innerHeight - 110 + "px"
}}
noScrollY={false}
noScrollX={scale === 1 ? true : false}
noScrollX={pdfNewWidth < pdfOriginalWidth ? false : true}
>
<div
style={{
width: containerWH.width * scale
}}
data-tut="reactourForth"
style={{ border: "0.1px solid #ebe8e8", width: pdfOriginalWidth }}
ref={drop}
id="container"
>
{pdfLoad &&
containerWH?.width &&
pdfOriginalWH.length > 0 &&
(pdfRequest //pdf request sign flow
? signerPos?.map((data, key) => {
{pdfLoadFail.status &&
(pdfRequest
? signerPos.map((data, key) => {
return (
<React.Fragment key={key}>
{checkSignedSigners(data)}
{checkSignedSignes(data)}
</React.Fragment>
);
})
: placeholder //placeholder and template flow
: placeholder
? signerPos.map((data, ind) => {
return (
<React.Fragment key={ind}>
@@ -479,6 +547,8 @@ function RenderPdf({
handleLinkUser={handleLinkUser}
handleUserName={handleUserName}
isSignYourself={false}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
isDragging={isDragging}
@@ -494,13 +564,6 @@ function RenderPdf({
handleNameModal={handleNameModal}
setTempSignerId={setTempSignerId}
uniqueId={uniqueId}
handleTextSettingModal={
handleTextSettingModal
}
scale={scale}
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
/>
</React.Fragment>
);
@@ -512,55 +575,53 @@ function RenderPdf({
);
})
: xyPostion.map((data, ind) => {
// signyourself flow
return (
<React.Fragment key={ind}>
{data.pageNumber === pageNumber &&
data.pos.map((pos) => {
return (
<React.Fragment key={pos.key}>
<Placeholder
pos={pos}
setIsPageCopy={setIsPageCopy}
setSignKey={setSignKey}
handleDeleteSign={handleDeleteSign}
setIsStamp={setIsStamp}
handleTabDrag={handleTabDrag}
handleStop={(event, dragElement) =>
handleStop(event, dragElement, pos.type)
}
handleSignYourselfImageResize={
handleSignYourselfImageResize
}
index={index}
xyPostion={xyPostion}
setXyPostion={setXyPostion}
setIsSignPad={setIsSignPad}
isShowBorder={true}
isSignYourself={true}
posWidth={posWidth}
posHeight={posHeight}
pdfDetails={pdfDetails[0]}
isDragging={isDragging}
setIsInitial={setIsInitial}
setWidgetType={setWidgetType}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
handleUserName={handleUserName}
setIsCheckbox={setIsCheckbox}
setValidateAlert={setValidateAlert}
setCurrWidgetsDetails={
setCurrWidgetsDetails
}
handleTextSettingModal={
handleTextSettingModal
}
scale={scale}
containerWH={containerWH}
pdfOriginalWH={pdfOriginalWH}
pageNumber={pageNumber}
/>
</React.Fragment>
pos && (
<React.Fragment key={pos.key}>
<Placeholder
pos={pos}
setIsPageCopy={setIsPageCopy}
setSignKey={setSignKey}
handleDeleteSign={handleDeleteSign}
setIsStamp={setIsStamp}
handleTabDrag={handleTabDrag}
handleStop={(event, dragElement) =>
handleStop(event, dragElement, pos.type)
}
handleSignYourselfImageResize={
handleSignYourselfImageResize
}
index={index}
xyPostion={xyPostion}
setXyPostion={setXyPostion}
pdfOriginalWidth={pdfOriginalWidth}
containerWH={containerWH}
setIsSignPad={setIsSignPad}
isShowBorder={true}
isSignYourself={true}
xPos={xPos}
yPos={yPos}
posWidth={posWidth}
posHeight={posHeight}
pdfDetails={pdfDetails[0]}
isDragging={isDragging}
setIsInitial={setIsInitial}
setWidgetType={setWidgetType}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
handleUserName={handleUserName}
setIsCheckbox={setIsCheckbox}
setValidateAlert={setValidateAlert}
setCurrWidgetsDetails={
setCurrWidgetsDetails
}
/>
</React.Fragment>
)
);
})}
</React.Fragment>
@@ -570,7 +631,11 @@ function RenderPdf({
{/* this component for render pdf document is in middle of the component */}
<Document
onLoadError={() => {
pdfLoad(false);
const load = {
status: false,
type: "failed"
};
setPdfLoadFail(load);
}}
loading={"Loading Document.."}
onLoadSuccess={pageDetails}
@@ -588,18 +653,17 @@ function RenderPdf({
: pdfDetails[0].URL
}
>
<Page
key={index}
width={containerWH.width}
scale={scale || 1}
className={"-z-[1]"} // when user zoom-in in tablet widgets move backward that's why pass -z-[1]
pageNumber={pageNumber}
renderAnnotationLayer={false}
renderTextLayer={false}
onGetAnnotationsError={(error) => {
console.log("annotation error", error);
}}
/>
{Array.from(new Array(numPages), (el, index) => (
<Page
key={index}
pageNumber={pageNumber}
renderAnnotationLayer={false}
renderTextLayer={false}
onGetAnnotationsError={(error) => {
console.log("annotation error", error);
}}
/>
))}
</Document>
</div>
</RSC>
+12 -24
View File
@@ -61,6 +61,7 @@ function SignPad({
} else if (isStamp) {
setImage("");
}
setIsSignImg("");
} else if (isTab === "uploadImage") {
setImage("");
@@ -68,10 +69,11 @@ function SignPad({
// setIsInitial(false);
};
//function for set signature url
const handleSignatureChange = (data) => {
setSignature(data);
setIsSignImg(data);
const handleSignatureChange = () => {
setSignature(canvasRef.current.toDataURL());
setIsSignImg(canvasRef.current.toDataURL());
};
//save button component
const SaveBtn = () => {
return (
@@ -101,8 +103,6 @@ function SignPad({
setIsSignImg("");
onSaveSign(null, false, textWidth, textHeight);
} else {
setIsSignImg("");
canvasRef.current.clear();
onSaveSign(signatureType);
}
}
@@ -127,16 +127,6 @@ function SignPad({
? ""
: "pointer-events-none"
} op-btn op-btn-primary shadow-lg`}
disabled={
(isTab === "draw" && isSignImg) ||
(isTab === "image" && image) ||
(isTab === "mysignature" && isDefaultSign) ||
(isTab === "type" && textWidth)
? false
: image
? false
: true
}
>
Save
</button>
@@ -203,6 +193,7 @@ function SignPad({
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isTab]);
//function for convert input text value in image
const convertToImg = async (fontStyle, text, color) => {
//get text content to convert in image
@@ -280,7 +271,7 @@ function SignPad({
}
}}
key={key}
className="fa-light fa-pen-nib"
className="fa solid fa-pen-nib"
width={20}
height={20}
></i>
@@ -313,9 +304,6 @@ function SignPad({
setIsImageSelect(false);
setIsTab("draw");
setImage();
if (isSignImg) {
setSignature(isSignImg);
}
}}
className={`${
isTab === "draw"
@@ -484,8 +472,8 @@ function SignPad({
ref={imageRef}
hidden
/>
<i className="fa-light fa-cloud-upload-alt uploadImgLogo"></i>
<div className="text-[10px]">Upload</div>
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
<div className="uploadImg">Upload</div>
</div>
</div>
) : (
@@ -521,7 +509,7 @@ function SignPad({
) : isTab === "type" ? (
<div>
<div className="flex justify-between items-center">
<span className="mr-[5px] text-[12px]">
<span className="signatureText">
{isInitial ? "Initials" : "Signature"}:
</span>
<input
@@ -537,7 +525,7 @@ function SignPad({
}}
/>
</div>
<div className="border-[1px] border-[#d6d3d3] mt-[10px] ml-[5px]">
<div className="fontOptionContainer">
{fontOptions.map((font, ind) => {
return (
<div
@@ -589,7 +577,7 @@ function SignPad({
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleSignatureChange(canvasRef.current?.toDataURL())
handleSignatureChange(canvasRef.current.toDataURL())
}
dotSize={1}
/>
+3 -7
View File
@@ -7,7 +7,7 @@ function Signedby({ pdfDetails }) {
};
return (
<div className="hidden md:block w-full h-full bg-base-100">
<div className="hidden md:block w-[180px] h-full bg-base-100">
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
Signed By
</div>
@@ -19,12 +19,8 @@ function Signedby({ pdfDetails }) {
</span>
</div>
<div className="flex flex-col">
<span className="text-[12px] font-bold text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
{pdfDetails.ExtUserPtr.Name}
</span>
<span className="text-[10px] font-medium text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
{pdfDetails.ExtUserPtr.Email}
</span>
<span className="userName">{pdfDetails.ExtUserPtr.Name}</span>
<span className="useEmail">{pdfDetails.ExtUserPtr.Email}</span>
</div>
</div>
</div>
@@ -1,53 +0,0 @@
import React from "react";
import { darkenColor, getFirstLetter } from "../../constant/Utils";
function SignerListComponent(props) {
const checkSignerBackColor = (obj) => {
if (obj) {
let data = "";
if (obj?.Id) {
data = props.signerPos.filter((data) => data.Id === obj.Id);
} else {
data = props.signerPos.filter(
(data) => data.signerObjId === obj.objectId
);
}
return data && data.length > 0 && data[0].blockColor;
}
};
const checkUserNameColor = (obj) => {
const getBackColor = checkSignerBackColor(obj);
if (getBackColor) {
const color = darkenColor(getBackColor, 0.4);
return color;
} else {
return "#abd1d0";
}
};
return (
<div
className="rounded-xl mx-1 flex flex-row items-center py-[10px] mt-1"
style={{ background: checkSignerBackColor(props.obj) }}
>
<div
style={{ background: checkUserNameColor(props.obj) }}
className="flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1"
>
<span className="text-[12px] text-center font-bold text-black uppercase">
{getFirstLetter(props?.obj?.Name || props?.obj?.Role)}
</span>
</div>
<div className="flex flex-col">
<span className="text-[12px] font-bold text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
{props.obj?.Name || props?.obj?.Role}
</span>
<span className="text-[10px] font-medium text-[#424242] w-[100px] whitespace-nowrap overflow-hidden text-ellipsis">
{props.obj?.Email || props.obj?.email}
</span>
</div>
</div>
);
}
export default SignerListComponent;
@@ -6,21 +6,19 @@ function SignerListPlace(props) {
return (
<div>
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
<span className="relative">
<span>
{props.title ? props.title : "Recipients"}
<span className="absolute text-xs z-[30] mt-1 ml-0.5">
<span className="text-xs mt-1 ml-0.5">
{props?.title === "Roles" && (
<>
<a data-tooltip-id="my-tooltip">
<sup>
<i className="fa-light fa-question rounded-full border-[1px] border-base-content text-[11px] py-[1px] px-[3px]"></i>
<i className="fa-solid fa-question rounded-full border-[1.5px] border-base-content text-[11px] py-[1px] px-[3px]"></i>
</sup>
</a>
<Tooltip id="my-tooltip" className="z-[100]">
<div className="max-w-[450px] 2xl:max-w-[500px] 2xl:text-[20px] p-[1px]">
<p className="font-bold pb-[1px]">
What are template roles?
</p>
<div className="max-w-[450px]">
<p className="font-bold">What are template roles?</p>
<p>
Begin by specifying each role needed for the completion of
the document. Think about the parties involved in the
@@ -63,21 +61,21 @@ function SignerListPlace(props) {
<div
role="button"
data-tut="reactourAddbtn"
disabled={props?.isMailSend ? true : false}
className="op-btn op-btn-accent op-btn-outline w-full mt-[14px]"
disabled={props?.isMailSend ? true : false}
onClick={() => props.handleAddSigner()}
>
<i className="fa-light fa-plus"></i> Add role
<i className="fa-solid fa-plus"></i> Add role
</div>
) : (
<div
role="button"
data-tut="addRecipient"
data-tut="reactourAddbtn"
className="op-btn op-btn-accent op-btn-outline w-full mt-[14px]"
disabled={props?.isMailSend ? true : false}
onClick={() => props.setIsAddSigner(true)}
>
<i className="fa-light fa-plus"></i> Add recipients
<i className="fa-solid fa-plus"></i> Add recipients
</div>
)}
</div>
@@ -1,75 +0,0 @@
import React from "react";
import ModalUi from "../../primitives/ModalUi";
import { fontColorArr, fontsizeArr } from "../../constant/Utils";
function TextFontSetting(props) {
return (
<ModalUi
headerColor={"#dc3545"}
isOpen={props.isTextSetting}
reduceWidth={"max-w-[350px]"}
title={"Text field"}
handleClose={() => {
props.setIsTextSetting(false);
}}
>
<div className="h-full p-[20px]">
<div className="flex items-center">
<span>Font size:</span>
<select
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
value={
props.fontSize || props.currWidgetsDetails?.options?.fontSize
}
onChange={(e) => props.setFontSize(e.target.value)}
>
{fontsizeArr.map((size, ind) => {
return (
<option className="text-[13px]" value={size} key={ind}>
{size}
</option>
);
})}
</select>
<div className="flex flex-row gap-1 items-center ml-4">
<span>color: </span>
<select
value={
props.fontColor || props.currWidgetsDetails?.options?.fontColor
}
onChange={(e) => props.setFontColor(e.target.value)}
className="ml-[7px] op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content text-xs"
>
{fontColorArr.map((color, ind) => {
return (
<option value={color} key={ind}>
{color}
</option>
);
})}
</select>
<span
style={{
background:
props.fontColor ||
props.currWidgetsDetails?.options?.fontColor
}}
className="w-5 h-[19px] ml-1"
></span>
</div>
</div>
<div className="h-[1px] bg-[#9f9f9f] w-full mt-[15px] mb-2"></div>
<button
onClick={() => props.handleSaveFontSize()}
type="button"
className="op-btn op-btn-primary mt-2"
>
save
</button>
</div>
</ModalUi>
);
}
export default TextFontSetting;
@@ -250,14 +250,15 @@ function WidgetComponent({
{isMobile ? (
!isMailSend && (
<div
data-tut={dataTut}
id="navbar"
className="fixed z-[99] bottom-0 right-0"
className="stickyfooter"
style={{ width: window.innerWidth + "px" }}
>
<div className="mx-1">
{isSigners && (
<div
data-tut="recipientArea"
data-tut={dataTut}
className="py-[10px] flex justify-center items-center op-card"
style={{
background: blockColor
@@ -296,7 +297,7 @@ function WidgetComponent({
</div>
)}
<div className="ml-[6px] text-[16px]">
<i className="fa-light fa-angle-down"></i>
<i className="fa-solid fa-angle-down"></i>
</div>
</span>
</div>
@@ -309,24 +310,23 @@ function WidgetComponent({
className="op-btn op-btn-accent w-full my-[2px]"
onClick={() => handleAddSigner()}
>
<i className="fa-light fa-plus"></i>
<i className="fa-solid fa-plus"></i>
<span>Add role</span>
</div>
) : (
setIsAddSigner && (
<div
data-tut="addRecipient"
data-tut="reactourAddbtn"
className="op-btn op-btn-accent w-full my-[2px]"
onClick={() => setIsAddSigner(true)}
>
<i className="fa-light fa-plus"></i>
<i className="fa-solid fa-plus"></i>
<span>Add recipients</span>
</div>
)
)}
</div>
<div
data-tut="addWidgets"
ref={scrollContainerRef}
className="bg-base-100 border-[2px] border-t-primary"
>
@@ -349,16 +349,12 @@ function WidgetComponent({
data-tut={dataTut}
className={`${
isMailSend ? "bg-opacity-50 pointer-events-none" : ""
} hidden md:block h-full bg-base-100`}
} hidden md:block w-[180px] h-full bg-base-100`}
>
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
<span>Fields</span>
</div>
<div
className="p-[15px] flex flex-col pt-4 2xl:m-5"
data-tut="addWidgets"
>
<div className="flex flex-col items-center my-3">
<WidgetList
updateWidgets={updateWidgets}
handleDivClick={handleDivClick}
@@ -4,9 +4,9 @@ import { getWidgetType } from "../../constant/Utils";
function WidgetList(props) {
return props.updateWidgets.map((item, ind) => {
return (
<div className="2xl:p-3 mb-[5px]" key={ind}>
<div key={ind} className="mb-[5px]">
<div
className="select-none mx-[2px] md:mx-0 cursor-all-scroll"
className="select-none"
onClick={() => {
props.addPositionOfSignature &&
props.addPositionOfSignature("onclick", item);
@@ -22,10 +22,11 @@ function WidgetList(props) {
}
}}
onMouseMove={props?.handleDivClick}
onMouseDown={() => props?.handleMouseLeave()}
onTouchStart={props?.handleDivClick}
onMouseDown={() => {
props?.handleMouseLeave();
}}
>
{item.ref && getWidgetType(item)}
{item.ref && getWidgetType(item, props?.marginLeft)}
</div>
</div>
);
@@ -221,7 +221,7 @@ const WidgetNameModal = (props) => {
style={{ fontSize: 12 }}
>
<i
className="fa-light fa-exclamation-circle text-[15px]"
className="fas fa-exclamation-circle text-[15px]"
style={{ color: "#fab005" }}
></i>
invalid default value
@@ -27,12 +27,10 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.equalTo("CreatedBy", Parse.User.current());
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.equalTo("CreatedBy", Parse.User.current());
}
const res = await FolderQuery.find();
@@ -120,13 +118,13 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
<Loader />
</div>
)}
<h1 className="text-base font-semibold mt-[0.4rem]">Create Folder</h1>
<h1 className="text-base font-semibold">Create Folder</h1>
<div className="text-xs mt-2">
<label className="block">
Name<span className="text-red-500 text-[13px]">*</span>
</label>
<input
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
value={name}
onChange={(e) => setName(e.target.value)}
required
@@ -137,7 +135,7 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
<select
value={selectedParent}
onChange={handleOptions}
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
>
<option>select</option>
{folderList.length > 0 &&
@@ -152,9 +150,9 @@ const CreateFolder = ({ parentFolderId, onSuccess, folderCls }) => {
<button
onClick={handleCreateFolder}
disabled={isLoader}
className="op-btn op-btn-primary op-btn-sm mt-3"
className="flex items-center rounded p-2 bg-[#32a3ac] text-white mt-3"
>
<i className="fa-light fa-plus"></i>
<i className="fa-solid fa-plus mr-1"></i>
<span>Create</span>
</button>
</div>
@@ -24,14 +24,12 @@ const FolderModal = (props) => {
const FolderQuery = new Parse.Query(props.folderCls);
if (folderPtr) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.descending("Type");
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.equalTo("CreatedBy", Parse.User.current());
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.descending("Type");
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.equalTo("CreatedBy", Parse.User.current());
}
const res = await FolderQuery.find();
@@ -145,14 +143,14 @@ const FolderModal = (props) => {
handleCreate();
};
return (
<div className="text-xs mt-2">
<div className="text-xs mt-2 ">
<ModalUi
title={"Select Folder"}
isOpen={props.isOpenModal}
handleClose={handleCancel}
>
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
<div className="pt-1 text-[#ac4848] text-[14px] font-[500]">
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
<span
className="cursor-pointer"
title="OpenSign™ Drive"
@@ -173,50 +171,27 @@ const FolderModal = (props) => {
{" / "}
</React.Fragment>
))}
<hr className="bg-[#8a8a8a] mt-[0.750rem]" />
<hr />
</div>
<div className="mt-2 mb-3">
<div className="max-h-[210px] overflow-auto">
{!isAdd && folderList.length > 0
? folderList.map((folder) => (
<div
key={folder.objectId}
className={`${
folder.Type === "Folder"
? "cursor-pointer"
: "cursor-default"
} border-b-[1px] border-[#8a8a8a] py-2 mb-0.5"`}
onClick={() =>
folder.Type === "Folder" && handleSelect(folder)
}
>
<div className="flex items-center gap-2">
{folder.Type === "Folder" ? (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[1.4rem] h-[1.4rem] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
className="w-[1.4rem] h-[1.4rem] fill-current op-text-primary"
>
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
</svg>
)}
<span className="font-semibold">{folder.Name}</span>
</div>
{!isAdd &&
folderList.length > 0 &&
folderList.map((folder) => (
<div
key={folder.Name}
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer "
onClick={() => handleSelect(folder)}
>
<div className="flex items-center gap-2">
<i
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
aria-hidden="true"
></i>
<span className="font-semibold">{folder.Name}</span>
</div>
))
: !isLoader && (
<div className="text-base-content text-center my-2">
No data found
</div>
)}
</div>
))}
</div>
{isAdd && (
<CreateFolder
@@ -226,8 +201,8 @@ const FolderModal = (props) => {
/>
)}
{isLoader && (
<div className="flex justify-center my-4">
<i className="fa-light fa-spinner fa-spin-pulse text-[30px]"></i>
<div className="flex justify-center">
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
</div>
)}
</div>
@@ -235,28 +210,22 @@ const FolderModal = (props) => {
<hr />
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
<div
className="op-btn op-btn-seconday op-btn-sm"
className="text-[30px] cursor-pointer text-[#32a3ac]"
title="Save Here"
onClick={handleCreate}
>
{isAdd ? (
<>
<i className="fa-light fa-arrow-left" aria-hidden="true"></i>
<span className="text-xs">Back</span>
</>
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
) : (
<>
<i className="fa-light fa-square-plus" aria-hidden="true"></i>
<span className="">Add folder</span>
</>
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
)}
</div>
<div
className="op-btn op-btn-primary op-btn-sm"
className="text-[30px] cursor-pointer"
title="Save Here"
onClick={handleSubmit}
>
<i className="fa-light fa-save" aria-hidden="true"></i>Save here
<i className="fas fa-save" aria-hidden="true"></i>
</div>
</div>
</ModalUi>
@@ -44,14 +44,12 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
const FolderQuery = new Parse.Query(folderCls);
if (folderPtr) {
FolderQuery.equalTo("Folder", folderPtr);
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.descending("Type");
FolderQuery.equalTo("CreatedBy", Parse.User.current());
} else {
FolderQuery.doesNotExist("Folder");
FolderQuery.equalTo("Type", "Folder");
FolderQuery.notEqualTo("IsArchive", true);
FolderQuery.descending("Type");
FolderQuery.equalTo("CreatedBy", Parse.User.current());
}
const res = await FolderQuery.find();
@@ -176,16 +174,14 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
<div className="relative max-w-sm">
<div
onClick={() => SetIsOpen(true)}
className="cursor-pointer rounded px-[20px] py-[20px] bg-base-100 border-[1px] border-base-200 shadow flex max-w-sm gap-8 items-center"
className=" cursor-pointer rounded px-[20px] py-[20px] bg-base-100 border-[1px] border-base-200 shadow flex max-w-sm gap-8 items-center"
>
<div>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[40px] h-[40px] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
<i
className="far fa-folder-open text-[40px] text-[#33bbff]"
style={{ fontSize: "40px" }}
aria-hidden="true"
></i>
</div>
<div className="font-semibold ">
<div className="flex items-center gap-2">
@@ -194,9 +190,12 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
? selectFolder.Name
: "OpenSign™ Drive"}
</p>
<div className="text-black text-sm">
<div
className="text-black text-sm"
// onClick={() => SetIsOpen(true)}
>
<i
className="fa-light fa-pencil cursor-pointer"
className="fa fa-pencil cursor-pointer"
title="Select Folder"
aria-hidden="true"
></i>
@@ -221,7 +220,7 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
handleClose={handleCancel}
>
<div className="w-full min-w-[300px] md:min-w-[500px] max-w-[500px] px-3">
<div className="pt-1 text-[#ac4848] text-[14px] font-[500]">
<div className="py-2 text-[#ac4848] text-[14px] font-[500]">
<span
className="cursor-pointer"
title="OpenSign™ Drive"
@@ -242,50 +241,27 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
{" / "}
</React.Fragment>
))}
<hr className="bg-[#8a8a8a] mt-[0.750rem]" />
<hr />
</div>
<div className="mb-2">
<div className="mt-2 mb-3">
<div className="max-h-[210px] overflow-auto">
{!isAdd && folderList.length > 0
? folderList.map((folder) => (
<div
key={folder.objectId}
className={`${
folder.Type === "Folder"
? "cursor-pointer"
: "cursor-default"
} border-b-[1px] border-[#8a8a8a] py-2 mb-0.5"`}
onClick={() =>
folder.Type === "Folder" && handleSelect(folder)
}
>
<div className="flex items-center gap-2">
{folder.Type === "Folder" ? (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 512 512"
className="w-[1.4rem] h-[1.4rem] fill-current op-text-secondary"
>
<path d="M64 480H448c35.3 0 64-28.7 64-64V160c0-35.3-28.7-64-64-64H288c-10.1 0-19.6-4.7-25.6-12.8L243.2 57.6C231.1 41.5 212.1 32 192 32H64C28.7 32 0 60.7 0 96V416c0 35.3 28.7 64 64 64z" />
</svg>
) : (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 384 512"
className="w-[1.4rem] h-[1.4rem] fill-current op-text-primary"
>
<path d="M374.629 150.627L233.371 9.373C227.371 3.371 219.23 0 210.746 0H64C28.652 0 0 28.652 0 64V448C0 483.345 28.652 512 64 512H320C355.348 512 384 483.345 384 448V173.254C384 164.767 380.629 156.629 374.629 150.627ZM224 22.629L361.375 160H248C234.781 160 224 149.234 224 136V22.629ZM368 448C368 474.467 346.469 496 320 496H64C37.531 496 16 474.467 16 448V64C16 37.533 37.531 16 64 16H208V136C208 158.062 225.938 176 248 176H368V448ZM96 264C96 268.406 99.594 272 104 272H280C284.406 272 288 268.406 288 264S284.406 256 280 256H104C99.594 256 96 259.594 96 264ZM280 320H104C99.594 320 96 323.594 96 328S99.594 336 104 336H280C284.406 336 288 332.406 288 328S284.406 320 280 320ZM280 384H104C99.594 384 96 387.594 96 392S99.594 400 104 400H280C284.406 400 288 396.406 288 392S284.406 384 280 384Z" />
</svg>
)}
<span className="font-semibold">{folder.Name}</span>
</div>
{!isAdd &&
folderList.length > 0 &&
folderList.map((folder) => (
<div
key={folder.Name}
className="border-[1px] border-[#8a8a8a] px-2 py-2 mb-2 cursor-pointer "
onClick={() => handleSelect(folder)}
>
<div className="flex items-center gap-2">
<i
className="fa fa-folder text-[#33bbff] text-[1.4rem]"
aria-hidden="true"
></i>
<span className="font-semibold">{folder.Name}</span>
</div>
))
: !isLoader && (
<div className="text-base-content text-center my-2">
No data found
</div>
)}
</div>
))}
</div>
{isAdd && (
<CreateFolder
@@ -295,8 +271,8 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
/>
)}
{isLoader && (
<div className="flex justify-center my-4">
<i className="fa-light fa-spinner fa-spin-pulse text-[30px]"></i>
<div className="flex justify-center">
<i className="fa-solid fa-spinner fa-spin-pulse text-[30px]"></i>
</div>
)}
</div>
@@ -304,28 +280,22 @@ const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
<hr />
<div className="flex justify-between items-center py-[.75rem] px-[1.25rem]">
<div
className="op-btn op-btn-seconday op-btn-sm"
className="text-[30px] cursor-pointer text-[#32a3ac]"
title="Save Here"
onClick={handleCreate}
>
{isAdd ? (
<>
<i className="fa-light fa-arrow-left" aria-hidden="true"></i>
<span className="text-xs">Back</span>
</>
<i className="fa-solid fa-arrow-left" aria-hidden="true"></i>
) : (
<>
<i className="fa-light fa-square-plus" aria-hidden="true"></i>
<span className="">Add folder</span>
</>
<i className="fa-solid fa-square-plus" aria-hidden="true"></i>
)}
</div>
<div
className="op-btn op-btn-primary op-btn-sm"
className="text-[30px] cursor-pointer"
title="Save Here"
onClick={handleSubmit}
>
<i className="fa-light fa-save" aria-hidden="true"></i>Save here
<i className="fas fa-save" aria-hidden="true"></i>
</div>
</div>
</ModalUi>
@@ -1,5 +1,6 @@
import React, { useState } from "react";
import Parse from "parse";
import "../../../styles/AddUser.css";
import AsyncSelect from "react-select/async";
const SelectSigners = (props) => {
@@ -167,7 +167,7 @@ const SignersInput = (props) => {
}}
className="cursor-pointer op-input op-input-bordered focus:outline-none hover:border-base-content max-h-[38px] min-w-[48px] flex justify-center items-center"
>
<i className="fa-light fa-plus"></i>
<i className="fas fa-plus"></i>
</div>
<AddSignerModal isOpen={modalIsOpen}>
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
+12 -31
View File
@@ -1,18 +1,18 @@
import React, { useState, useEffect } from "react";
import Menu from "./Menu";
import Submenu from "./SubMenu";
import SocialMedia from "./SocialMedia";
import Parse from "parse";
import dp from "../../assets/images/dp.png";
import sidebarList from "../../json/menuJson";
const Sidebar = ({ isOpen, closeSidebar }) => {
const [menuList, setmenuList] = useState([]);
const [submenuOpen, setSubmenuOpen] = useState(false);
let username = localStorage.getItem("username");
const image = localStorage.getItem("profileImg") || dp;
const tenantname = localStorage.getItem("Extand_Class")
? JSON.parse(localStorage.getItem("Extand_Class"))?.[0]?.Company
: "";
const tenantname = localStorage.getItem("TenantName");
useEffect(() => {
if (localStorage.getItem("accesstoken")) {
@@ -22,32 +22,13 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
const menuItem = async () => {
try {
if (localStorage.getItem("defaultmenuid")) {
const menuId = localStorage.getItem("defaultmenuid") !== "VPh91h0ZHk";
if (menuId) {
setmenuList(sidebarList);
} else {
const addUserForm = {
icon: "fa-light fa-user",
title: "Add User",
target: "_self",
pageType: "form",
description: "",
objectId: "lM0xRnM3iE"
};
const newSidebarList = sidebarList.map((item) => {
if (item.title === "Settings") {
// Make a shallow copy of the item
const newItem = { ...item };
// Insert addUserForm at the second position
newItem.children.splice(1, 0, addUserForm);
return newItem;
}
return item;
});
setmenuList(newSidebarList);
}
}
var sideMenu = Parse.Object.extend("w_menu");
var query = new Parse.Query(sideMenu);
query.equalTo("objectId", localStorage.getItem("defaultmenuid"));
const results = await query.first();
const resultjson = results.toJSON();
let result = resultjson;
setmenuList(result.menuItems);
} catch (e) {
console.error("Problem", e);
}
@@ -63,7 +44,7 @@ const Sidebar = ({ isOpen, closeSidebar }) => {
};
return (
<aside
className={`absolute lg:relative bg-base-100 h-screen overflow-y-auto transition-all z-[999] shadow-lg hide-scrollbar
className={`absolute md:relative bg-base-100 h-screen overflow-y-auto transition-all z-[100] hide-scrollbar
${isOpen ? "w-full md:w-[300px]" : "w-0"}`}
>
<div className="flex px-2 py-3 gap-2 items-center shadow-md">
@@ -18,8 +18,8 @@ const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
<i
className={`${
submenuOpen[item.title]
? "fa-light fa-angle-down"
: "fa-light fa-angle-right"
? "fa-solid fa-angle-down"
: "fa-solid fa-angle-right"
}`}
aria-hidden="true"
></i>
+309 -327
View File
@@ -8,10 +8,7 @@ import { appInfo } from "./appinfo";
import { saveAs } from "file-saver";
import printModule from "print-js";
export const fontsizeArr = [7, 8, 9, 10, 11, 12, 13, 14, 15, 18];
export const fontColorArr = ["red", "black", "blue", "yellow"];
export const isMobile = window.innerWidth < 767;
export const isTabAndMobile = window.innerWidth < 1023;
export const textInputWidget = "text input";
export const textWidget = "text";
export const radioButtonWidget = "radio button";
@@ -160,7 +157,9 @@ export const getDrive = async (documentId, skip = 0, limit = 100) => {
// `pdfNewWidthFun` function is used to calculate pdf width to render in middle container
export const pdfNewWidthFun = (divRef) => {
const pdfWidth = divRef.current.offsetWidth;
const clientWidth = divRef.current.offsetWidth;
const pdfWidth = clientWidth - 160 - 200;
//160 is width of left side, 200 is width of right side component
return pdfWidth;
};
@@ -200,12 +199,15 @@ export const handleImageResize = (
signerPos,
setSignerPos,
pageNumber,
containerScale,
scale,
signerId,
showResize
) => {
// const filterSignerPos = signerPos.filter(
// (data) => data.signerObjId === signerId
// );
const filterSignerPos = signerPos.filter((data) => data.Id === signerId);
if (filterSignerPos.length > 0) {
const getPlaceHolder = filterSignerPos[0].placeHolder;
const getPageNumer = getPlaceHolder.filter(
@@ -218,8 +220,8 @@ export const handleImageResize = (
if (url.key === key) {
return {
...url,
Width: ref.offsetWidth / (containerScale * scale),
Height: ref.offsetHeight / (containerScale * scale),
Width: ref.offsetWidth,
Height: ref.offsetHeight,
IsResize: showResize ? true : false
};
}
@@ -248,72 +250,72 @@ export const handleImageResize = (
export const widgets = [
{
type: "signature",
icon: "fa-light fa-pen-nib",
icon: "fa-solid fa-pen-nib",
iconSize: "20px"
},
{
type: "stamp",
icon: "fa-light fa-stamp",
icon: "fa-solid fa-stamp",
iconSize: "19px"
},
{
type: "initials",
icon: "fa-light fa-signature",
icon: "fa-solid fa-signature",
iconSize: "15px"
},
{
type: "name",
icon: "fa-light fa-user",
icon: "fa-solid fa-user",
iconSize: "21px"
},
{
type: "job title",
icon: "fa-light fa-address-card",
icon: "fa-solid fa-address-card",
iconSize: "17px"
},
{
type: "company",
icon: "fa-light fa-building",
icon: "fa-solid fa-building",
iconSize: "25px"
},
{
type: "date",
icon: "fa-light fa-calendar-days",
icon: "fa-solid fa-calendar-days",
iconSize: "20px"
},
{
type: textWidget,
icon: "fa-light fa-text-width",
icon: "fa-solid fa-text-width",
iconSize: "20px"
},
{
type: textInputWidget,
icon: "fa-light fa-font",
icon: "fa-solid fa-font",
iconSize: "21px"
},
{
type: "checkbox",
icon: "fa-light fa-square-check",
icon: "fa-solid fa-square-check",
iconSize: "22px"
},
{
type: "dropdown",
icon: "fa-light fa-circle-chevron-down",
icon: "fa-solid fa-circle-chevron-down",
iconSize: "19px"
},
{
type: radioButtonWidget,
icon: "fa-light fa-circle-dot",
icon: "fa-regular fa-circle-dot",
iconSize: "20px"
},
{
type: "image",
icon: "fa-light fa-image",
icon: "fa-solid fa-image",
iconSize: "20px"
},
{
type: "email",
icon: "fa-light fa-envelope",
icon: "fa-solid fa-envelope",
iconSize: "20px"
}
];
@@ -376,15 +378,15 @@ export const addWidgetOptions = (type) => {
};
export const getWidgetType = (item) => {
return (
<div className="op-btn w-fit md:w-[100%] op-btn-primary op-btn-outline op-btn-sm focus:outline-none outline outline-[1.5px] ml-[6px] md:ml-0 p-0 overflow-hidden">
<div className="op-btn op-btn-primary op-btn-outline op-btn-sm focus:outline-none outline outline-[1.5px] w-fit md:w-[150px] ml-[6px] md:ml-0 p-0 overflow-hidden">
<div className="w-full h-full flex md:justify-between items-center">
<div className="flex justify-start items-center text-[13px] ml-1">
{!isMobile && <i className="fa-light fa-grip-vertical ml-[3px]"></i>}
<span className="md:inline-block text-center text-[15px] ml-[5px] font-semibold pr-1 md:pr-0">
{!isMobile && <i className="fa-sharp fa-solid fa-grip-vertical"></i>}
<span className="text-center text-[15px] ml-[5px] font-semibold">
{item.type}
</span>
</div>
<div className="text-[20px] op-btn op-btn-primary rounded-none w-[40px] h-full flex justify-center items-center">
<div className="text-[20px] op-btn op-btn-primary w-[40px] h-full flex justify-center items-center">
<i className={item.icon}></i>
</div>
</div>
@@ -419,9 +421,9 @@ export const defaultWidthHeight = (type) => {
case "email":
return { width: 150, height: 20 };
case radioButtonWidget:
return { width: 5, height: 10 };
return { width: 15, height: 30 };
case textWidget:
return { width: 150, height: 25 };
return { width: 150, height: 17 };
default:
return { width: 150, height: 60 };
}
@@ -491,9 +493,7 @@ export const handleSignYourselfImageResize = (
key,
xyPostion,
setXyPostion,
index,
containerScale,
scale
index
) => {
const getXYdata = xyPostion[index].pos;
const getPosData = getXYdata;
@@ -501,8 +501,8 @@ export const handleSignYourselfImageResize = (
if (url.key === key) {
return {
...url,
Width: ref.offsetWidth / (scale * containerScale),
Height: ref.offsetHeight / (scale * containerScale),
Width: ref.offsetWidth,
Height: ref.offsetHeight,
IsResize: true
};
}
@@ -942,23 +942,7 @@ export const onChangeHeightOfTextArea = (
setXyPostion(updatePlaceholder);
}
};
//calculate width and height
export const calculateInitialWidthHeight = (widgetData) => {
const intialText = widgetData;
const span = document.createElement("span");
span.textContent = intialText;
span.style.font = `14px`; // here put your text size and font family
span.style.display = "hidden";
document.body.appendChild(span);
const width = span.offsetWidth;
const height = span.offsetHeight;
document.body.removeChild(span);
return {
getWidth: width,
getHeight: height
};
};
export const addInitialData = (signerPos, setXyPostion, value, userId) => {
function widgetDataValue(type) {
switch (type) {
@@ -1007,13 +991,9 @@ export const addInitialData = (signerPos, setXyPostion, value, userId) => {
options: {
...item.options,
defaultValue: widgetData
}
// Width:
// calculateInitialWidthHeight(item.type, widgetData).getWidth ||
// item?.Width,
// Height:
// calculateInitialWidthHeight(item.type, widgetData).getHeight ||
// item?.Height
},
Width: calculateInitialWidthHeight(item.type, widgetData).getWidth,
Height: calculateInitialWidthHeight(item.type, widgetData).getHeight
};
} else {
return {
@@ -1024,6 +1004,24 @@ export const addInitialData = (signerPos, setXyPostion, value, userId) => {
});
};
//calculate width and height
export const calculateInitialWidthHeight = (type, widgetData) => {
const intialText = widgetData;
const span = document.createElement("span");
span.textContent = intialText;
span.style.font = `14px`; // here put your text size and font family
span.style.display = "hidden";
document.body.appendChild(span);
const width = span.offsetWidth;
const height = span.offsetHeight;
document.body.removeChild(span);
return {
getWidth: width,
getHeight: height
};
};
//function for embed document id
export const embedDocId = async (pdfDoc, documentId, allPages) => {
for (let i = 0; i < allPages; i++) {
@@ -1180,6 +1178,7 @@ export const onImageSelect = (event, setImgWH, setImage) => {
setImage({ src: image.src, imgType: imageType });
};
};
//convert https url to base64
export const fetchImageBase64 = async (imageUrl) => {
try {
@@ -1226,15 +1225,15 @@ export const changeImageWH = async (base64Image) => {
//function for embed multiple signature using pdf-lib
export const multiSignEmbed = async (
xyPositionArray,
pngUrl,
pdfDoc,
pdfOriginalWidth,
signyourself,
scale
containerWH
) => {
for (let item of xyPositionArray) {
for (let item of pngUrl) {
const typeExist = item.pos.some((data) => data?.type);
let updateItem;
if (typeExist) {
if (signyourself) {
updateItem = item.pos;
@@ -1246,13 +1245,15 @@ export const multiSignEmbed = async (
} else {
updateItem = item.pos;
}
const newWidth = containerWH.width;
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
const pageNo = item.pageNumber;
const widgetsPositionArr = updateItem;
const imgUrlList = updateItem;
const pages = pdfDoc.getPages();
const form = pdfDoc.getForm();
const page = pages[pageNo - 1];
const images = await Promise.all(
widgetsPositionArr.map(async (url) => {
imgUrlList.map(async (url) => {
let signUrl = url.SignUrl && url.SignUrl;
if (signUrl) {
if (url.ImageType === "image/png") {
@@ -1260,13 +1261,17 @@ export const multiSignEmbed = async (
const newUrl = await convertPNGtoJPEG(signUrl);
signUrl = newUrl;
}
// const checkUrl = urlValidator(signUrl);
// if (checkUrl) {
// signUrl = signUrl + "?get";
// }
const res = await fetch(signUrl);
return res.arrayBuffer();
}
})
);
widgetsPositionArr.forEach(async (position, id) => {
imgUrlList.forEach(async (position, id) => {
let img;
if (["signature", "stamp", "initials", "image"].includes(position.type)) {
if (
@@ -1287,36 +1292,110 @@ export const multiSignEmbed = async (
img = await pdfDoc.embedPng(images[id]);
}
}
let widgetWidth, widgetHeight;
widgetWidth = placeholderWidth(position);
widgetHeight = placeholderHeight(position);
const xPos = (position) => {
const resizePos = position.xPosition;
//first two condition handle to old data already saved from mobile view which scale point diffrent
if (isMobile && position.isMobile) {
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
const x = resizePos * (position.scale / scale);
return x * scale;
} else if (position.isMobile && position.scale) {
const x = resizePos * position.scale;
return x;
} else {
return resizePos;
}
};
const yPos = (position) => {
const resizePos = position.yPosition;
let scaleWidth, scaleHeight;
scaleWidth = placeholderWidth(position, scale, signyourself);
scaleHeight = placeholderHeight(position, scale, signyourself);
if (position.isMobile && position.scale) {
if (position.IsResize) {
const y = resizePos * position.scale;
return y;
const xPos = (pos) => {
const resizePos = pos.xPosition;
if (signyourself) {
if (isMobile) {
return resizePos * scale;
} else {
const y = resizePos * position.scale;
return y;
return resizePos;
}
} else {
return resizePos;
//checking both condition mobile and desktop view
if (isMobile) {
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
if (pos.isMobile) {
const x = resizePos * (pos.scale / scale);
return x * scale;
} else {
const x = resizePos / scale;
return x * scale;
}
} else {
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
if (pos.isMobile) {
const x = resizePos * pos.scale;
return x;
} else {
return resizePos;
}
}
}
};
const yPos = (pos, ind, labelDefaultHeight) => {
const resizePos = pos.yPosition;
let newUpdateHeight = labelDefaultHeight
? labelDefaultHeight
: scaleHeight;
const widgetHeight =
position.type === radioButtonWidget
? 10
: position.type === "checkbox"
? 10
: newUpdateHeight;
const newHeight = ind ? (ind > 0 ? widgetHeight : 0) : widgetHeight;
if (signyourself) {
if (isMobile) {
if (ind && ind > 0 && position.type === "checkbox") {
return page.getHeight() - resizePos * scale - newHeight;
} else if (!ind && position.type === "checkbox") {
return page.getHeight() - resizePos * scale - 10;
} else {
return page.getHeight() - resizePos * scale - newHeight;
}
// return page.getHeight() - resizePos * scale - scaleHeight;
} else {
if (ind && ind > 0 && position.type === "checkbox") {
return page.getHeight() - resizePos - newHeight;
} else if (!ind && position.type === "checkbox") {
return page.getHeight() - resizePos - 10;
} else {
return page.getHeight() - resizePos - newHeight;
}
// return page.getHeight() - resizePos - scaleHeight;
}
} else {
//checking both condition mobile and desktop view
const y = resizePos / scale;
if (isMobile) {
//if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale
if (pos.isMobile) {
const y = resizePos * (pos.scale / scale);
return page.getHeight() - y * scale - newUpdateHeight;
} else {
if (pos.IsResize) {
return page.getHeight() - y * scale - newUpdateHeight;
} else {
return page.getHeight() - y * scale - newUpdateHeight;
}
}
} else {
//else if pos.isMobile true -- placeholder saved from mobile or tablet view then handle position in desktop view divide by scale
if (pos.isMobile) {
if (pos.IsResize) {
const y = resizePos * pos.scale;
return page.getHeight() - y - newUpdateHeight;
} else {
const y = resizePos * pos.scale;
return page.getHeight() - y - newUpdateHeight;
}
} else {
if (ind && ind > 0 && position.type === "checkbox") {
return page.getHeight() - resizePos - newHeight;
} else if (position.type === "checkbox") {
return page.getHeight() - resizePos - 10;
} else {
return page.getHeight() - resizePos - newHeight;
}
}
}
}
};
const widgetTypeExist = [
@@ -1329,16 +1408,14 @@ export const multiSignEmbed = async (
"email"
].includes(position.type);
if (position.type === "checkbox") {
const font = await pdfDoc.embedFont("Helvetica");
let checkboxOptionGapFromTop, isCheck;
let y = yPos(position);
const optionsFontSize = 13;
const checkboxSize = 18;
const checkboxTextGapFromLeft = 22;
let addYPosition = 0,
isCheck;
if (position?.options?.values.length > 0) {
position?.options?.values.forEach((item, ind) => {
const checkboxRandomId = "checkbox" + randomId();
let yPosition;
const height = 13;
if (
position?.options?.response &&
position?.options?.response?.length > 0
@@ -1349,38 +1426,27 @@ export const multiSignEmbed = async (
}
const checkbox = form.createCheckBox(checkboxRandomId);
if (ind > 0) {
y = y + checkboxOptionGapFromTop;
yPosition = yPos(position, ind) - addYPosition;
addYPosition = addYPosition + height + 8;
} else {
checkboxOptionGapFromTop = 26;
yPosition = yPos(position, ind);
addYPosition = height + 8;
}
if (!position?.options?.isHideLabel) {
// below line of code is used to embed label with radio button in pdf
const optionsPosition = compensateRotation(
page.getRotation().angle,
xPos(position) + checkboxTextGapFromLeft,
y,
1,
page.getSize(),
optionsFontSize,
rgb(0, 0, 0),
font,
page
);
page.drawText(item, optionsPosition);
page.drawText(item, {
x: xPos(position) + 17,
y: yPosition + 2,
size: height
});
}
let checkboxObj = {
checkbox.addToPage(page, {
x: xPos(position),
y: y,
width: checkboxSize,
height: checkboxSize
};
checkboxObj = getImagePosition(page, checkboxObj, 1);
checkbox.addToPage(page, checkboxObj);
//applied which checkbox should be checked
y: yPosition - 3,
width: height,
height: height
});
if (isCheck) {
checkbox.check();
} else {
@@ -1391,27 +1457,14 @@ export const multiSignEmbed = async (
}
} else if (widgetTypeExist) {
const font = await pdfDoc.embedFont("Helvetica");
const fontSize = parseInt(position?.options?.fontSize) || 12;
const color = position?.options?.fontColor;
let updateColorInRgb;
if (color === "red") {
updateColorInRgb = rgb(1, 0, 0);
} else if (color === "black") {
updateColorInRgb = rgb(0, 0, 0);
} else if (color === "blue") {
updateColorInRgb = rgb(0, 0, 1);
} else if (color === "yellow") {
updateColorInRgb = rgb(0.9, 1, 0);
} else {
updateColorInRgb = rgb(0, 0, 0);
}
const fontSize = 12;
let textContent;
if (position?.options?.response) {
textContent = position.options?.response;
} else if (position?.options?.defaultValue) {
textContent = position?.options?.defaultValue;
}
const fixedWidth = widgetWidth; // Set your fixed width
const fixedWidth = scaleWidth; // Set your fixed width
const isNewOnEnterLineExist = textContent.includes("\n");
// Function to break text into lines based on the fixed width
@@ -1464,23 +1517,21 @@ export const multiSignEmbed = async (
? breakTextIntoLines(textContent, fixedWidth)
: NewbreakTextIntoLines(textContent, fixedWidth);
// Set initial y-coordinate for the first line
const labelDefaultHeight = defaultWidthHeight(position.type).height;
let y = yPos(position, null, labelDefaultHeight) + 10;
let x = xPos(position);
let y = yPos(position);
//xPos(position)
// Embed each line on the page
for (const line of lines) {
const textPosition = compensateRotation(
page.getRotation().angle,
x,
page.drawText(line, {
x: x,
y,
1,
page.getSize(),
fontSize,
updateColorInRgb,
font,
page
);
page.drawText(line, textPosition);
y += 18; // Adjust the line height as needed
color: rgb(0, 0, 0),
size: fontSize
});
y -= 18; // Adjust the line height as needed
}
} else if (position.type === "dropdown") {
const dropdownRandomId = "dropdown" + randomId();
@@ -1491,82 +1542,65 @@ export const multiSignEmbed = async (
} else if (position?.options?.defaultValue) {
dropdown.select(position?.options?.defaultValue);
}
const dropdownObj = {
dropdown.addToPage(page, {
x: xPos(position),
y: yPos(position),
width: widgetWidth,
height: widgetHeight
};
const dropdownOption = getImagePosition(page, dropdownObj, 1);
// page.drawImage(img, imageOptions);
dropdown.addToPage(page, dropdownOption);
width: scaleWidth,
height: scaleHeight,
borderWidth: 0
});
dropdown.enableReadOnly();
} else if (position.type === radioButtonWidget) {
const font = await pdfDoc.embedFont("Helvetica");
const radioRandomId = "radio" + randomId();
const radioGroup = form.createRadioGroup(radioRandomId);
let radioOptionGapFromTop;
const optionsFontSize = 16;
const radioTextGapFromLeft = 20;
const radioSize = 18;
let y = yPos(position);
if (position?.options?.values.length > 0) {
position?.options?.values.forEach((item, ind) => {
if (ind > 0) {
y = y + radioOptionGapFromTop;
} else {
radioOptionGapFromTop = 25;
}
if (!position?.options?.isHideLabel) {
// below line of code is used to embed label with radio button in pdf
let addYPosition = 18;
const optionsPosition = compensateRotation(
page.getRotation().angle,
xPos(position) + radioTextGapFromLeft,
y,
1,
page.getSize(),
optionsFontSize,
rgb(0, 0, 0),
font,
page
);
for (let i = 1; i <= position?.options?.values.length; i++) {
const data = position?.options?.values[i - 1];
let yPosition;
if (i > 1) {
yPosition = yPos(position) - addYPosition;
} else {
yPosition = yPos(position);
}
page.drawText(item, optionsPosition);
}
let radioObj = {
x: xPos(position),
y: y,
width: radioSize,
height: radioSize
};
radioObj = getImagePosition(page, radioObj, 1);
radioGroup.addOptionToPage(item, page, radioObj);
if (!position?.options?.isHideLabel) {
// below line of code is used to embed label with radio button in pdf
page.drawText(data, {
x: xPos(position) + 15,
y: yPosition + 2,
size: 11
});
}
radioGroup.addOptionToPage(data, page, {
x: xPos(position),
y: yPosition,
width: 11,
height: 11
});
if (i > 1) {
addYPosition = addYPosition + 18;
}
}
if (position?.options?.response) {
radioGroup.select(position.options?.response);
} else if (position?.options?.defaultValue) {
radioGroup.select(position?.options?.defaultValue);
}
radioGroup.enableReadOnly();
} else {
const signature = {
page.drawImage(img, {
x: xPos(position),
y: yPos(position),
width: widgetWidth,
height: widgetHeight
};
const imageOptions = getImagePosition(page, signature, 1);
page.drawImage(img, imageOptions);
width: scaleWidth,
height: scaleHeight
});
}
});
}
const pdfBytes = await pdfDoc.saveAsBase64({ useObjectStreams: false });
// console.log("pdf", pdfBytes);
return pdfBytes;
};
@@ -1579,38 +1613,90 @@ export function urlValidator(url) {
return false;
}
}
//calculate placeholder width to embed in pdf
export const placeholderWidth = (pos) => {
const defaultWidth = defaultWidthHeight(pos.type).width;
const posWidth = pos.Width || defaultWidth;
//condition to handle old data saved from mobile view to get widthh
if (pos.isMobile && pos.scale) {
if (pos.IsResize) {
return posWidth;
export const placeholderWidth = (pos, scale, signyourself) => {
let width;
const defaultWidth = defaultWidthHeight(pos.type).width;
const posWidth = pos.Width ? pos.Width : defaultWidth;
if (signyourself) {
if (isMobile) {
return posWidth * scale;
} else {
return posWidth * pos.scale;
return posWidth;
}
} else {
return posWidth;
if (isMobile) {
if (pos.isMobile) {
width = posWidth ? posWidth * scale : defaultWidth * scale;
return width;
} else {
if (pos.IsResize) {
width = posWidth ? posWidth * scale : defaultWidth * scale;
return width;
} else {
width = posWidth ? posWidth : defaultWidth;
return width;
}
}
} else {
if (pos.isMobile) {
if (pos.IsResize) {
width = posWidth ? posWidth : defaultWidth;
return width;
} else {
width = posWidth ? posWidth * pos.scale : defaultWidth * pos.scale;
return width;
}
} else {
width = posWidth ? posWidth : defaultWidth;
return width;
}
}
}
};
//calculate placeholder height to embed in pdf
export const placeholderHeight = (pos) => {
export const placeholderHeight = (pos, scale, signyourself) => {
let height;
const posHeight = pos.Height;
const defaultHeight = defaultWidthHeight(pos.type).height;
const posUpdateHeight = posHeight || defaultHeight;
//condition to handle old data saved from mobile view to get height
if (pos.isMobile && pos.scale) {
if (pos.IsResize) {
return posUpdateHeight;
if (signyourself) {
if (isMobile) {
return posHeight ? posHeight * scale : defaultHeight * scale;
} else {
return posUpdateHeight * pos.scale;
return posHeight ? posHeight : defaultHeight;
}
} else {
return posUpdateHeight;
if (isMobile) {
if (pos.isMobile) {
height = posHeight ? posHeight * scale : defaultHeight * scale;
return height;
} else {
if (pos.IsResize) {
height = posHeight ? posHeight * scale : defaultHeight * scale;
return height;
} else {
height = posHeight ? posHeight : defaultHeight;
return height;
}
}
} else {
if (pos.isMobile) {
if (pos.IsResize) {
height = posHeight ? posHeight : defaultHeight;
return height;
} else {
height = posHeight
? posHeight * pos.scale
: defaultHeight * pos.scale;
return height;
}
} else {
height = posHeight ? posHeight : defaultHeight;
return height;
}
}
}
};
@@ -1915,6 +2001,7 @@ export const convertPdfArrayBuffer = async (url) => {
return "Error";
}
};
//`handleSendOTP` function is used to send otp on user's email using `SendOTPMailV1` cloud function
export const handleSendOTP = async (email) => {
try {
@@ -2076,108 +2163,3 @@ export async function findContact(value) {
console.error("Error fetching suggestions:", error);
}
}
// `compensateRotation` is used to calculate x and y position of widget on portait, landscape pdf for pdf-lib
function compensateRotation(
pageRotation,
x,
y,
scale,
dimensions,
fontSize,
updateColorInRgb,
font,
page
) {
let rotationRads = (pageRotation * Math.PI) / 180;
//These coords are now from bottom/left
let coordsFromBottomLeft = { x: x / scale };
if (pageRotation === 90 || pageRotation === 270) {
coordsFromBottomLeft.y = dimensions.width - (y + fontSize) / scale;
} else {
coordsFromBottomLeft.y = dimensions.height - (y + fontSize) / scale;
}
let drawX = null;
let drawY = null;
if (pageRotation === 90) {
drawX =
coordsFromBottomLeft.x * Math.cos(rotationRads) -
coordsFromBottomLeft.y * Math.sin(rotationRads) +
dimensions.width;
drawY =
coordsFromBottomLeft.x * Math.sin(rotationRads) +
coordsFromBottomLeft.y * Math.cos(rotationRads);
} else if (pageRotation === 180) {
drawX =
coordsFromBottomLeft.x * Math.cos(rotationRads) -
coordsFromBottomLeft.y * Math.sin(rotationRads) +
dimensions.width;
drawY =
coordsFromBottomLeft.x * Math.sin(rotationRads) +
coordsFromBottomLeft.y * Math.cos(rotationRads) +
dimensions.height;
} else if (pageRotation === 270) {
drawX =
coordsFromBottomLeft.x * Math.cos(rotationRads) -
coordsFromBottomLeft.y * Math.sin(rotationRads);
drawY =
coordsFromBottomLeft.x * Math.sin(rotationRads) +
coordsFromBottomLeft.y * Math.cos(rotationRads) +
dimensions.height;
} else {
//no rotation
drawX = coordsFromBottomLeft.x;
drawY = coordsFromBottomLeft.y;
}
if (font) {
return {
x: drawX,
y: drawY,
font,
color: updateColorInRgb,
size: fontSize,
rotate: page.getRotation()
};
} else {
return { x: drawX, y: drawY };
}
}
// `getImagePosition` is used to calulcate position of image type widget like x, y, width, height for pdf-lib
function getImagePosition(page, image, sizeRatio) {
let pageWidth;
// pageHeight;
if ([90, 270].includes(page.getRotation().angle)) {
pageWidth = page.getHeight();
} else {
pageWidth = page.getWidth();
}
// eslint-disable-next-line
if (!image?.hasOwnProperty("vpWidth")) {
image["vpWidth"] = pageWidth;
}
const pageRatio = pageWidth / (image.vpWidth * sizeRatio);
const imageWidth = image.width * sizeRatio * pageRatio;
const imageHeight = image.height * sizeRatio * pageRatio;
const imageX = image.x * sizeRatio * pageRatio;
const imageYFromTop = image.y * sizeRatio * pageRatio;
const correction = compensateRotation(
page.getRotation().angle,
imageX,
imageYFromTop,
1,
page.getSize(),
imageHeight
);
return {
width: imageWidth,
height: imageHeight,
x: correction.x,
y: correction.y,
rotate: page.getRotation()
};
}
-56
View File
@@ -15,59 +15,3 @@ body {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
/* below css class replace bootstrap background color with daisy */
.op-bg-primary {
@apply bg-primary;
}
.op-bg-secondary {
@apply bg-secondary;
}
.op-bg-info {
@apply bg-info;
}
.op-bg-success{
@apply bg-success;
}
.op-bg-warning {
@apply bg-warning;
}
/* below css class replace bootstrap text color with daisy */
.op-text-primary {
@apply text-primary;
}
.op-text-secondary {
@apply text-secondary;
}
.op-text-info {
@apply text-info;
}
.op-text-success{
@apply text-success;
}
.op-text-warning {
@apply text-warning;
}
.op-border-primary{
@apply border-primary
}
/* CSS for scrollbar customization */
* {
scrollbar-width: thin; /* For Firefox */
scrollbar-color: gray; /* For Firefox */
}
/* For webkit-based browsers like Chrome, Safari */
*::-webkit-scrollbar {
width: 5px;
}
*::-webkit-scrollbar-track {
background-color: transparent;
}
*::-webkit-scrollbar-thumb {
background-color: gray;
border-radius: 10px;
}
+31 -31
View File
@@ -15,7 +15,7 @@ export default function reportJson(id) {
btnId: "1231",
hoverLabel: "Edit",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-pen",
btnIcon: "fa-solid fa-pen",
redirectUrl: "draftDocument",
action: "redirect"
},
@@ -23,7 +23,7 @@ export default function reportJson(id) {
btnId: "2142",
hoverLabel: "Delete",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
btnIcon: "fa fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -42,7 +42,7 @@ export default function reportJson(id) {
btnLabel: "sign",
hoverLabel: "Sign",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-signature",
btnIcon: "fa-solid fa-signature",
redirectUrl: "pdfRequestFiles",
action: "redirect"
}
@@ -60,7 +60,7 @@ export default function reportJson(id) {
btnId: "8901",
hoverLabel: "Share",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-share",
btnIcon: "fa-solid fa-share",
redirectUrl: "",
action: "share"
},
@@ -68,7 +68,7 @@ export default function reportJson(id) {
btnId: "1588",
hoverLabel: "View",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-eye",
btnIcon: "fa fa-eye",
redirectUrl: "pdfRequestFiles",
action: "redirect"
},
@@ -77,14 +77,14 @@ export default function reportJson(id) {
hoverLabel: "option",
btnColor: "",
textColor: "black",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
action: "option",
subaction: [
{
btnId: "1630",
btnLabel: "Resend",
hoverLabel: "Resend",
btnIcon: "fa-light fa-envelope",
btnIcon: "fa-solid fa-envelope",
redirectUrl: "",
action: "resend"
},
@@ -92,7 +92,7 @@ export default function reportJson(id) {
btnId: "1688",
btnLabel: "Revoke",
hoverLabel: "Revoke",
btnIcon: "fa-light fa-file-circle-xmark",
btnIcon: "fa-solid fa-file-circle-xmark",
redirectUrl: "",
action: "revoke"
},
@@ -100,7 +100,7 @@ export default function reportJson(id) {
btnId: "1488",
btnLabel: "Delete",
hoverLabel: "Delete",
btnIcon: "fa-light fa-trash",
btnIcon: "fa fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -120,7 +120,7 @@ export default function reportJson(id) {
btnId: "1378",
hoverLabel: "Edit",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-eye",
btnIcon: "fa fa-eye",
redirectUrl: "draftDocument",
action: "redirect"
},
@@ -128,7 +128,7 @@ export default function reportJson(id) {
btnId: "1278",
hoverLabel: "Delete",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
btnIcon: "fa fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -146,7 +146,7 @@ export default function reportJson(id) {
btnId: "1458",
hoverLabel: "View",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-eye",
btnIcon: "fa fa-eye",
redirectUrl: "draftDocument",
action: "redirect"
},
@@ -154,7 +154,7 @@ export default function reportJson(id) {
btnId: "1358",
hoverLabel: "Delete",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
btnIcon: "fa fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -172,7 +172,7 @@ export default function reportJson(id) {
btnId: "1898",
hoverLabel: "View",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-eye",
btnIcon: "fa fa-eye",
redirectUrl: "draftDocument",
action: "redirect"
},
@@ -180,7 +180,7 @@ export default function reportJson(id) {
btnId: "1998",
hoverLabel: "Delete",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
btnIcon: "fa fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -198,7 +198,7 @@ export default function reportJson(id) {
btnId: "1999",
hoverLabel: "Share",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-share",
btnIcon: "fa-solid fa-share",
redirectUrl: "",
action: "share"
},
@@ -206,7 +206,7 @@ export default function reportJson(id) {
btnId: "1999",
hoverLabel: "View",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-eye",
btnIcon: "fa fa-eye",
redirectUrl: "pdfRequestFiles",
action: "redirect"
},
@@ -215,14 +215,14 @@ export default function reportJson(id) {
hoverLabel: "option",
btnColor: "",
textColor: "black",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
action: "option",
subaction: [
{
btnId: "1631",
btnLabel: "Resend",
hoverLabel: "Resend",
btnIcon: "fa-light fa-envelope",
btnIcon: "fa-solid fa-envelope",
redirectUrl: "",
action: "resend"
},
@@ -230,7 +230,7 @@ export default function reportJson(id) {
btnId: "6788",
btnLabel: "Revoke",
hoverLabel: "Revoke",
btnIcon: "fa-light fa-file-circle-xmark",
btnIcon: "fa-solid fa-file-circle-xmark",
redirectUrl: "",
action: "revoke"
},
@@ -238,7 +238,7 @@ export default function reportJson(id) {
btnId: "2000",
btnLabel: "Delete",
hoverLabel: "Delete",
btnIcon: "fa-light fa-trash",
btnIcon: "fa fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -257,7 +257,7 @@ export default function reportJson(id) {
btnLabel: "sign",
hoverLabel: "Sign",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-signature",
btnIcon: "fa-solid fa-signature",
redirectUrl: "pdfRequestFiles",
action: "redirect"
}
@@ -273,7 +273,7 @@ export default function reportJson(id) {
btnId: "2003",
hoverLabel: "Edit",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-pen",
btnIcon: "fa-solid fa-pen",
redirectUrl: "draftDocument",
action: "redirect"
},
@@ -281,7 +281,7 @@ export default function reportJson(id) {
btnId: "2004",
hoverLabel: "Delete",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
btnIcon: "fa fa-trash",
redirectUrl: "",
action: "delete"
}
@@ -296,8 +296,8 @@ export default function reportJson(id) {
{
btnId: "2204",
hoverLabel: "Delete",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-trash",
btnColor: "op-btn-outline op-btn-error",
btnIcon: "fa-solid fa-trash",
action: "delete"
}
],
@@ -316,7 +316,7 @@ export default function reportJson(id) {
btnLabel: "Use",
hoverLabel: "Use",
btnColor: "op-btn-primary",
btnIcon: "fa-light fa-plus",
btnIcon: "fa fa-plus",
redirectUrl: "placeHolderSign",
action: "redirect",
selector: "reactourSecond",
@@ -328,7 +328,7 @@ export default function reportJson(id) {
btnLabel: "Quick send",
hoverLabel: "Quick send",
btnColor: "op-btn-secondary",
btnIcon: "fa-light fa-envelope",
btnIcon: "fa-solid fa-envelope",
redirectUrl: "",
action: "bulksend",
selector: "tourbulksend",
@@ -340,7 +340,7 @@ export default function reportJson(id) {
hoverLabel: "option",
btnColor: "",
textColor: "black",
btnIcon: "fa-light fa-ellipsis-vertical fa-lg",
btnIcon: "fa-solid fa-ellipsis-vertical fa-lg",
action: "option",
selector: "reactourThird",
message:
@@ -350,7 +350,7 @@ export default function reportJson(id) {
btnId: "2434",
btnLabel: "Edit",
hoverLabel: "Edit",
btnIcon: "fa-light fa-pen",
btnIcon: "fa-solid fa-pen",
redirectUrl: "template",
action: "redirect"
},
@@ -358,7 +358,7 @@ export default function reportJson(id) {
btnId: "1834",
btnLabel: "Delete",
hoverLabel: "Delete",
btnIcon: "fa-light fa-trash",
btnIcon: "fa fa-trash",
redirectUrl: "",
action: "delete"
}
+4 -4
View File
@@ -6,8 +6,8 @@ const dashboardJson = [
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
widget: {
type: "Card",
icon: "fa-light fa-signature",
bgColor: "op-bg-primary",
icon: "fas fa-signature",
bgColor: "bg-[#f0058e]",
label: "Need your Signature",
description: null,
data: {
@@ -29,8 +29,8 @@ const dashboardJson = [
colsize: "col-span-12 md:col-span-6 lg:col-span-6",
widget: {
type: "Card",
icon: "fa-light fa-sign-out-alt",
bgColor: "op-bg-secondary",
icon: "fas fa-sign-out-alt",
bgColor: "bg-[#2ed8b6]",
label: "Out for signatures",
description: null,
data: {
-161
View File
@@ -1,161 +0,0 @@
const sidebarList = [
{
icon: "fa-light fa-tachometer-alt",
title: "Dashboard",
target: "",
pageType: "dashboard",
description: "",
objectId: "35KBoSgoAK"
},
{
icon: "fa-light fa-pen-nib",
title: "Sign yourself",
target: "_self",
pageType: "form",
description: "",
objectId: "sHAnZphf69"
},
{
icon: "fa-light fa-paper-plane",
title: "Request signatures",
target: "_self",
pageType: "form",
description: "",
objectId: "8mZzFxbG1z"
},
{
icon: "fa-light fa-newspaper",
title: "Templates",
target: "_self",
pageType: null,
description: null,
objectId: null,
children: [
{
icon: "fa-light fa-file-signature",
title: "Create template",
target: "_self",
pageType: "form",
description: "",
objectId: "template"
},
{
icon: "fa-light fa-file-contract",
title: "Manage templates",
target: "_self",
pageType: "report",
description: "",
objectId: "6TeaPr321t"
}
]
},
{
icon: "fa-light fa-folder",
title: "OpenSign™ Drive",
target: "_self",
pageType: "",
description: "",
objectId: "opensigndrive"
},
{
icon: "fa-light fa-address-card",
title: "Reports",
target: "_self",
pageType: null,
description: "",
objectId: null,
children: [
{
icon: "fa-light fa-signature",
title: "Need your sign",
target: "_self",
pageType: "report",
description: "",
objectId: "4Hhwbp482K"
},
{
icon: "fa-light fa-tasks",
title: "In Progress",
target: "_self",
pageType: "report",
description: "",
objectId: "1MwEuxLEkF"
},
{
icon: "fa-light fa-check-circle",
title: "Completed",
target: "_self",
pageType: "report",
description: "",
objectId: "kQUoW4hUXz"
},
{
icon: "fa-light fa-edit",
title: "Drafts",
target: "_self",
pageType: "report",
description: "",
objectId: "ByHuevtCFY"
},
{
icon: "fa-light fa-times-circle",
title: "Declined",
target: "_self",
pageType: "report",
description: "",
objectId: "UPr2Fm5WY3"
},
{
icon: "fa-light fa-hourglass-end",
title: "Expired",
target: "_self",
pageType: "report",
description: "",
objectId: "zNqBHXHsYH"
},
{
icon: "fa-light fa-address-book",
title: "Contactbook",
target: "_self",
pageType: "report",
description: "",
objectId: "5KhaPr482K"
}
]
},
{
icon: "fa-light fa-cog",
title: "Settings",
target: "_self",
pageType: null,
description: "",
objectId: null,
children: [
{
icon: "fa-light fa-pen-fancy",
title: "My Signature",
target: "_self",
pageType: "",
description: "",
objectId: "managesign"
},
{
icon: "fa-light fa-key",
title: "API Token",
target: "_self",
pageType: "generatetoken",
description: "",
objectId: ""
},
{
icon: "fa-light fa-globe",
title: "Webhook",
target: "_self",
pageType: "webhook",
description: "",
objectId: ""
}
]
}
];
export default sidebarList;
+2 -5
View File
@@ -5,7 +5,7 @@ import Sidebar from "../components/sidebar/Sidebar";
import { useWindowSize } from "../hook/useWindowSize";
import Tour from "reactour";
import axios from "axios";
import { useDispatch, useSelector } from "react-redux";
import { useSelector } from "react-redux";
import Parse from "parse";
import ModalUi from "../primitives/ModalUi";
import { useNavigate, useLocation, Outlet } from "react-router-dom";
@@ -13,12 +13,10 @@ import { isEnableSubscription } from "../constant/const";
import { useCookies } from "react-cookie";
import { fetchSubscription } from "../constant/Utils";
import Loader from "../primitives/Loader";
import { showHeader } from "../redux/reducers/showHeader";
const HomeLayout = () => {
const navigate = useNavigate();
const location = useLocation();
const dispatch = useDispatch();
const { width } = useWindowSize();
const [isOpen, setIsOpen] = useState(true);
const arr = useSelector((state) => state.TourSteps);
@@ -100,7 +98,6 @@ const HomeLayout = () => {
}
const showSidebar = () => {
setIsOpen((value) => !value);
dispatch(showHeader(!isOpen));
};
useEffect(() => {
if (width && width <= 768) {
@@ -234,7 +231,7 @@ const HomeLayout = () => {
}
const closeSidebar = () => {
if (width <= 1023) {
if (width <= 768) {
setIsOpen(false);
}
};
+3 -6
View File
@@ -49,8 +49,8 @@ function ChangePassword() {
return <Navigate to="/" />;
}
return (
<div className="w-full bg-base-100 text-base-content shadow rounded-box p-2">
<Title title="Change Password" />
<div className="w-full bg-base-100 text-base-content shadow rounded p-2">
<Title title={"Change Password"} />
<div className="text-xl font-bold border-b-[1px] border-gray-300">
Change Password
</div>
@@ -98,10 +98,7 @@ function ChangePassword() {
required
/>
</div>
<button
type="submit"
className="op-btn op-btn-primary shadow-md mt-2"
>
<button type="submit" className="op-btn op-btn-primary shadow-md m-2">
Change Password
</button>
</form>
+1
View File
@@ -1,4 +1,5 @@
import React, { useState, useEffect } from "react";
import "../styles/loader.css";
import GetDashboard from "../components/dashboard/GetDashboard";
import { useNavigate, useParams } from "react-router-dom";
import Title from "../components/Title";
+109 -31
View File
@@ -1,5 +1,7 @@
import React, { useEffect, useState } from "react";
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
import "../styles/signature.css";
import "../styles/AddUser.css";
import Title from "../components/Title";
import RenderDebugPdf from "../components/RenderDebugPdf";
import { pdfjs } from "react-pdf";
@@ -56,7 +58,7 @@ const DebugPdf = () => {
const fetchPdfMetadata = async () => {
try {
const pdfDataURL = URL.createObjectURL(pdf); // Convert File to data URL
// console.log("pdfDataURL ", pdfDataURL);
console.log("pdfDataURL ", pdfDataURL);
const pdfInfo = await pdfjs.getDocument({ url: pdfDataURL }).promise;
const pdfType = await inferPdfType(pdfInfo);
setPdfDetails((prevDetails) => ({
@@ -74,7 +76,7 @@ const DebugPdf = () => {
const inferPdfType = async (pdf) => {
try {
const firstPage = await pdf.getPage(2);
const firstPage = await pdf.getPage(1);
const scale = 1;
const { width, height } = firstPage.getViewport({ scale });
setPdfDimension({ width: width, height: height });
@@ -215,18 +217,14 @@ const DebugPdf = () => {
};
return (
<div>
{copied && (
<Alert type="success">
<span className="ml-3">Copied</span>
</Alert>
)}
{copied && <Alert type="success">Copied</Alert>}
<Title title={"Debug Pdf"} />
{width < 800 ? (
<HandleError handleError={"Debug PDF only availble for PC"} />
) : (
<>
{!isModal && (
<div className="flex flex-row justify-between">
<div className="signatureContainer">
{/* this component used to render all pdf pages in left side */}
<RenderAllPdfPage
signPdfUrl={pdf}
@@ -255,68 +253,126 @@ const DebugPdf = () => {
/>
</div>
</div>
<div className="w-[220px] bg-base-100">
<div className="text-[18px] font-medium py-[10px] px-[12px] border-b-[1px] border-[gray]">
<div style={{ backgroundColor: "white", width: 220 }}>
<div
style={{
fontSize: 18,
fontWeight: 500,
padding: "10px 12px",
borderBottom: "1px solid grey"
}}
>
PDF details
</div>
<div className="text-[14px] py-[5px] px-[12px]">
<div style={{ fontSize: 14, padding: "5px 12px" }}>
Name: {pdfDetails?.name}
</div>
<div className="text-[14px] py-[5px] px-[12px]">
<div style={{ fontSize: 14, padding: "5px 12px" }}>
Pdf type: {pdfDetails?.pdftype}
</div>
<div className="text-[14px] py-[5px] px-[12px]">
<div style={{ fontSize: 14, padding: "5px 12px" }}>
Total Pages: {pdfDetails?.totalPages}
</div>
<div className="text-[14px] py-[5px] px-[12px]">
<div style={{ fontSize: 14, padding: "5px 12px" }}>
Current Page: {pdfDetails?.currentPage}
</div>
<div className="text-[14px] py-[5px] px-[12px]">
<div style={{ fontSize: 14, padding: "5px 12px" }}>
Base64 : {pdfDetails?.base64.slice(0, 10)}...
<span
className="op-btn op-btn-outline op-btn-primary op-btn-xs rounded-md w-[25px] h-[25px] text-[12px] m-[2px] "
style={{
borderRadius: 4,
padding: "3px 5px",
border: "1px solid gray",
fontSize: 12,
margin: 2,
cursor: "pointer"
}}
onClick={() => copytoclipboard(pdfDetails?.base64)}
>
<i className="fa-light fa-copy"></i>
<i className="fa-solid fa-copy"></i>
</span>
</div>
<div className="text-[18px] font-medium py-[10px] px-[12px] border-b-[1px] border-[gray]">
<div
style={{
fontSize: 18,
fontWeight: 500,
padding: "10px 12px",
borderBottom: "1px solid grey"
}}
>
Last click
</div>
<div className="text-[14px] py-[5px] px-[12px]">
<div style={{ fontSize: 14, padding: "5px 12px" }}>
x co-ordinate: {pdfDetails?.x}
</div>
<div className="text-[14px] py-[5px] px-[12px]">
<div style={{ fontSize: 14, padding: "5px 12px" }}>
y co-ordinate: {pdfDetails?.y}
</div>
<div className="text-[18px] font-medium py-[10px] px-[12px] border-y-[1px] border-[gray]">
<div
style={{
fontSize: 18,
fontWeight: 500,
padding: "10px 12px",
borderBottom: "1px solid grey",
borderTop: "1px solid grey"
}}
>
Annotation
</div>
<ul className=" list-none p-[10px] h-[500px] overflow-y-auto">
<ul
style={{
listStyle: "none",
padding: 10,
height: 500,
overflowY: "auto",
scrollbarWidth: 5
}}
>
{annotations.map((coord, index) => (
<li key={index}>
<span className="text-[13px] font-medium">{`Box ${
<span style={{ fontSize: 13, fontWeight: 500 }}>{`Box ${
index + 1
}:`}</span>
<code className="text-[12px] text-base-content select-none">
<code
style={{
fontSize: 12,
color: "black",
cursor: "pointer"
}}
>
{` ["page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}]`}
</code>
<div>
<span
className="op-btn op-btn-outline op-btn-primary op-btn-xs rounded-md w-[23px] h-[20px] text-[12px] m-[2px] "
style={{
borderRadius: 4,
padding: "3px 5px",
border: "1px solid gray",
fontSize: 12,
margin: 2,
cursor: "pointer"
}}
onClick={() =>
copytoclipboard(
`"page":${coord?.page}, "x": ${coord.x}, "y": ${coord.y}, "w": ${coord.width}, "h": ${coord.height}`
)
}
>
<i className="fa-light fa-copy"></i>
<i className="fa-solid fa-copy"></i>
</span>
<span
className="op-btn op-btn-outline op-btn-error op-btn-xs rounded-md w-[23px] h-[20px] text-[12px] m-[2px] "
style={{
borderRadius: 4,
padding: "3px 5px",
border: "1px solid gray",
fontSize: 12,
margin: 2,
cursor: "pointer"
}}
onClick={() => handleDelete(coord.key)}
>
<i className="fa-light fa-trash-can"></i>
<i className="fa-solid fa-trash-can"></i>
</span>
</div>
</li>
@@ -326,16 +382,38 @@ const DebugPdf = () => {
</div>
)}
<ModalUi title={"Select PDF"} isOpen={isModal}>
<form onSubmit={handleSubmit} className="m-[10px]">
<form onSubmit={handleSubmit} style={{ margin: "10px" }}>
<input
type="file"
onChange={(e) => handleFileChange(e.target.files)}
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full h-[40px] text-xs"
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
className="op-btn op-btn-primary w-full mt-3 mb-1"
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
+26 -19
View File
@@ -445,7 +445,7 @@ const Forms = (props) => {
setIsSubmit(false);
}
} else {
alert("Please wait while the document is being uploaded.");
alert("Please wait until the PDF has been uploading.");
}
};
@@ -565,7 +565,7 @@ const Forms = (props) => {
setFormData((prev) => ({ ...prev, autoreminder: !formData.autoreminder }));
};
return (
<div className="shadow-md rounded-box my-[2px] p-3 bg-base-100 text-base-content">
<div className="shadow-md rounded my-2 p-3 bg-base-100 text-base-content md:border-[1px] md:border-gray-600/50">
<Title title={props?.title} />
{isAlert && (
<Alert type={isErr ? "danger" : "success"}>
@@ -645,15 +645,15 @@ const Forms = (props) => {
</label>
{fileupload.length > 0 ? (
<div className="flex gap-2 justify-center items-center">
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm w-full h-full text-x text-[13px]">
<div className="break-all ">
file selected: {getFileName(fileupload)}
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm w-full text-x text-[13px]">
<div className="break-all">
file selected : {getFileName(fileupload)}
</div>
<div
onClick={() => setFileUpload("")}
className="cursor-pointer px-[10px] text-[20px] font-bold text-red-500"
>
<i className="fa-light fa-xmark"></i>
<i className="fa-solid fa-xmark"></i>
</div>
</div>
{process.env.REACT_APP_DROPBOX_API_KEY && (
@@ -701,17 +701,15 @@ const Forms = (props) => {
required
/>
</div>
{props.title === "New Template" && (
<div className="text-xs mt-2">
<label className="block">Description</label>
<input
name="Description"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.Description}
onChange={(e) => handleStrInput(e)}
/>
</div>
)}
<div className="text-xs mt-2">
<label className="block">Description</label>
<input
name="Description"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.Description}
onChange={(e) => handleStrInput(e)}
/>
</div>
{props.signers && (
<SignersInput
onChange={handleSigners}
@@ -761,7 +759,16 @@ const Forms = (props) => {
Send In Order
<a data-tooltip-id="sendInOrder-tooltip" className="ml-1">
<sup>
<i className="fa-light fa-question rounded-full border-[#33bbff] text-[#33bbff] text-[13px] border-[1px] py-[1.5px] px-[4px]"></i>
<i
className="fa-solid fa-question rounded-full"
style={{
borderColor: "#33bbff",
color: "#33bbff",
fontSize: 13,
borderWidth: 1.5,
padding: "1.5px 4px"
}}
></i>
</sup>
</a>
<Tooltip id="sendInOrder-tooltip" className="z-50">
@@ -834,7 +841,7 @@ const Forms = (props) => {
{!isEnableSubscription && (
<PremiumAlertHeader
message={
"Auto reminder is free in beta, this feature will incur a fee later."
"Disable Auto reminder is free in beta, this feature will incur a fee later."
}
/>
)}
+149 -137
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import Title from "../components/Title";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import Alert from "../primitives/Alert";
import ModalUi from "../primitives/ModalUi";
import { isEnableSubscription } from "../constant/const";
@@ -8,24 +9,19 @@ import { checkIsSubscribed, copytoData, openInNewTab } from "../constant/Utils";
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
import Tooltip from "../primitives/Tooltip";
import Loader from "../primitives/Loader";
import SubscribeCard from "../primitives/SubscribeCard";
import Tour from "reactour";
const tourSteps = [
{
selector: '[data-tut="apisubscribe"]',
content: "Upgrade now to generate API token"
}
];
function GenerateToken() {
const navigation = useNavigate();
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [apiToken, SetApiToken] = useState("");
const [isLoader, setIsLoader] = useState(true);
const [copied, setCopied] = useState(false);
const [isGenerate, setIsGenerate] = useState(false);
const [isErr, setIsErr] = useState(false);
const [isModal, setIsModal] = useState(false);
const [isSubscribe, setIsSubscribe] = useState(false);
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isTour, setIsTour] = useState(false);
useEffect(() => {
fetchToken();
// eslint-disable-next-line
@@ -37,6 +33,7 @@ function GenerateToken() {
const getIsSubscribe = await checkIsSubscribed();
setIsSubscribe(getIsSubscribe);
}
const url = parseBaseUrl + "functions/getapitoken";
const headers = {
"Content-Type": "application/json",
@@ -47,6 +44,7 @@ function GenerateToken() {
if (res) {
SetApiToken(res.data.result.result);
}
setIsLoader(false);
} catch (err) {
SetApiToken();
@@ -56,43 +54,49 @@ function GenerateToken() {
};
const handleSubmit = async (e) => {
e.preventDefault();
if (!isSubscribe && isEnableSubscription) {
setIsTour(true);
} else {
setIsLoader(true);
setIsModal(false);
try {
const url = parseBaseUrl + "functions/generateapitoken";
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessiontoken: localStorage.getItem("accesstoken")
};
const res = await axios.post(url, {}, { headers: headers });
setIsLoader(true);
setIsModal(false);
try {
const url = parseBaseUrl + "functions/generateapitoken";
const headers = {
"Content-Type": "application/json",
"X-Parse-Application-Id": parseAppId,
sessiontoken: localStorage.getItem("accesstoken")
};
await axios.post(url, {}, { headers: headers }).then((res) => {
if (res) {
SetApiToken(res.data.result.token);
setIsAlert({ type: "success", msg: "Token generated successfully." });
// localStorage.setItem("apiToken", res.data.result.token);
setIsGenerate(true);
setTimeout(() => {
setIsGenerate(false);
}, 1500);
setIsLoader(false);
} else {
console.error("Error while generating Token");
setIsAlert({ type: "danger", msg: "Something went wrong." });
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsErr(false);
}, 1500);
}
} catch (error) {
setIsAlert({ type: "danger", msg: "Something went wrong." });
console.log("while generating Token", error);
} finally {
setIsLoader(false);
setTimeout(() => {
setIsAlert({ type: "success", msg: "" });
}, 1500);
}
});
} catch (error) {
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsErr(false);
}, 1500);
console.log("err", error);
}
};
const copytoclipboard = (text) => {
copytoData(text);
setIsAlert({ type: "success", msg: "Copied" });
setCopied(true);
setTimeout(() => {
setIsAlert({ type: "success", msg: "" });
setCopied(false);
}, 1500); // Reset copied state after 1.5 seconds
};
const handleModal = () => setIsModal(!isModal);
@@ -100,124 +104,132 @@ function GenerateToken() {
return (
<React.Fragment>
<Title title={"API Token"} />
{isAlert.msg && (
<Alert type={isAlert.type}>
<div className="ml-3">{isAlert.msg}</div>
</Alert>
{isGenerate && (
<Alert type="success">Token generated successfully!</Alert>
)}
{copied && <Alert type="success">Copied</Alert>}
{isErr && <Alert type="danger">Something went wrong!</Alert>}
{isLoader ? (
<div className="flex justify-center items-center h-screen">
<Loader />
</div>
) : (
<>
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3">
{!isEnableSubscription && <PremiumAlertHeader />}
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
OpenSign API{" "}
<Tooltip
url={
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
}
isSubscribe={true}
/>
</h1>
<ul
className={"w-full flex flex-col p-2 text-sm"}
// isSubscribe || !isEnableSubscription
// ? "w-full flex flex-col p-2 text-sm "
// : "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
>
<li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2">
<div className="w-full md:w-[70%] flex-col md:flex-row text-xs md:text-[15px] flex items-center gap-x-5">
<span className="ml-1">API Token:</span>{" "}
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow rounded">
{!isEnableSubscription && <PremiumAlertHeader />}
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
OpenSign API{" "}
<Tooltip
url={
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
}
isSubscribe={true}
/>
</h1>
<ul
className={
isSubscribe || !isEnableSubscription
? "w-full flex flex-col p-2 text-sm "
: "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
}
>
<li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2">
<div className="w-full md:w-[70%] flex-col md:flex-row text-xs md:text-[15px] flex items-center gap-x-5 ">
<span className="">Api Token:</span>{" "}
<span id="token" className="md:text-end py-2 md:py-0">
<span
id="token"
className={`${
isSubscribe || !isEnableSubscription
? ""
: "bg-white/20 pointer-events-none select-none"
} md:text-end py-2 md:py-0`}
className="cursor-pointer"
onClick={() => copytoclipboard(apiToken)}
>
<span
className="cursor-pointer"
onClick={() => copytoclipboard(apiToken)}
>
{apiToken ? apiToken : "_____"}
</span>
<button
className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2 cursor-pointer"
onClick={() => copytoclipboard(apiToken)}
>
<i className="fa-light fa-copy"></i>
</button>
{apiToken ? apiToken : "_____"}
</span>
</div>
<button
onClick={apiToken ? handleModal : handleSubmit}
className="op-btn op-btn-primary"
>
{apiToken ? "Regenerate Token" : "Generate Token"}
</button>
</li>
</ul>
<div className="flex items-center justify-center">
<button
type="button"
onClick={() =>
openInNewTab(
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
)
}
className="op-btn op-btn-secondary mt-2 mb-3 px-8"
>
View Docs
</button>
</div>
<ModalUi
isOpen={isModal}
title={apiToken ? "Regenerate Token" : "Generate Token"}
handleClose={handleModal}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-base-content">
Are you sure you want to regenerate token it will expire old
token?
</div>
<hr className="bg-[#ccc] mt-4" />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={handleSubmit}
className="op-btn op-btn-primary ml-[2px]"
className="op-btn op-btn-accent op-btn-outline op-btn-sm ml-2"
onClick={() => copytoclipboard(apiToken)}
>
Yes
<i className="fa-solid fa-copy"></i>
</button>
<button
onClick={handleModal}
className="op-btn op-btn-secondary"
>
No
</button>
</div>
</span>
</div>
</ModalUi>
<button
onClick={apiToken ? handleModal : handleSubmit}
className="op-btn op-btn-primary"
>
{apiToken ? "Regenerate Token" : "Generate Token"}
</button>
</li>
</ul>
<div className="flex items-center justify-center ">
<button
type="button"
onClick={() =>
openInNewTab(
"https://docs.opensignlabs.com/docs/API-docs/opensign-api-v-1"
)
}
className="op-btn op-btn-secondary my-2"
>
View Docs
</button>
</div>
{!isSubscribe && isEnableSubscription && (
<div data-tut="apisubscribe">
<SubscribeCard />
</div>
<>
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
Upgrade to PRO Plan
</h1>
<ul className={"w-full flex flex-col p-2 text-sm "}>
<li
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
>
<div className="w-[70%] flex-col md:flex-row flex items-center gap-3 ">
<span className="">$29.99/month:</span>{" "}
<span id="token" className=" md:text-end cursor-pointer">
Sign 100 docs using API. Only 0.15/docs after that.
</span>
</div>
{!isSubscribe && isEnableSubscription && (
<button
type="button"
onClick={() => navigation("/subscription")}
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
>
Upgrade Now
</button>
)}
</li>
</ul>
</>
)}
</>
<ModalUi
isOpen={isModal}
title={"Regenerate Token"}
handleClose={handleModal}
>
<div className="m-[20px]">
<div className="text-lg font-normal text-base-content">
Are you sure you want to regenerate token it will expire old
token?
</div>
<hr className="bg-[#ccc] mt-4 " />
<div className="flex items-center mt-3 gap-2 text-white">
<button
onClick={handleSubmit}
className="op-btn op-btn-primary ml-[2px]"
>
Yes
</button>
<button
onClick={handleModal}
className="op-btn op-btn-secondary"
>
No
</button>
</div>
</div>
</ModalUi>
</div>
)}
<Tour
onRequestClose={() => setIsTour(false)}
steps={tourSteps}
isOpen={isTour}
closeWithMask={false}
disableKeyboardNavigation={["esc"]}
scrollOffset={-100}
rounded={5}
/>
</React.Fragment>
);
}
+8 -8
View File
@@ -191,7 +191,7 @@ function GuestLogin() {
<div className="m-1 md:m-2 p-[30px] text-base-content bg-base-100 op-card shadow-md">
<div className="md:w-[250px] md:h-[66px] inline-block overflow-hidden mt-2 mb-11">
{appLogo && (
<img src={appLogo} className="object-contain" alt="logo" />
<img src={appLogo} className="object-contain h-full" alt="logo" />
)}
</div>
{contactId ? (
@@ -199,7 +199,7 @@ function GuestLogin() {
{!EnterOTP ? (
<div className="w-full md:w-[50%] text-base-content">
<h1 className="text-2xl md:text-[30px]">Welcome Back!</h1>
<legend className="text-[12px] text-[#878787] mt-2 mb-1">
<legend className="text-[12px] text-[#878787] mt-2">
Verification code is sent to your email
</legend>
<div className="p-[20px] outline outline-1 outline-slate-300/50 my-2 op-card shadow-md">
@@ -207,17 +207,17 @@ function GuestLogin() {
type="email"
name="mobile"
value={email}
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full disabled:text-[#5c5c5c] text-xs"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
disabled
/>
</div>
<div className="mt-3">
<div className="mt-2">
<button
className="op-btn op-btn-primary"
onClick={(e) => handleSendOTPBtn(e)}
disabled={loading}
>
{loading ? "Loading..." : "Get verification code"}
{loading ? "Loading..." : "Send OTP"}
</button>
</div>
</div>
@@ -228,7 +228,7 @@ function GuestLogin() {
>
<h1 className="text-2xl md:text-[30px]">Welcome Back!</h1>
<legend className="text-[12px] text-[#878787] mt-2">
You will get a verification code via Email
You will get a OTP via Email
</legend>
<div className="p-[20px] pt-[15px] outline outline-1 outline-slate-300/50 op-card my-2 shadow-md">
<p className="text-sm">Enter Verification Code</p>
@@ -240,7 +240,7 @@ function GuestLogin() {
onChange={(e) => setOTP(e.target.value)}
/>
</div>
<div className="mt-2.5">
<div className="mt-2">
<button
className="op-btn op-btn-primary"
type="submit"
@@ -298,7 +298,7 @@ function GuestLogin() {
disabled
/>
</div>
<div className="mt-2.5">
<div className="mb-2">
<label
htmlFor="phone"
className="block text-xs text-gray-700 font-semibold"
+1 -2
View File
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from "react";
import Parse from "parse";
import "../styles/loader.css";
import { useDispatch } from "react-redux";
import axios from "axios";
import Title from "../components/Title";
@@ -1103,7 +1104,6 @@ function Login() {
type="email"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
name="email"
autoComplete="username"
value={state.email}
onChange={handleChange}
required
@@ -1123,7 +1123,6 @@ function Login() {
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
name="password"
value={state.password}
autoComplete="current-password"
onChange={handleChange}
required
/>
+161 -113
View File
@@ -228,7 +228,12 @@ const ManageSign = () => {
}
}
};
const handleSignatureBtn = () => {
if (imageRef.current) {
imageRef.current.value = "";
}
setImage("");
};
const handleUploadBtn = () => {
imageRef.current.click();
};
@@ -237,130 +242,166 @@ const ManageSign = () => {
setIsValue(true);
};
return (
<div className="relative h-full bg-base-100 text-base-content flex shadow-md rounded-box overflow-auto">
<div className="relative h-full bg-base-100 text-base-content flex shadow rounded overflow-auto">
{isLoader && (
<div className="absolute bg-black bg-opacity-30 z-50 w-full h-full flex justify-center items-center">
<Loader />
</div>
)}
{isAlert?.message && <Alert type={isAlert.type}>{isAlert.message}</Alert>}
<div className="relative w-full">
<div className="ml-[5px] my-[20px] md:m-[20px]">
<div className="text-[20px] font-semibold m-[10px] md:m-0 mb-2">
My Signature
</div>
<div className="flex flex-col md:flex-row gap-0 md:gap-[12px]">
<div className="relative">
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
Signature
</span>
<input
type="file"
onChange={onImageChange}
className="filetype"
accept="image/*"
ref={imageRef}
hidden
/>
<div
className="mainDiv"
style={{
width: "100%",
paddingRight: "10px"
}}
>
<div className="m-[20px]">
<div className="font-[700] text-[15px] pb-[8px]">My Signature</div>
<div className="signBlock mt-4">
<div>
<div className="relative">
<div>
{image ? (
<div className="signatureCanvas relative border-[2px] border-[#888] rounded-box">
<img
alt="signature"
src={image}
className="w-full h-full object-contain"
/>
</div>
) : (
<SignatureCanvas
ref={canvasRef}
penColor={penColor}
canvasProps={{
width: "456px",
height: "180px",
className: "signatureCanvas rounded-box"
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
handleSignatureChange(canvasRef.current.toDataURL())
}
dotSize={1}
<div className="flex flex-row justify-between w-1/2 pl-[10px]">
<div className="flex flex-row justify-around items-center gap-[10px] mb-[10px]">
<>
<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 className="penContainerDefault flex flex-row justify-between">
<div>
{!image && (
<div className="flex flex-row">
{allColor.map((data, key) => {
return (
<i
style={{
margin: "5px",
color: data,
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}
className="fa-light fa-pen-nib"
width={20}
height={20}
></i>
);
})}
</div>
)}
</div>
<div className="flex flex-row gap-2 text-sm md:text-base mr-1">
<div
type="button"
className="op-link"
onClick={() => handleUploadBtn()}
>
Upload image
</div>
</div>
<div className="relative">
<div>
{image ? (
<div className="signatureCanvas relative border-[2px] border-[#888]">
<img
alt="preview image"
src={image}
className="w-full h-full object-contain"
/>
</div>
<div
type="button"
className="op-link"
onClick={() => handleClear()}
>
Clear
) : (
<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"
}}
className="penContainerDefault"
>
<div>
{!image && (
<div
style={{ display: "flex", flexDirection: "row" }}
>
{allColor.map((data, key) => {
return (
<i
style={{
margin: "5px",
color: data,
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}
className="fa solid fa-pen-nib"
width={20}
height={20}
></i>
);
})}
</div>
)}
</div>
<div>
<div
type="button"
className="clearbtn cursor-pointer"
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>
{warning && (
<span className="customwarning signWarning text-[12px] w-[220px] md:w-[300px]">
<i className="fa-light fa-exclamation-circle text-[#fab005] text-[15px] mr-[4px]"></i>
Please upload signature/Image
</span>
)}
</div>
</div>
<div className="relative">
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
Initials
</span>
<div style={{ position: "relative" }}>
<div style={{ margin: "6px 5px 18px" }}>
<span className="signature">Initials</span>
</div>
<div>
{isInitials ? (
<div className="intialSignature relative border-[1px] border-[#888] rounded-box overflow-hidden">
<div
style={{
position: "relative",
border: "2px solid #888"
}}
className="intialSignature"
>
<img
alt="inititals"
alt="preview image"
src={Initials}
style={{
width: "100%",
@@ -374,7 +415,7 @@ const ManageSign = () => {
ref={initailsRef}
penColor={initialPen}
canvasProps={{
className: "intialSignature rounded-box"
className: "intialSignature"
}}
backgroundColor="rgb(255, 255, 255)"
onEnd={() =>
@@ -383,10 +424,17 @@ const ManageSign = () => {
dotSize={1}
/>
)}
<div className="flex flex-row justify-between w-[183px]">
<div
style={{
display: "flex",
flexDirection: "row",
justifyContent: "space-between"
}}
className="penContainerInitial"
>
<div>
{!isInitials && (
<div className="flex flex-row">
<div style={{ display: "flex", flexDirection: "row" }}>
{allColor.map((data, key) => {
return (
<i
@@ -412,7 +460,7 @@ const ManageSign = () => {
}
}}
key={key}
className="fa-light fa-pen-nib"
className="fa solid fa-pen-nib"
width={20}
height={20}
></i>
@@ -424,7 +472,7 @@ const ManageSign = () => {
<div>
<div
type="button"
className="op-link text-sm md:text-base mr-1"
className="clearbtn cursor-pointer"
onClick={() => handleClearInitials()}
>
Clear
@@ -434,7 +482,7 @@ const ManageSign = () => {
</div>
</div>
</div>
<div className="pt-3 ml-2 md:ml-0">
<div style={{ paddingTop: 10 }}>
<button
className="op-btn op-btn-primary"
onClick={(e) => handleSubmit(e)}
+22 -27
View File
@@ -522,7 +522,7 @@ function Opensigndrive() {
}
}
return (
<div className="bg-base-100 text-base-content rounded-box w-full shadow-md">
<div className="bg-base-100 text-base-content rounded-xl w-full">
<Title title={"OpenSign™ Drive"} drive={true} />
<ModalUi
isOpen={isAlert.isShow}
@@ -598,13 +598,11 @@ function Opensigndrive() {
{isLoading.isLoad ? (
<div className="flex flex-col justify-center items-center h-[100vh] w-full">
<Loader />
<span className="text-[13px] text-base-content">
{isLoading.message}
</span>
<span className="text-[13px] text-[gray]">{isLoading.message}</span>
</div>
) : handleError ? (
<div className="flex justify-center items-center h-[100vh] w-full">
<span className="text-[20px] text-base-content">{handleError}</span>
<span className="text-[20px] text-[gray]">{handleError}</span>
</div>
) : (
<>
@@ -627,7 +625,7 @@ function Opensigndrive() {
>
{handleFolderTab(folderName)}
</div>
<div className="flex flex-row items-center">
<div className="dropMenuBD">
<div
id="folder-menu"
className={
@@ -637,7 +635,7 @@ function Opensigndrive() {
>
<div className="sort" data-tut="reactourSecond">
<i
className="fa-light fa-plus-square"
className="fa fa-plus-square"
aria-hidden="true"
style={{ fontSize: "25px", color: `${iconColor}` }}
></i>
@@ -649,27 +647,24 @@ function Opensigndrive() {
>
<div className="flex flex-col">
<span
className="dropdown-item text-[10px] md:text-[13px]"
className="dropdown-item itemColor"
onClick={() => setIsFolder(true)}
>
<i
className="fa-light fa-plus mr-[5px]"
aria-hidden="true"
></i>
<i className="fa fa-plus mr-[5px]" aria-hidden="true"></i>
Create folder
</span>
<span
className="dropdown-item text-[10px] md:text-[13px]"
className="dropdown-item itemColor"
onClick={() => navigate("/form/sHAnZphf69")}
>
<i className="fa-light fa-pen-nib mr-[5px]"></i>
<i className="fas fa-pen-nib mr-[5px"></i>
Sign Yourself
</span>
<span
className="dropdown-item text-[10px] md:text-[13px]"
className="dropdown-item itemColor"
onClick={() => navigate("/form/8mZzFxbG1z")}
>
<i className="fa-light fa-file-signature mr-[5px]"></i>
<i className="fa fa-file-signature mr-[5px"></i>
Request Signatures
</span>
</div>
@@ -686,7 +681,7 @@ function Opensigndrive() {
data-toggle="dropdown"
>
<i
className="fa-light fa-sort-amount-asc mr-[5px] text-[14px]"
className="fa fa-sort-amount-asc mr-[5px] text-[14px]"
aria-hidden="true"
style={{ color: `${iconColor}` }}
></i>
@@ -709,18 +704,18 @@ function Opensigndrive() {
setSelectedSort(value);
sortingData(value, null, pdfData);
}}
className="dropdown-item text-[10px] md:text-[13px]"
className="dropdown-item itemColor"
style={{
paddingLeft: selectedSort !== value && "31px"
paddingLeft: selectedSort !== value && "33px"
}}
>
{selectedSort === value && (
<i
className="fa-light fa-check"
className="fa fa-check mr-[5px"
aria-hidden="true"
></i>
)}
<span className="ml-[5px]">{value}</span>
{value}
</span>
);
})}
@@ -734,18 +729,18 @@ function Opensigndrive() {
setSortingOrder(order);
sortingData(null, order, pdfData);
}}
className="dropdown-item text-[10px] md:text-[13px]"
className="dropdown-item itemColor"
style={{
paddingLeft: sortingOrder !== order && "31px"
paddingLeft: sortingOrder !== order && "33px"
}}
>
{sortingOrder === order && (
<i
className="fa-light fa-check"
className="fa fa-check mr-[5px"
aria-hidden="true"
></i>
)}
<span className="ml-[5px]">{order}</span>
{order}
</span>
);
})}
@@ -757,7 +752,7 @@ function Opensigndrive() {
<div className="sort" onClick={() => setIsList(!isList)}>
<i
onClick={() => setIsList(!isList)}
className="fa-light fa-th-large"
className="fa fa-th-large"
style={{ fontSize: "24px", color: `${iconColor}` }}
aria-hidden="true"
></i>
@@ -769,7 +764,7 @@ function Opensigndrive() {
onClick={() => setIsList(!isList)}
>
<i
className="fa-light fa-list"
className="fa fa-list"
aria-hidden="true"
style={{ fontSize: "23px", color: `${iconColor}` }}
></i>
+1 -1
View File
@@ -4,7 +4,7 @@ import Title from "../components/Title";
const PageNotFound = ({ prefix }) => {
return (
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded">
<Title title={"Page Not Found"} />
<div className="text-center">
<h1 className="text-[60px] lg:text-[120px] font-semibold">404</h1>
+343 -328
View File
@@ -31,7 +31,8 @@ import {
contactBook,
handleDownloadPdf,
handleToPrint,
handleDownloadCertificate
handleDownloadCertificate,
darkenColor
} from "../constant/Utils";
import LoaderWithMsg from "../primitives/LoaderWithMsg";
import HandleError from "../primitives/HandleError";
@@ -41,17 +42,14 @@ import PdfDeclineModal from "../primitives/PdfDeclineModal";
import Title from "../components/Title";
import DefaultSignature from "../components/pdf/DefaultSignature";
import ModalUi from "../primitives/ModalUi";
import VerifyEmail from "../components/pdf/VerifyEmail";
import TourContentWithBtn from "../primitives/TourContentWithBtn";
import { appInfo } from "../constant/appinfo";
import Loader from "../primitives/Loader";
import { useSelector } from "react-redux";
import SignerListComponent from "../components/pdf/SignerListComponent";
import VerifyEmail from "../components/pdf/VerifyEmail";
import PdfZoom from "../components/pdf/PdfZoom";
function useQuery() {
return new URLSearchParams(useLocation().search);
}
function PdfRequestFiles() {
const { docId } = useParams();
const navigate = useNavigate();
@@ -83,10 +81,11 @@ function PdfRequestFiles() {
isLoad: true,
message: "This might take some time"
});
const [defaultSignImg, setDefaultSignImg] = useState();
const [isDocId, setIsDocId] = useState(false);
const [pdfNewWidth, setPdfNewWidth] = useState();
const [pdfOriginalWH, setPdfOriginalWH] = useState([]);
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
const [signerPos, setSignerPos] = useState([]);
const [signerObjectId, setSignerObjectId] = useState();
const [isUiLoading, setIsUiLoading] = useState(false);
@@ -95,7 +94,6 @@ function PdfRequestFiles() {
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
const [unSignedWidgetId, setUnSignedWidgetId] = useState("");
const [expiredDate, setExpiredDate] = useState("");
const [isResize, setIsResize] = useState(false);
const [signerUserId, setSignerUserId] = useState();
const [isDontShow, setIsDontShow] = useState(false);
const [isDownloading, setIsDownloading] = useState("");
@@ -110,7 +108,10 @@ function PdfRequestFiles() {
});
const [myInitial, setMyInitial] = useState("");
const [isInitial, setIsInitial] = useState(false);
const [pdfLoad, setPdfLoad] = useState(false);
const [pdfLoadFail, setPdfLoadFail] = useState({
status: false,
type: "load"
});
const [isSigned, setIsSigned] = useState(false);
const [isExpired, setIsExpired] = useState(false);
const [alreadySign, setAlreadySign] = useState(false);
@@ -126,10 +127,6 @@ function PdfRequestFiles() {
const [isVerifyModal, setIsVerifyModal] = useState(false);
const [otp, setOtp] = useState("");
const [contractName, setContractName] = useState("");
const [zoomPercent, setZoomPercent] = useState(0);
const [totalZoomPercent, setTotalZoomPercent] = useState();
const [scale, setScale] = useState(1);
const isHeader = useSelector((state) => state.showHeader);
const divRef = useRef(null);
const isMobile = window.innerWidth < 767;
const rowLevel =
@@ -158,23 +155,17 @@ function PdfRequestFiles() {
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
useEffect(() => {
const updateSize = () => {
if (divRef.current) {
const pdfWidth = pdfNewWidthFun(divRef);
setPdfNewWidth(pdfWidth);
setContainerWH({
width: divRef.current.offsetWidth,
height: divRef.current.offsetHeight
});
}
};
// Use setTimeout to wait for the transition to complete
const timer = setTimeout(updateSize, 100); // match the transition duration
return () => clearTimeout(timer);
if (divRef.current) {
const pdfWidth = pdfNewWidthFun(divRef);
setPdfNewWidth(pdfWidth);
setContainerWH({
width: divRef.current.offsetWidth,
height: divRef.current.offsetHeight
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [divRef.current, isHeader]);
}, [divRef.current]);
//function to use resend otp for email verification
const handleResend = async (e) => {
e.preventDefault();
@@ -182,7 +173,7 @@ function PdfRequestFiles() {
const localuser = localStorage.getItem(
`Parse/${appInfo.appId}/currentUser`
);
const currentUser = JSON.parse(localuser);
const currentUser = JSON.parse(JSON.stringify(localuser));
await handleSendOTP(currentUser?.email);
setOtpLoader(false);
alert("OTP sent on you email");
@@ -194,7 +185,7 @@ function PdfRequestFiles() {
const localuser = localStorage.getItem(
`Parse/${appInfo.appId}/currentUser`
);
const currentUser = JSON.parse(localuser);
const currentUser = JSON.parse(JSON.stringify(localuser));
try {
const resEmail = await Parse.Cloud.run("verifyemail", {
otp: otp,
@@ -215,13 +206,14 @@ function PdfRequestFiles() {
setOtpLoader(false);
}
};
//`handleVerifyBtn` function is used to send otp on user mail
const handleVerifyBtn = async () => {
setIsVerifyModal(true);
const localuser = localStorage.getItem(
`Parse/${appInfo.appId}/currentUser`
);
const currentUser = JSON.parse(localuser);
const currentUser = JSON.parse(JSON.stringify(localuser));
await handleSendOTP(currentUser?.email);
};
async function checkIsSubscribed(extUserId, contactId) {
@@ -328,13 +320,6 @@ function PdfRequestFiles() {
message:
"You have successfully signed the document. You can download or print a copy of the partially signed document. A copy of the digitally signed document will be sent to the owner over email once it is signed by all signers."
});
} else {
const checkCurrentUser = documentData[0].Placeholders.find(
(data) => data.signerObjId === currUserId
);
if (checkCurrentUser) {
setCurrentSigner(true);
}
}
const isGuestSign = location.pathname.includes("/load/");
@@ -500,7 +485,7 @@ function PdfRequestFiles() {
const localuser = localStorage.getItem(
`Parse/${appInfo.appId}/currentUser`
);
const currentUser = JSON.parse(localuser);
const currentUser = JSON.parse(JSON.stringify(localuser));
const currentUserEmail = currentUser.email;
const res = await contractUsers(currentUserEmail);
if (res === "Error: Something went wrong!") {
@@ -781,10 +766,10 @@ function PdfRequestFiles() {
const pdfBytes = await multiSignEmbed(
pngUrl,
pdfDoc,
pdfOriginalWidth,
isSignYourSelfFlow,
scale
containerWH
);
// console.log("pdfte", pdfBytes);
//get ExistUserPtr object id of user class to get tenantDetails
const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId;
//get ExistUserPtr email to get userDetails
@@ -1013,24 +998,31 @@ function PdfRequestFiles() {
style: { fontSize: "13px" }
}
];
//function for get pdf page details
const pageDetails = async (pdf) => {
let pdfWHObj = [];
const totalPages = pdf.numPages; // Get the total number of pages
for (let index = 0; index < totalPages; index++) {
const getPage = await pdf.getPage(index + 1);
const scale = 1;
const { width, height } = getPage.getViewport({ scale });
pdfWHObj.push({ pageNumber: index + 1, width, height });
}
setPdfOriginalWH(pdfWHObj);
setPdfLoad(true);
const load = {
status: true
};
setPdfLoadFail(load);
pdf.getPage(1).then((pdfPage) => {
const pageWidth = pdfPage.view[2];
setPdfOriginalWidth(pageWidth);
});
};
//function for change page
function changePage(offset) {
setPageNumber((prevPageNumber) => prevPageNumber + offset);
}
const getFirstLetter = (name) => {
if (name) {
const firstLetter = name.charAt(0);
return firstLetter;
}
};
//function for image upload or update
const onImageChange = (event) => {
if (event.target.files && event.target.files[0]) {
@@ -1139,6 +1131,26 @@ function PdfRequestFiles() {
return newState;
});
};
const checkSignerBackColor = (obj) => {
let data = "";
if (obj?.Id) {
data = signerPos.filter((data) => data.Id === obj.Id);
} else {
data = signerPos.filter((data) => data.signerObjId === obj.objectId);
}
return data && data.length > 0 && data[0].blockColor;
};
const checkUserNameColor = (obj) => {
const getBackColor = checkSignerBackColor(obj);
if (getBackColor) {
const color = darkenColor(getBackColor, 0.4);
return color;
} else {
return "#abd1d0";
}
};
//function for set decline true on press decline button
const declineDoc = async () => {
setIsDecline({ isDeclined: false });
@@ -1234,7 +1246,6 @@ function PdfRequestFiles() {
const handleDontShow = (isChecked) => {
setIsDontShow(isChecked);
};
// console.log("signerpos", signerPos);
//function to close tour and save tour status
const closeRequestSignTour = async () => {
setRequestSignTour(true);
@@ -1288,7 +1299,7 @@ function PdfRequestFiles() {
style: { fontSize: "13px" }
},
{
selector: '[data-tut="pdfArea"]',
selector: '[data-tut="reactourForth"]',
content: () => (
<TourContentWithBtn
message={`Click any of the placeholders appearing on the document to sign. You will then see options to draw your signature, type it, or upload an image .`}
@@ -1385,7 +1396,7 @@ function PdfRequestFiles() {
{isUiLoading && (
<div className="absolute h-[100vh] w-full flex flex-col justify-center items-center z-[999] bg-[#e6f2f2] bg-opacity-80">
<Loader />
<span className="text-[13px] text-base-content">
<span className="text-[13px] font-bold">
This might take some time
</span>
</div>
@@ -1399,6 +1410,7 @@ function PdfRequestFiles() {
</div>
)}
<div
className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300"
style={{
pointerEvents:
isExpired ||
@@ -1406,7 +1418,7 @@ function PdfRequestFiles() {
? "none"
: "auto"
}}
className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300"
ref={divRef}
>
{!requestSignTour && requestSignTourFunction()}
<ModalUi
@@ -1423,12 +1435,9 @@ function PdfRequestFiles() {
<p>{isAlert.alertMessage}</p>
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
<button
onClick={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
onClick={() =>
setIsAlert({ isShow: false, alertMessage: "" })
}
type="button"
className="op-btn op-btn-primary"
>
@@ -1486,12 +1495,9 @@ function PdfRequestFiles() {
<ModalUi
isOpen={defaultSignAlert.isShow}
title={"Auto sign"}
handleClose={() => {
setDefaultSignAlert({
isShow: false,
alertMessage: ""
});
}}
handleClose={() =>
setDefaultSignAlert({ isShow: false, alertMessage: "" })
}
>
<div className="h-full p-[20px]">
<p>{defaultSignAlert.alertMessage}</p>
@@ -1506,12 +1512,12 @@ function PdfRequestFiles() {
Yes
</button>
<button
onClick={() => {
onClick={() =>
setDefaultSignAlert({
isShow: false,
alertMessage: ""
});
}}
})
}
type="button"
className="op-btn op-btn-secondary"
>
@@ -1520,12 +1526,9 @@ function PdfRequestFiles() {
</>
) : (
<button
onClick={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
onClick={() =>
setIsAlert({ isShow: false, alertMessage: "" })
}
type="button"
className="op-btn op-btn-primary"
>
@@ -1547,277 +1550,289 @@ function PdfRequestFiles() {
setPageNumber={setPageNumber}
pageNumber={pageNumber}
/>
{/* pdf render view */}
<div className=" w-full md:w-[57%] flex mr-4">
<PdfZoom
setScale={setScale}
scale={scale}
containerWH={containerWH}
setZoomPercent={setZoomPercent}
zoomPercent={zoomPercent}
<div
style={{
marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px",
marginRight: !isMobile && pdfOriginalWidth > 500 && "20px"
}}
>
{/* this modal is used show this document is already sign */}
<ModalUi
isOpen={isCompleted.isModal}
title={"Document signed"}
handleClose={() => {
setIsCompleted((prev) => ({ ...prev, isModal: false }));
}}
reduceWidth={
!isCompleted?.message &&
"md:min-w-[440px] md:max-w-[400px]"
}
>
<div className="h-full p-[20px] text-base-content">
{isCompleted?.message ? (
<p>{isCompleted?.message}</p>
) : (
<div className="px-[15px]">
<span>
Congratulations! 🎉 This document has been
successfully signed by all participants!
</span>
</div>
)}
{!isCompleted?.message && (
<div className="flex mt-4 gap-1 px-[15px]">
<button
type="button"
onClick={() =>
handleDownloadCertificate(
pdfDetails,
setIsDownloading
)
}
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-secondary"
>
<i
className="fa-solid fa-award"
aria-hidden="true"
></i>
<span className="hidden lg:block">Certificate</span>
</button>
<button
onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading)
}
type="button"
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-neutral"
>
<i className="fa fa-print" aria-hidden="true"></i>
<span className="hidden lg:block">Print</span>
</button>
<button
type="button"
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-primary"
onClick={() =>
handleDownloadPdf(
pdfDetails,
pdfUrl,
setIsDownloading
)
}
>
<i
className="fa fa-download"
aria-hidden="true"
></i>
<span className="hidden lg:block">Download</span>
</button>
</div>
)}
</div>
</ModalUi>
{isDownloading === "pdf" && (
<div className="fixed z-[1000] inset-0 flex justify-center items-center bg-black bg-opacity-30">
<Loader />
</div>
)}
<ModalUi
isOpen={isDownloading === "certificate"}
title={
isDownloading === "certificate"
? "Generating certificate"
: "PDF Download"
}
handleClose={() => setIsDownloading("")}
>
<div className="p-3 md:p-5 text-[13px] md:text-base text-center">
{isDownloading === "certificate"}{" "}
<p>
Your completion certificate is being generated. Please
wait momentarily.
</p>
<p>
If the download doesn&apos;t start shortly, click the
button again.
</p>
</div>
</ModalUi>
{/* this component is used for signature pad modal */}
<SignPad
isSignPad={isSignPad}
isStamp={isStamp}
setIsImageSelect={setIsImageSelect}
setIsSignPad={setIsSignPad}
setImage={setImage}
isImageSelect={isImageSelect}
imageRef={imageRef}
onImageChange={onImageChange}
setSignature={setSignature}
image={image}
onSaveImage={saveImage}
onSaveSign={saveSign}
defaultSign={defaultSignImg}
myInitial={myInitial}
isInitial={isInitial}
setIsInitial={setIsInitial}
setIsStamp={setIsStamp}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
/>
<div className=" w-full md:w-[95%] ">
{/* this modal is used show this document is already sign */}
<ModalUi
isOpen={isCompleted.isModal}
title={"Document signed"}
handleClose={() => {
setIsCompleted((prev) => ({ ...prev, isModal: false }));
}}
reduceWidth={
!isCompleted?.message &&
"md:min-w-[440px] md:max-w-[400px]"
}
>
<div className="h-full p-[20px] text-base-content">
{isCompleted?.message ? (
<p>{isCompleted?.message}</p>
) : (
<div className="px-[15px]">
<span>
Congratulations! 🎉 This document has been
successfully signed by all participants!
</span>
</div>
)}
{!isCompleted?.message && (
<div className="flex mt-4 gap-1 px-[15px]">
<button
type="button"
onClick={() =>
handleDownloadCertificate(
pdfDetails,
setIsDownloading
)
}
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-secondary"
>
<i
className="fa-light fa-award mx-[3px] lg:mx-0"
aria-hidden="true"
></i>
<span className="hidden lg:block">
Certificate
</span>
</button>
<button
onClick={(e) =>
handleToPrint(e, pdfUrl, setIsDownloading)
}
type="button"
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-neutral"
>
<i
className="fa-light fa-print"
aria-hidden="true"
></i>
<span className="hidden lg:block">Print</span>
</button>
<button
type="button"
className="font-[500] text-[13px] mr-[5px] op-btn op-btn-primary"
onClick={() =>
handleDownloadPdf(
pdfDetails,
pdfUrl,
setIsDownloading
)
}
>
<i
className="fa-light fa-download"
aria-hidden="true"
></i>
<span className="hidden lg:block">Download</span>
</button>
</div>
)}
</div>
</ModalUi>
{isDownloading === "pdf" && (
<div className="fixed z-[1000] inset-0 flex justify-center items-center bg-black bg-opacity-30">
<Loader />
</div>
)}
<ModalUi
isOpen={isDownloading === "certificate"}
title={
isDownloading === "certificate"
? "Generating certificate"
: "PDF Download"
}
handleClose={() => setIsDownloading("")}
>
<div className="p-3 md:p-5 text-[13px] md:text-base text-center text-base-content">
{isDownloading === "certificate"}{" "}
<p>
Your completion certificate is being generated. Please
wait momentarily. If the download doesn&apos;t start
shortly, click the button again.
</p>
</div>
</ModalUi>
{/* this component is used for signature pad modal */}
<SignPad
isSignPad={isSignPad}
isStamp={isStamp}
setIsImageSelect={setIsImageSelect}
setIsSignPad={setIsSignPad}
setImage={setImage}
isImageSelect={isImageSelect}
imageRef={imageRef}
onImageChange={onImageChange}
setSignature={setSignature}
image={image}
onSaveImage={saveImage}
onSaveSign={saveSign}
defaultSign={defaultSignImg}
myInitial={myInitial}
isInitial={isInitial}
setIsInitial={setIsInitial}
setIsStamp={setIsStamp}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
/>
{/* pdf header which contain funish back button */}
<Header
isPdfRequestFiles={true}
{/* pdf header which contain funish back button */}
<Header
isPdfRequestFiles={true}
pageNumber={pageNumber}
allPages={allPages}
changePage={changePage}
pdfDetails={pdfDetails}
signerPos={signerPos}
isSigned={isSigned}
isCompleted={isCompleted.isCertificate}
embedWidgetsData={embedWidgetsData}
isShowHeader={true}
setIsDecline={setIsDecline}
decline={true}
currentSigner={currentSigner}
pdfUrl={pdfUrl}
alreadySign={alreadySign}
/>
{containerWH && (
<RenderPdf
pageNumber={pageNumber}
allPages={allPages}
changePage={changePage}
pdfOriginalWidth={pdfOriginalWidth}
pdfNewWidth={pdfNewWidth}
setIsSignPad={setIsSignPad}
setIsStamp={setIsStamp}
setSignKey={setSignKey}
pdfDetails={pdfDetails}
signerPos={signerPos}
isSigned={isSigned}
isCompleted={isCompleted.isCertificate}
embedWidgetsData={embedWidgetsData}
isShowHeader={true}
setIsDecline={setIsDecline}
decline={true}
currentSigner={currentSigner}
successEmail={false}
pdfUrl={pdfUrl}
alreadySign={alreadySign}
totalZoomPercent={totalZoomPercent}
setTotalZoomPercent={setTotalZoomPercent}
setScale={setScale}
scale={scale}
pdfOriginalWH={pdfOriginalWH}
numPages={numPages}
pageDetails={pageDetails}
pdfRequest={true}
signerObjectId={signerObjectId}
signedSigners={signedSigners}
setCurrentSigner={setCurrentSigner}
setPdfLoadFail={setPdfLoadFail}
pdfLoadFail={pdfLoadFail}
setSignerPos={setSignerPos}
containerWH={containerWH}
setZoomPercent={setZoomPercent}
zoomPercent={zoomPercent}
setIsInitial={setIsInitial}
setValidateAlert={setValidateAlert}
unSignedWidgetId={unSignedWidgetId}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
setCurrWidgetsDetails={setCurrWidgetsDetails}
/>
)}
</div>
<div>
<div className="hidden md:block w-[180px] h-full bg-base-100">
<div
style={{ maxHeight: window.innerHeight - 70 + "px" }}
className="overflow-y-auto hide-scrollbar"
>
{signedSigners.length > 0 && (
<div data-tut="reactourSecond">
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
Signed by
</div>
<div className="mt-[2px]">
{signedSigners.map((obj, ind) => {
return (
<div
className="rounded-xl mx-1 flex flex-row items-center py-[10px] mt-1"
style={{
background: checkSignerBackColor(obj)
}}
key={ind}
>
<div
className="flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1"
style={{
background: checkUserNameColor(obj)
}}
>
<span className="text-[12px] text-center font-bold text-white uppercase">
{getFirstLetter(obj?.Name || obj?.Role)}
</span>
</div>
<div className="flex flex-col">
<span className="userName">
{obj?.Name || obj?.Role}
</span>
<span className="useEmail">
{obj?.Email || obj?.email}
</span>
</div>
</div>
);
})}
</div>
</div>
)}
<div ref={divRef} data-tut="pdfArea" className="h-[95%]">
{containerWH && (
<RenderPdf
pageNumber={pageNumber}
pdfOriginalWH={pdfOriginalWH}
pdfNewWidth={pdfNewWidth}
setIsSignPad={setIsSignPad}
setIsStamp={setIsStamp}
setSignKey={setSignKey}
pdfDetails={pdfDetails}
signerPos={signerPos}
successEmail={false}
pdfUrl={pdfUrl}
numPages={numPages}
pageDetails={pageDetails}
pdfRequest={true}
signerObjectId={signerObjectId}
signedSigners={signedSigners}
setPdfLoad={setPdfLoad}
pdfLoad={pdfLoad}
setSignerPos={setSignerPos}
containerWH={containerWH}
setIsInitial={setIsInitial}
setValidateAlert={setValidateAlert}
unSignedWidgetId={unSignedWidgetId}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
setCurrWidgetsDetails={setCurrWidgetsDetails}
divRef={divRef}
setIsResize={setIsResize}
isResize={isResize}
setTotalZoomPercent={setTotalZoomPercent}
setScale={setScale}
scale={scale}
{unsignedSigners.length > 0 && (
<div data-tut="reactourFirst">
<div className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300">
Yet to sign
</div>
<div className="mt-[5px]">
{unsignedSigners.map((obj, ind) => {
return (
<div
className="rounded-xl mx-1 flex flex-row items-center py-[10px] mt-1"
style={{
background: checkSignerBackColor(obj)
}}
key={ind}
>
<div
className="flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1"
style={{
background: checkUserNameColor(obj)
}}
>
<span className="text-[12px] text-center font-bold text-black uppercase">
{getFirstLetter(obj?.Name || obj?.email)}
</span>
</div>
<div className="flex flex-col">
<span className="userName">
{obj?.Name || obj?.Role}
</span>
<span className="useEmail">
{obj?.Email || obj?.email}
</span>
</div>
<hr />
</div>
);
})}
</div>
</div>
)}
{defaultSignImg && !alreadySign && (
<DefaultSignature
defaultSignImg={defaultSignImg}
setDefaultSignImg={setDefaultSignImg}
userObjectId={signerObjectId}
setIsLoading={setIsLoading}
xyPostion={signerPos}
setDefaultSignAlert={setDefaultSignAlert}
/>
)}
</div>
</div>
</div>
<div className="w-full md:w-[23%] bg-base-100 overflow-y-auto hide-scrollbar hidden md:inline-block">
<div className={`max-h-screen`}>
{signedSigners.length > 0 && (
<>
<div
data-tut="reactourSecond"
className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300"
>
<span> Signed by</span>
</div>
<div className="mt-[2px]">
{signedSigners.map((obj, ind) => {
return (
<div key={ind}>
<SignerListComponent
ind={ind}
obj={obj}
isMenu={isHeader}
signerPos={signerPos}
/>
</div>
);
})}
</div>
</>
)}
{unsignedSigners.length > 0 && (
<>
<div
data-tut="reactourFirst"
className="mx-2 pr-2 pt-2 pb-1 text-[15px] text-base-content font-semibold border-b-[1px] border-base-300"
>
<span>Yet to sign</span>
</div>
<div className="mt-[5px]">
{unsignedSigners.map((obj, ind) => {
return (
<div key={ind}>
<SignerListComponent
ind={ind}
obj={obj}
isMenu={isHeader}
signerPos={signerPos}
/>
</div>
);
})}
</div>
</>
)}
{defaultSignImg && !alreadySign && currentSigner && (
<DefaultSignature
defaultSignImg={defaultSignImg}
setDefaultSignImg={setDefaultSignImg}
userObjectId={signerObjectId}
setIsLoading={setIsLoading}
xyPostion={signerPos}
setDefaultSignAlert={setDefaultSignAlert}
/>
)}
</div>
</div>
</div>
</div>
)}
<ModalUi
isOpen={validateAlert}
title={"Validation alert"}
handleClose={() => {
setValidateAlert(false);
}}
handleClose={() => setValidateAlert(false)}
>
<div className="h-[100%] p-[20px]">
<p>
+80 -85
View File
@@ -1,4 +1,5 @@
import React, { useState, useEffect } from "react";
import "../styles/pgsignup.css";
import Parse from "parse";
import axios from "axios";
import { useDispatch } from "react-redux";
@@ -408,101 +409,95 @@ const PgSignUp = () => {
}
};
return (
<div className="w-full h-screen">
<div className="bg-white">
<Title title={"Pgsignup page"} />
{isLoader ? (
<div className="flex justify-center items-center h-[100vh]">
<Loader />
</div>
) : (
<div className="py-10 lg:p-16 flex justify-center">
<form
id="signup"
className="w-[90%] md:w-[55%] bg-base-100 text-base-content op-card shadow-md"
onSubmit={handleSubmit}
>
<div className="p-[16px]">
<h1 className="text-2xl md:text-3xl font-bold">
Choose Password
</h1>
<hr className="border-[1px] border-[#cecece] mb-[5px]" />
<label htmlFor="password">
<b className="text-[13px]">Password</b>
</label>
<input
type="password"
placeholder="Enter Password"
name="password"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
value={formData.password}
onChange={handlePassowordChange}
required
/>
<label htmlFor="confirmPassword">
<b className="text-[13px]">Confirm Password</b>
</label>
<input
type="password"
placeholder="Confirm Password"
name="confirmPassword"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
style={{
border: validationMessage
? validationMessage === "Passwords match!"
? "1px solid green"
: "1px solid red"
: ""
}}
value={formData.confirmPassword}
onChange={handleConFirmPassowordChange}
required
/>
<div
className={`${
validationMessage === "Passwords match!"
? "text-[green]"
: "text-[red]"
} ml-[13px] text-[11px]`}
>
{validationMessage}
<form id="signup" className="pgsignup-content" onSubmit={handleSubmit}>
<div className="pgsignup-container">
<h1 className="text-2xl md:text-3xl font-bold">Choose Password</h1>
<hr className="hrt" />
<label htmlFor="password">
<b className="text-[13px]">Password</b>
</label>
<input
type="password"
placeholder="Enter Password"
name="password"
className="inputt"
value={formData.password}
onChange={handlePassowordChange}
required
/>
<label htmlFor="confirmPassword">
<b className="text-[13px]">Confirm Password</b>
</label>
<input
type="password"
placeholder="Confirm Password"
name="confirmPassword"
className="confirmInputt"
style={{
border: validationMessage
? validationMessage === "Passwords match!"
? "2px solid green"
: "2px solid red"
: "2px solid transparent",
outline: "none"
}}
value={formData.confirmPassword}
onChange={handleConFirmPassowordChange}
required
/>
<div
className="icon"
style={{
margin: validationMessage ? "0 2px 0 2px" : "0 2px 22px 2px",
color:
validationMessage === "Passwords match!" ? "green" : "red",
fontSize: 11
}}
>
{validationMessage}
</div>
{formData.password.length > 0 && (
<div className="mt-1 text-[11px]">
<p
className={`${
lengthValid ? "text-green-600" : "text-red-600"
}`}
>
{lengthValid ? "✓" : "✗"} Password should be 8 characters long
</p>
<p
className={`${
caseDigitValid ? "text-green-600" : "text-red-600"
}`}
>
{caseDigitValid ? "✓" : "✗"} Password should contain uppercase
letter, lowercase letter, digit
</p>
<p
className={`${
specialCharValid ? "text-green-600" : "text-red-600"
}`}
>
{specialCharValid ? "✓" : "✗"} Password should contain special
character
</p>
</div>
{formData.password.length > 0 && (
<div className="mt-1 text-[11px]">
<p
className={`${
lengthValid ? "text-green-600" : "text-red-600"
}`}
>
{lengthValid ? "✓" : "✗"} Password should be 8 characters
long
</p>
<p
className={`${
caseDigitValid ? "text-green-600" : "text-red-600"
}`}
>
{caseDigitValid ? "✓" : "✗"} Password should contain
uppercase letter, lowercase letter, digit
</p>
<p
className={`${
specialCharValid ? "text-green-600" : "text-red-600"
}`}
>
{specialCharValid ? "✓" : "✗"} Password should contain
special character
</p>
</div>
)}
<button
type="submit"
className="op-btn op-btn-primary w-full mt-[8px]"
>
)}
<div className="clearfix">
<button type="submit" className="signupbtn">
Submit
</button>
</div>
</form>
</div>
</div>
</form>
)}
</div>
);
File diff suppressed because it is too large Load Diff
+290 -365
View File
@@ -17,6 +17,7 @@ import {
contractDocument,
embedDocId,
multiSignEmbed,
pdfNewWidthFun,
onImageSelect,
calculateInitialWidthHeight,
defaultWidthHeight,
@@ -30,7 +31,6 @@ import {
getTenantDetails,
checkIsSubscribed,
convertPdfArrayBuffer,
textInputWidget,
fetchImageBase64,
changeImageWH,
handleSendOTP
@@ -46,10 +46,7 @@ import TourContentWithBtn from "../primitives/TourContentWithBtn";
import Title from "../components/Title";
import ModalUi from "../primitives/ModalUi";
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
import { useSelector } from "react-redux";
import TextFontSetting from "../components/pdf/TextFontSetting";
import VerifyEmail from "../components/pdf/VerifyEmail";
import PdfZoom from "../components/pdf/PdfZoom";
import Loader from "../primitives/Loader";
//For signYourself inProgress section signer can add sign and complete doc sign.
function SignYourSelf() {
@@ -71,12 +68,10 @@ function SignYourSelf() {
const signRef = useRef(null);
const dragRef = useRef(null);
const [dragKey, setDragKey] = useState();
const [fontSize, setFontSize] = useState(11);
const [fontColor, setFontColor] = useState("black");
const [signKey, setSignKey] = useState();
const [imgWH, setImgWH] = useState({});
const [pdfNewWidth, setPdfNewWidth] = useState();
const [pdfOriginalWH, setPdfOriginalWH] = useState([]);
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
const [successEmail, setSuccessEmail] = useState(false);
const imageRef = useRef(null);
const [myInitial, setMyInitial] = useState("");
@@ -102,11 +97,13 @@ function SignYourSelf() {
const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({
status: false
});
const [isTextSetting, setIsTextSetting] = useState(false);
const [currWidgetsDetails, setCurrWidgetsDetails] = useState({});
const [isCheckbox, setIsCheckbox] = useState(false);
const [widgetType, setWidgetType] = useState("");
const [pdfLoad, setPdfLoad] = useState(false);
const [pdfLoadFail, setPdfLoadFail] = useState({
status: false,
type: "load"
});
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
const [isDontShow, setIsDontShow] = useState(false);
const [extUserId, setExtUserId] = useState("");
@@ -117,9 +114,6 @@ function SignYourSelf() {
const [isEmailVerified, setIsEmailVerified] = useState(true);
const [isVerifyModal, setIsVerifyModal] = useState(false);
const [otp, setOtp] = useState("");
const [zoomPercent, setZoomPercent] = useState(0);
const isHeader = useSelector((state) => state.showHeader);
const [scale, setScale] = useState(1);
const divRef = useRef(null);
const nodeRef = useRef(null);
const [, drop] = useDrop({
@@ -129,7 +123,10 @@ function SignYourSelf() {
isOver: !!monitor.isOver()
})
});
const isMobile = window.innerWidth < 767;
const pdfRef = useRef();
const [{ isDragSign }, dragSignature] = useDrag({
type: "BOX",
item: {
@@ -157,6 +154,7 @@ function SignYourSelf() {
return object.pageNumber === pageNumber;
});
// rowlevel={JSON.parse(localStorage.getItem("rowlevel"))}
const rowLevel =
localStorage.getItem("rowlevel") &&
JSON.parse(localStorage.getItem("rowlevel"));
@@ -184,25 +182,17 @@ function SignYourSelf() {
}, []);
useEffect(() => {
const updateSize = () => {
if (divRef.current) {
const pdfWidth = divRef.current.offsetWidth;
setPdfNewWidth(pdfWidth);
setContainerWH({
width: divRef.current.offsetWidth,
height: divRef.current.offsetHeight
});
setScale(1);
setZoomPercent(0);
}
};
// Use setTimeout to wait for the transition to complete
const timer = setTimeout(updateSize, 100); // match the transition duration
return () => clearTimeout(timer);
if (divRef.current) {
const pdfWidth = pdfNewWidthFun(divRef);
setPdfNewWidth(pdfWidth);
setContainerWH({
width: divRef.current.offsetWidth,
height: divRef.current.offsetHeight
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [divRef.current, isHeader]);
}, [divRef.current]);
//function for get document details for perticular signer with signer'object id
const getDocumentDetails = async (showComplete) => {
let isCompleted;
@@ -224,17 +214,14 @@ function SignYourSelf() {
} else {
setHandleError("Error: Something went wrong!");
}
isCompleted = documentData[0].IsCompleted && documentData[0].IsCompleted;
if (isCompleted) {
setIsCelebration(true);
setTimeout(() => {
setIsCelebration(false);
}, 5000);
setIsCompleted(true);
setPdfUrl(documentData[0].SignedUrl);
const alreadySign = {
status: true,
mssg: "Congratulations! 🎉 This document has been successfully signed by you!"
mssg: "You have successfully signed the document!"
};
if (showComplete) {
setShowAlreadySignDoc(alreadySign);
@@ -242,8 +229,12 @@ function SignYourSelf() {
setIsUiLoading(false);
setIsSignPad(false);
setIsEmail(true);
setIsCelebration(true);
setXyPostion([]);
setSignBtnPosition([]);
setTimeout(() => {
setIsCelebration(false);
}, 5000);
}
}
} else if (
@@ -451,69 +442,61 @@ function SignYourSelf() {
);
const dragTypeValue = item?.text ? item.text : monitor.type;
const widgetValue = getWidgetValue(dragTypeValue);
const widgetWidth = defaultWidthHeight(dragTypeValue).width;
const widgetHeight = defaultWidthHeight(dragTypeValue).height;
const widgetTypeExist = ["name", "company", "job title", "email"].includes(
dragTypeValue
);
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
);
const containerScale = containerWH?.width / getPdfPageWidth?.width || 1;
//adding and updating drop position in array when user drop signature button in div
if (item === "onclick") {
const getWidth = widgetTypeExist
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
: dragTypeValue === "initials"
? defaultWidthHeight(dragTypeValue).width
: "";
const getHeight = widgetTypeExist
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
: dragTypeValue === "initials"
? defaultWidthHeight(dragTypeValue).height
: "";
dropObj = {
xPosition: containerWH.width / 2,
yPosition: containerWH.height / 2,
xPosition: containerWH.width / 2 - widgetWidth / 2,
yPosition: containerWH.height / 2 - widgetHeight / 2,
isDrag: false,
isStamp:
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
key: key,
type: dragTypeValue,
scale: containerScale,
Width: getWidth / (containerScale * scale),
Height: getHeight / (containerScale * scale),
yBottom: window.innerHeight / 2 - 60,
Width: widgetTypeExist
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
: dragTypeValue === "initials"
? defaultWidthHeight(dragTypeValue).width
: "",
Height: widgetTypeExist
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
: dragTypeValue === "initials"
? defaultWidthHeight(dragTypeValue).height
: "",
options: addWidgetOptions(dragTypeValue)
};
dropData.push(dropObj);
} else {
//This method returns the offset of the current pointer (mouse) position relative to the client viewport.
const offset = monitor.getClientOffset();
//adding and updating drop position in array when user drop signature button in div
const containerRect = document
.getElementById("container")
.getBoundingClientRect();
//`containerRect.left`, The distance from the left of the viewport to the left side of the element.
//`containerRect.top` The distance from the top of the viewport to the top of the element.
const x = offset.x - containerRect.left;
const y = offset.y - containerRect.top;
const getXPosition = signBtnPosition[0] ? x - signBtnPosition[0].xPos : x;
const getYPosition = signBtnPosition[0] ? y - signBtnPosition[0].yPos : y;
const getWidth = widgetTypeExist
? calculateInitialWidthHeight(widgetValue).getWidth
: defaultWidthHeight(dragTypeValue).width;
const getHeight = widgetTypeExist
? calculateInitialWidthHeight(widgetValue).getHeight
: defaultWidthHeight(dragTypeValue).height;
dropObj = {
xPosition: getXPosition / (containerScale * scale),
yPosition: getYPosition / (containerScale * scale),
xPosition: signBtnPosition[0] ? x - signBtnPosition[0].xPos : x,
yPosition: signBtnPosition[0] ? y - signBtnPosition[0].yPos : y,
// isDrag: false,
isStamp:
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
key: key,
type: dragTypeValue,
Width: getWidth / (containerScale * scale),
Height: getHeight / (containerScale * scale),
options: addWidgetOptions(dragTypeValue),
scale: containerScale
Width: widgetTypeExist
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
: defaultWidthHeight(dragTypeValue).width,
Height: widgetTypeExist
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
: defaultWidthHeight(dragTypeValue).height,
options: addWidgetOptions(dragTypeValue)
};
dropData.push(dropObj);
@@ -523,12 +506,16 @@ function SignYourSelf() {
return object.pageNumber === pageNumber;
});
const updateData = filterDropPos[0].pos;
// if (updateData.length > dropData.length) {
const newSignPos = updateData.concat(dropData);
let xyPos = {
pageNumber: pageNumber,
pos: newSignPos
};
xyPostion.splice(index, 1, xyPos);
// }
} else {
const xyPos = {
pageNumber: pageNumber,
@@ -552,18 +539,6 @@ function SignYourSelf() {
setIsInitial(true);
} else if (dragTypeValue === "checkbox") {
setIsCheckbox(true);
} else if (
[
textInputWidget,
textWidget,
"name",
"company",
"job title",
"email"
].includes(dragTypeValue)
) {
setFontSize(12);
setFontColor("black");
}
setWidgetType(dragTypeValue);
setSelectWidgetId(key);
@@ -694,14 +669,13 @@ function SignYourSelf() {
const pdfBytes = await multiSignEmbed(
xyPostion,
pdfDoc,
pdfOriginalWidth,
isSignYourSelfFlow,
scale
containerWH
);
// console.log("pdf", pdfBytes);
//function for call to embed signature in pdf and get digital signature pdf
if (pdfBytes) {
await signPdfFun(pdfBytes, documentId);
}
await signPdfFun(pdfBytes, documentId);
} catch (err) {
setIsUiLoading(false);
if (err && err.message.includes("is encrypted.")) {
@@ -807,18 +781,22 @@ function SignYourSelf() {
setDragKey(key);
setIsDragging(true);
};
//function for set and update x and y postion after drag and drop signature tab
const handleStop = (event, dragElement) => {
if (isDragging && dragElement) {
event.preventDefault();
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
);
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
const containerRect = document
.getElementById("container")
.getBoundingClientRect();
const ybottom = containerRect.height - dragElement.y;
if (dragKey >= 0) {
const filterDropPos = xyPostion.filter(
(data) => data.pageNumber === pageNumber
);
if (filterDropPos.length > 0) {
const getXYdata = xyPostion[index].pos;
const getPosData = getXYdata;
@@ -826,8 +804,10 @@ function SignYourSelf() {
if (url.key === dragKey) {
return {
...url,
xPosition: dragElement.x / (containerScale * scale),
yPosition: dragElement.y / (containerScale * scale)
xPosition: dragElement.x,
yPosition: dragElement.y,
isDrag: true,
yBottom: ybottom
};
}
return url;
@@ -847,24 +827,26 @@ function SignYourSelf() {
setIsDragging(false);
}, 200);
};
//function for get pdf page details
const pageDetails = async (pdf) => {
let pdfWHObj = [];
const totalPages = pdf?.numPages;
for (let index = 0; index < totalPages; index++) {
const getPage = await pdf.getPage(index + 1);
const scale = 1;
const { width, height } = getPage.getViewport({ scale });
pdfWHObj.push({ pageNumber: index + 1, width, height });
}
setPdfOriginalWH(pdfWHObj);
setPdfLoad(true);
const load = {
status: true
};
setPdfLoadFail(load);
pdf.getPage(1).then((pdfPage) => {
const pageWidth = pdfPage.view[2];
setPdfOriginalWidth(pageWidth);
});
};
//function for change page numver of pdf
function changePage(offset) {
setSignBtnPosition([]);
setPageNumber((prevPageNumber) => prevPageNumber + offset);
}
//function for image upload or update
const onImageChange = (event) => {
if (event.target.files && event.target.files[0]) {
@@ -914,30 +896,18 @@ function SignYourSelf() {
setXyPostion(getUpdatePosition);
};
//function for capture position on hover or touch widgets button
//function for capture position on hover signature button
const handleDivClick = (e) => {
const isTouchEvent = e.type.startsWith("touch");
const divRect = e.currentTarget.getBoundingClientRect();
let mouseX, mouseY;
if (isTouchEvent) {
const touch = e.touches[0]; // Get the first touch point
mouseX = touch.clientX - divRect.left;
mouseY = touch.clientY - divRect.top;
setSignBtnPosition([
{
xPos: mouseX,
yPos: mouseY
}
]);
} else {
mouseX = e.clientX - divRect.left;
mouseY = e.clientY - divRect.top;
const xyPosition = {
xPos: mouseX,
yPos: mouseY
};
setXYSignature(xyPosition);
}
const mouseX = e.clientX - divRect.left;
const mouseY = e.clientY - divRect.top;
const xyPosition = {
xPos: mouseX,
yPos: mouseY
};
setXYSignature(xyPosition);
};
//function for capture position of x and y on hover signature button last position
@@ -985,7 +955,7 @@ function SignYourSelf() {
};
const tourConfig = [
{
selector: '[data-tut="addWidgets"]',
selector: '[data-tut="reactourFirst"]',
content: () => (
<TourContentWithBtn
message={`Select and drag your preferred widgets onto the PDF to customize your document before signing. Choose the perfect spots for each modification to tailor the document to your needs.`}
@@ -1113,47 +1083,11 @@ function SignYourSelf() {
}
}
};
const handleCloseModal = () => {
setCurrWidgetsDetails({});
setIsCheckbox(false);
};
const handleTextSettingModal = (value) => {
setIsTextSetting(value);
};
const handleSaveFontSize = () => {
const getPageNumer = xyPostion.filter(
(data) => data.pageNumber === pageNumber
);
if (getPageNumer.length > 0) {
const getXYdata = getPageNumer[0].pos;
const getPosData = getXYdata;
const addSignPos = getPosData.map((position) => {
if (position.key === signKey) {
return {
...position,
options: {
...position.options,
fontSize: fontSize || currWidgetsDetails?.options?.fontSize,
fontColor: fontColor || currWidgetsDetails?.options?.fontColor
}
};
}
return position;
});
const updateXYposition = xyPostion.map((obj, ind) => {
if (ind === index) {
return { ...obj, pos: addSignPos };
}
return obj;
});
setXyPostion(updateXYposition);
setFontSize();
setFontColor();
handleTextSettingModal(false);
}
};
return (
<DndProvider backend={HTML5Backend}>
<Title title={"Self Sign"} />
@@ -1164,20 +1098,23 @@ function SignYourSelf() {
) : (
<div>
{isUiLoading && (
<div className="absolute h-[100vh] w-full z-[999] flex flex-col justify-center items-center bg-[#e6f2f2] bg-opacity-80">
<div className="absolute h-[100vh] w-full z-[999] flex flex-col justify-center items-start bg-[#e6f2f2] bg-opacity-80">
<Loader />
<span style={{ fontSize: "13px", fontWeight: "bold" }}>
<span className="font-bold text-[13px]">
This might take some time
</span>
</div>
)}
{isCelebration && (
<div className="relative z-[1000]">
<div className="relative z-[999]">
<Confetti width={window.innerWidth} height={window.innerHeight} />
</div>
)}
<div className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300">
<div
className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300"
ref={divRef}
>
{!isEmailVerified && (
<VerifyEmail
isVerifyModal={isVerifyModal}
@@ -1191,7 +1128,7 @@ function SignYourSelf() {
/>
)}
{/* this component used for UI interaction and show their functionality */}
{pdfLoad && !checkTourStatus && (
{pdfLoadFail && !checkTourStatus && (
<Tour
onRequestClose={closeTour}
steps={tourConfig}
@@ -1212,198 +1149,196 @@ function SignYourSelf() {
setPageNumber={setPageNumber}
setSignBtnPosition={setSignBtnPosition}
pageNumber={pageNumber}
containerWH={containerWH}
/>
<div className=" w-full md:w-[57%] flex mr-4">
<PdfZoom
setScale={setScale}
scale={scale}
containerWH={containerWH}
setZoomPercent={setZoomPercent}
zoomPercent={zoomPercent}
/>
<div className=" w-full md:w-[95%] ">
<ModalUi
isOpen={isAlert.isShow}
title={isAlert?.header || "Alert"}
handleClose={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
>
<div className="p-[20px] h-full">
<p>{isAlert.alertMessage}</p>
</div>
</ModalUi>
{/* this modal is used show this document is already sign */}
<ModalUi
isOpen={showAlreadySignDoc.status}
title={"Document signed"}
handleClose={() => {
setShowAlreadySignDoc({ status: false });
}}
>
<div className="p-[20px] h-full">
<p>{showAlreadySignDoc.mssg}</p>
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
<button
className="op-btn op-btn-ghost shadow-md"
onClick={() => setShowAlreadySignDoc({ status: false })}
>
Close
</button>
</div>
</ModalUi>
<DropdownWidgetOption
type="checkbox"
title="Checkbox"
showDropdown={isCheckbox}
setShowDropdown={setIsCheckbox}
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
isSignYourself={true}
handleClose={handleCloseModal}
/>
<PlaceholderCopy
isPageCopy={isPageCopy}
setIsPageCopy={setIsPageCopy}
xyPostion={xyPostion}
setXyPostion={setXyPostion}
allPages={allPages}
pageNumber={pageNumber}
signKey={signKey}
/>
{/* this is modal of signature pad */}
<SignPad
isSignPad={isSignPad}
isStamp={isStamp}
setIsImageSelect={setIsImageSelect}
setIsSignPad={setIsSignPad}
setImage={setImage}
isImageSelect={isImageSelect}
imageRef={imageRef}
onImageChange={onImageChange}
setSignature={setSignature}
image={image}
onSaveImage={saveImage}
onSaveSign={saveSign}
defaultSign={defaultSignImg}
myInitial={myInitial}
isInitial={isInitial}
setIsInitial={setIsInitial}
setIsStamp={setIsStamp}
widgetType={widgetType}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
/>
{/*render email component to send email after finish signature on document */}
<EmailComponent
isEmail={isEmail}
pdfUrl={pdfUrl}
setIsEmail={setIsEmail}
pdfName={pdfDetails[0] && pdfDetails[0].Name}
setSuccessEmail={setSuccessEmail}
sender={jsonSender}
setIsAlert={setIsAlert}
extUserId={extUserId}
activeMailAdapter={activeMailAdapter}
/>
{/* pdf header which contain funish back button */}
<Header
pageNumber={pageNumber}
allPages={allPages}
changePage={changePage}
pdfUrl={pdfUrl}
embedWidgetsData={embedWidgetsData}
pdfDetails={pdfDetails}
isShowHeader={true}
currentSigner={true}
alreadySign={pdfUrl ? true : false}
isSignYourself={true}
setIsEmail={setIsEmail}
isCompleted={isCompleted}
/>
<div
ref={divRef}
data-tut="reactourSecond"
className="h-full md:h-[95%]"
>
{containerWH?.width && containerWH?.height && (
<RenderPdf
pageNumber={pageNumber}
pdfOriginalWH={pdfOriginalWH}
pdfNewWidth={pdfNewWidth}
drop={drop}
successEmail={successEmail}
nodeRef={nodeRef}
handleTabDrag={handleTabDrag}
handleStop={handleStop}
isDragging={isDragging}
setIsSignPad={setIsSignPad}
setIsStamp={setIsStamp}
handleDeleteSign={handleDeleteSign}
setSignKey={setSignKey}
pdfDetails={pdfDetails}
setIsDragging={setIsDragging}
xyPostion={xyPostion}
pdfRef={pdfRef}
pdfUrl={pdfUrl}
numPages={numPages}
pageDetails={pageDetails}
pdfLoad={pdfLoad}
setPdfLoad={setPdfLoad}
setXyPostion={setXyPostion}
index={index}
containerWH={containerWH}
setIsPageCopy={setIsPageCopy}
setIsInitial={setIsInitial}
setWidgetType={setWidgetType}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
setIsCheckbox={setIsCheckbox}
setCurrWidgetsDetails={setCurrWidgetsDetails}
setValidateAlert={setValidateAlert}
handleTextSettingModal={handleTextSettingModal}
setScale={setScale}
scale={scale}
/>
)}
{/* pdf render view */}
<div
style={{
marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px",
marginRight: !isMobile && pdfOriginalWidth > 500 && "20px"
}}
>
<ModalUi
isOpen={isAlert.isShow}
title={isAlert?.header || "Alert"}
handleClose={() => {
setIsAlert({
isShow: false,
alertMessage: ""
});
}}
>
<div className="p-[20px] h-full">
<p>{isAlert.alertMessage}</p>
</div>
</div>
</div>
<div className="w-full md:w-[23%] bg-base-100 overflow-y-auto hide-scrollbar">
<div className={`max-h-screen`}>
{!isCompleted ? (
<div>
<WidgetComponent
pdfUrl={pdfUrl}
dragSignature={dragSignature}
signRef={signRef}
handleDivClick={handleDivClick}
handleMouseLeave={handleMouseLeave}
isDragSign={isDragSign}
dragStamp={dragStamp}
dragRef={dragRef}
isDragStamp={isDragStamp}
handleAllDelete={handleAllDelete}
xyPostion={xyPostion}
isSignYourself={true}
addPositionOfSignature={addPositionOfSignature}
isMailSend={false}
/>
</div>
) : (
<div>
<Signedby pdfDetails={pdfDetails[0]} />
</div>
</ModalUi>
{/* this modal is used show this document is already sign */}
<ModalUi
isOpen={showAlreadySignDoc.status}
title={"Document signed"}
handleClose={() => {
setShowAlreadySignDoc({ status: false });
}}
>
<div className="p-[20px] h-full">
<p>{showAlreadySignDoc.mssg}</p>
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
<button
className="op-btn op-btn-ghost shadow-md"
onClick={() => setShowAlreadySignDoc({ status: false })}
>
Close
</button>
</div>
</ModalUi>
<DropdownWidgetOption
type="checkbox"
title="Checkbox"
showDropdown={isCheckbox}
setShowDropdown={setIsCheckbox}
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
isSignYourself={true}
handleClose={handleCloseModal}
/>
<PlaceholderCopy
isPageCopy={isPageCopy}
setIsPageCopy={setIsPageCopy}
xyPostion={xyPostion}
setXyPostion={setXyPostion}
allPages={allPages}
pageNumber={pageNumber}
signKey={signKey}
/>
{/* this is modal of signature pad */}
<SignPad
isSignPad={isSignPad}
isStamp={isStamp}
setIsImageSelect={setIsImageSelect}
setIsSignPad={setIsSignPad}
setImage={setImage}
isImageSelect={isImageSelect}
imageRef={imageRef}
onImageChange={onImageChange}
setSignature={setSignature}
image={image}
onSaveImage={saveImage}
onSaveSign={saveSign}
defaultSign={defaultSignImg}
myInitial={myInitial}
isInitial={isInitial}
setIsInitial={setIsInitial}
setIsStamp={setIsStamp}
widgetType={widgetType}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
/>
{/*render email component to send email after finish signature on document */}
<EmailComponent
isEmail={isEmail}
pdfUrl={pdfUrl}
setIsEmail={setIsEmail}
pdfName={pdfDetails[0] && pdfDetails[0].Name}
setSuccessEmail={setSuccessEmail}
sender={jsonSender}
setIsAlert={setIsAlert}
extUserId={extUserId}
activeMailAdapter={activeMailAdapter}
/>
{/* pdf header which contain funish back button */}
<Header
pageNumber={pageNumber}
allPages={allPages}
changePage={changePage}
pdfUrl={pdfUrl}
embedWidgetsData={embedWidgetsData}
pdfDetails={pdfDetails}
isShowHeader={true}
currentSigner={true}
alreadySign={pdfUrl ? true : false}
isSignYourself={true}
setIsEmail={setIsEmail}
isCompleted={isCompleted}
/>
<div data-tut="reactourSecond">
{containerWH && (
<RenderPdf
pageNumber={pageNumber}
pdfOriginalWidth={pdfOriginalWidth}
pdfNewWidth={pdfNewWidth}
drop={drop}
successEmail={successEmail}
nodeRef={nodeRef}
handleTabDrag={handleTabDrag}
handleStop={handleStop}
isDragging={isDragging}
setIsSignPad={setIsSignPad}
setIsStamp={setIsStamp}
handleDeleteSign={handleDeleteSign}
setSignKey={setSignKey}
pdfDetails={pdfDetails}
setIsDragging={setIsDragging}
xyPostion={xyPostion}
pdfRef={pdfRef}
pdfUrl={pdfUrl}
numPages={numPages}
pageDetails={pageDetails}
setPdfLoadFail={setPdfLoadFail}
pdfLoadFail={pdfLoadFail}
setXyPostion={setXyPostion}
index={index}
containerWH={containerWH}
setIsPageCopy={setIsPageCopy}
setIsInitial={setIsInitial}
setWidgetType={setWidgetType}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
setIsCheckbox={setIsCheckbox}
setCurrWidgetsDetails={setCurrWidgetsDetails}
setValidateAlert={setValidateAlert}
/>
)}
</div>
</div>
{/*if document is not completed then render signature and stamp button in the right side */}
{/*else document is completed then render signed by signer name in the right side */}
<div
style={{
maxHeight: window.innerHeight - 70 + "px",
backgroundColor: "white"
}}
className="overflow-y-auto hide-scrollbar"
>
{!isCompleted ? (
<div>
<WidgetComponent
dataTut="reactourFirst"
pdfUrl={pdfUrl}
dragSignature={dragSignature}
signRef={signRef}
handleDivClick={handleDivClick}
handleMouseLeave={handleMouseLeave}
isDragSign={isDragSign}
dragStamp={dragStamp}
dragRef={dragRef}
isDragStamp={isDragStamp}
handleAllDelete={handleAllDelete}
xyPostion={xyPostion}
isSignYourself={true}
addPositionOfSignature={addPositionOfSignature}
isMailSend={false}
/>
</div>
) : (
<div>
<Signedby pdfDetails={pdfDetails[0]} />
</div>
)}
</div>
</div>
</div>
)}
@@ -1429,16 +1364,6 @@ function SignYourSelf() {
</button>
</div>
</ModalUi>
<TextFontSetting
isTextSetting={isTextSetting}
setIsTextSetting={setIsTextSetting}
fontSize={fontSize}
setFontSize={setFontSize}
fontColor={fontColor}
setFontColor={setFontColor}
handleSaveFontSize={handleSaveFontSize}
currWidgetsDetails={currWidgetsDetails}
/>
</DndProvider>
);
}
+359 -478
View File
@@ -37,12 +37,8 @@ import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
import TourContentWithBtn from "../primitives/TourContentWithBtn";
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
import Parse from "parse";
import { useSelector } from "react-redux";
import TextFontSetting from "../components/pdf/TextFontSetting";
import PdfZoom from "../components/pdf/PdfZoom";
const TemplatePlaceholder = () => {
const navigate = useNavigate();
const isHeader = useSelector((state) => state.showHeader);
const { templateId } = useParams();
const [pdfDetails, setPdfDetails] = useState([]);
const [isMailSend, setIsMailSend] = useState(false);
@@ -70,7 +66,7 @@ const TemplatePlaceholder = () => {
const [checkTourStatus, setCheckTourStatus] = useState(false);
const [tourStatus, setTourStatus] = useState([]);
const [signerUserId, setSignerUserId] = useState();
const [pdfOriginalWH, setPdfOriginalWH] = useState([]);
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
const [contractName, setContractName] = useState("");
const [containerWH, setContainerWH] = useState();
const signRef = useRef(null);
@@ -87,8 +83,10 @@ const TemplatePlaceholder = () => {
const [blockColor, setBlockColor] = useState("");
const [selectWidgetId, setSelectWidgetId] = useState("");
const [isNameModal, setIsNameModal] = useState(false);
const [isTextSetting, setIsTextSetting] = useState(false);
const [pdfLoad, setPdfLoad] = useState(false);
const [pdfLoadFail, setPdfLoadFail] = useState({
status: false,
type: "load"
});
const color = [
"#93a3db",
"#e6c3db",
@@ -149,10 +147,6 @@ const TemplatePlaceholder = () => {
const [isCheckbox, setIsCheckbox] = useState(false);
const [widgetName, setWidgetName] = useState(false);
const [isAddRole, setIsAddRole] = useState(false);
const [fontSize, setFontSize] = useState();
const [fontColor, setFontColor] = useState();
const [zoomPercent, setZoomPercent] = useState(0);
const [scale, setScale] = useState(1);
const senderUser =
localStorage.getItem(
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
@@ -168,25 +162,16 @@ const TemplatePlaceholder = () => {
}, []);
useEffect(() => {
const updateSize = () => {
if (divRef.current) {
const pdfWidth = pdfNewWidthFun(divRef);
setPdfNewWidth(pdfWidth);
setContainerWH({
width: divRef.current.offsetWidth,
height: divRef.current.offsetHeight
});
setScale(1);
setZoomPercent(0);
}
};
// Use setTimeout to wait for the transition to complete
const timer = setTimeout(updateSize, 100); // match the transition duration
return () => clearTimeout(timer);
if (divRef.current) {
const pdfWidth = pdfNewWidthFun(divRef);
setPdfNewWidth(pdfWidth);
setContainerWH({
width: divRef.current.offsetWidth,
height: divRef.current.offsetHeight
});
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [divRef.current, isHeader]);
}, [divRef.current]);
async function checkIsSubscribed() {
const res = await fetchSubscription();
const freeplan = res.plan;
@@ -365,36 +350,29 @@ const TemplatePlaceholder = () => {
if (signer) {
const posZIndex = zIndex + 1;
setZIndex(posZIndex);
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
);
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
const newWidth = containerWH.width;
const scale = pdfOriginalWidth / newWidth;
const key = randomId();
// let filterSignerPos = signerPos.filter(
// (data) => data.signerObjId === signerObjId
// );
let filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
const dragTypeValue = item?.text ? item.text : monitor.type;
const widgetWidth = defaultWidthHeight(dragTypeValue).width;
const widgetHeight = defaultWidthHeight(dragTypeValue).height;
let dropData = [];
let placeHolder;
if (item === "onclick") {
const dropObj = {
//onclick put placeholder center on pdf
xPosition:
(containerWH.width / 2 - widgetWidth / 2) /
(containerScale * scale),
yPosition:
(containerWH.height / 2 - widgetHeight / 2) /
(containerScale * scale),
xPosition: window.innerWidth / 2 - 150,
yPosition: window.innerHeight / 2 - 60,
isStamp:
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
key: key,
scale: containerScale,
// isMobile: isMobile,
scale: scale,
isMobile: isMobile,
zIndex: posZIndex,
type: dragTypeValue,
options: addWidgetOptions(dragTypeValue),
Width: widgetWidth / (containerScale * scale),
Height: widgetHeight / (containerScale * scale)
options: addWidgetOptions(dragTypeValue)
};
dropData.push(dropObj);
placeHolder = {
@@ -409,25 +387,17 @@ const TemplatePlaceholder = () => {
.getBoundingClientRect();
const x = offset.x - containerRect.left;
const y = offset.y - containerRect.top;
const getXPosition = signBtnPosition[0]
? x - signBtnPosition[0].xPos
: x;
const getYPosition = signBtnPosition[0]
? y - signBtnPosition[0].yPos
: y;
const dropObj = {
xPosition: getXPosition / (containerScale * scale),
yPosition: getYPosition / (containerScale * scale),
xPosition: signBtnPosition[0] ? x - signBtnPosition[0].xPos : x,
yPosition: signBtnPosition[0] ? y - signBtnPosition[0].yPos : y,
isStamp:
(dragTypeValue === "stamp" || dragTypeValue === "image") && true,
key: key,
scale: containerScale,
// isMobile: isMobile,
scale: scale,
isMobile: isMobile,
zIndex: posZIndex,
type: item.text,
options: addWidgetOptions(dragTypeValue),
Width: widgetWidth / (containerScale * scale),
Height: widgetHeight / (containerScale * scale)
options: addWidgetOptions(dragTypeValue)
};
dropData.push(dropObj);
@@ -501,13 +471,6 @@ const TemplatePlaceholder = () => {
setShowDropdown(true);
} else if (dragTypeValue === "checkbox") {
setIsCheckbox(true);
} else if (
[textInputWidget, "name", "company", "job title", "email"].includes(
dragTypeValue
)
) {
setFontSize(12);
setFontColor("black");
} else if (dragTypeValue === radioButtonWidget) {
setIsRadio(true);
}
@@ -536,16 +499,14 @@ const TemplatePlaceholder = () => {
//function for get pdf page details
const pageDetails = async (pdf) => {
let pdfWHObj = [];
const totalPages = pdf?.numPages;
for (let index = 0; index < totalPages; index++) {
const getPage = await pdf.getPage(index + 1);
const scale = 1;
const { width, height } = getPage.getViewport({ scale });
pdfWHObj.push({ pageNumber: index + 1, width, height });
}
setPdfOriginalWH(pdfWHObj);
setPdfLoad(true);
const load = {
status: true
};
setPdfLoadFail(load);
pdf.getPage(1).then((pdfPage) => {
const pageWidth = pdfPage.view[2];
setPdfOriginalWidth(pageWidth);
});
};
//function for save x and y position and show signature tab on that position
const handleTabDrag = (key) => {
@@ -559,12 +520,14 @@ const TemplatePlaceholder = () => {
const dataNewPlace = addZIndex(signerPos, key, setZIndex);
let updateSignPos = [...signerPos];
updateSignPos.splice(0, updateSignPos.length, ...dataNewPlace);
// signerPos.splice(0, signerPos.length, ...dataNewPlace);
const containerRect = document
.getElementById("container")
.getBoundingClientRect();
const signId = signerId; //? signerId : signerObjId;
const keyValue = key ? key : dragKey;
const getPdfPageWidth = pdfOriginalWH.find(
(data) => data.pageNumber === pageNumber
);
const containerScale = containerWH.width / getPdfPageWidth?.width || 1;
const ybottom = containerRect.height - dragElement.y;
if (keyValue >= 0) {
const filterSignerPos = updateSignPos.filter(
(data) => data.Id === signId
@@ -585,8 +548,10 @@ const TemplatePlaceholder = () => {
if (url.key === keyValue) {
return {
...url,
xPosition: dragElement.x / (containerScale * scale),
yPosition: dragElement.y / (containerScale * scale)
xPosition: dragElement.x,
yPosition: dragElement.y,
isDrag: true,
yBottom: ybottom
};
}
return url;
@@ -686,30 +651,18 @@ const TemplatePlaceholder = () => {
setPageNumber((prevPageNumber) => prevPageNumber + offset);
}
//function for capture position on hover or touch widgets
//function for capture position on hover signature button
const handleDivClick = (e) => {
const isTouchEvent = e.type.startsWith("touch");
const divRect = e.currentTarget.getBoundingClientRect();
let mouseX, mouseY;
if (isTouchEvent) {
const touch = e.touches[0]; // Get the first touch point
mouseX = touch.clientX - divRect.left;
mouseY = touch.clientY - divRect.top;
setSignBtnPosition([
{
xPos: mouseX,
yPos: mouseY
}
]);
} else {
mouseX = e.clientX - divRect.left;
mouseY = e.clientY - divRect.top;
const xyPosition = {
xPos: mouseX,
yPos: mouseY
};
setXYSignature(xyPosition);
}
const mouseX = e.clientX - divRect.left;
const mouseY = e.clientY - divRect.top;
const xyPosition = {
xPos: mouseX,
yPos: mouseY
};
setXYSignature(xyPosition);
};
//function for capture position of x and y on hover signature button last position
@@ -813,7 +766,7 @@ const TemplatePlaceholder = () => {
action: () => handleCloseRoleModal()
},
{
selector: '[data-tut="addWidgets"]',
selector: '[data-tut="reactourSecond"]',
content: () => (
<TourContentWithBtn
message={`Drag or click on a field to add it to the document.`}
@@ -835,10 +788,10 @@ const TemplatePlaceholder = () => {
style: { fontSize: "13px" }
},
{
selector: '[data-tut="headerArea"]',
selector: '[data-tut="reactourFour"]',
content: () => (
<TourContentWithBtn
message={`Clicking Next will store the current template. After saving, youll be prompted to create a new document from this template if you wish.`}
message={`Clicking Save will store the current template. After saving, youll be prompted to create a new document from this template if you wish.`}
isChecked={handleDontShow}
/>
),
@@ -1249,57 +1202,8 @@ const TemplatePlaceholder = () => {
setIsCheckbox(false);
};
const handleSaveFontSize = () => {
const filterSignerPos = signerPos.filter((data) => data.Id === uniqueId);
if (filterSignerPos.length > 0) {
const getPlaceHolder = filterSignerPos[0].placeHolder;
const getPageNumer = getPlaceHolder.filter(
(data) => data.pageNumber === pageNumber
);
if (getPageNumer.length > 0) {
const getXYdata = getPageNumer[0].pos;
const getPosData = getXYdata;
const addSignPos = getPosData.map((position) => {
if (position.key === signKey) {
return {
...position,
options: {
...position.options,
fontSize: fontSize,
fontColor: fontColor
}
};
}
return position;
});
const newUpdateSignPos = getPlaceHolder.map((obj) => {
if (obj.pageNumber === pageNumber) {
return { ...obj, pos: addSignPos };
}
return obj;
});
const newUpdateSigner = signerPos.map((obj) => {
if (obj.Id === uniqueId) {
return { ...obj, placeHolder: newUpdateSignPos };
}
return obj;
});
setSignerPos(newUpdateSigner);
}
}
setFontSize();
setFontColor();
handleTextSettingModal(false);
};
const handleTextSettingModal = (value) => {
setIsTextSetting(value);
};
return (
<>
<div>
<Title title={"Template"} />
<DndProvider backend={HTML5Backend}>
{isLoading.isLoad ? (
@@ -1307,287 +1211,275 @@ const TemplatePlaceholder = () => {
) : handleError ? (
<HandleError handleError={handleError} />
) : (
<div>
<div className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300">
{/* this component used for UI interaction and show their functionality */}
{!checkTourStatus && (
//this tour component used in your html component where you want to put
//onRequestClose function to close tour
//steps is defined what will be your messages and style also
//isOpen is takes boolean value to open
<Tour
onRequestClose={closeTour}
steps={tourConfig}
isOpen={templateTour}
rounded={5}
closeWithMask={false}
/>
)}
{isAddRole && (
<Tour
onRequestClose={() => setIsAddRole(false)}
steps={tourAddRole}
isOpen={isAddRole}
rounded={5}
closeWithMask={false}
/>
)}
{/* this component used to render all pdf pages in left side */}
<RenderAllPdfPage
signPdfUrl={pdfDetails[0].URL}
allPages={allPages}
setAllPages={setAllPages}
setPageNumber={setPageNumber}
setSignBtnPosition={setSignBtnPosition}
pageNumber={pageNumber}
<div
className="op-card overflow-hidden flex flex-row justify-between bg-base-300 relative"
ref={divRef}
>
{/* this component used for UI interaction and show their functionality */}
{!checkTourStatus && (
//this tour component used in your html component where you want to put
//onRequestClose function to close tour
//steps is defined what will be your messages and style also
//isOpen is takes boolean value to open
<Tour
onRequestClose={closeTour}
steps={tourConfig}
isOpen={templateTour}
rounded={5}
closeWithMask={false}
/>
)}
{isAddRole && (
<Tour
onRequestClose={() => setIsAddRole(false)}
steps={tourAddRole}
isOpen={isAddRole}
rounded={5}
closeWithMask={false}
/>
)}
{/* this component used to render all pdf pages in left side */}
<RenderAllPdfPage
signPdfUrl={pdfDetails[0].URL}
allPages={allPages}
setAllPages={setAllPages}
setPageNumber={setPageNumber}
setSignBtnPosition={setSignBtnPosition}
pageNumber={pageNumber}
/>
{/* pdf render view */}
<div className=" w-full md:w-[57%] flex mr-4">
<PdfZoom
setScale={setScale}
scale={scale}
containerWH={containerWH}
setZoomPercent={setZoomPercent}
zoomPercent={zoomPercent}
/>
<div className=" w-full md:w-[95%] ">
{/* this modal is used show alert set placeholder for all signers before send mail */}
<ModalUi
isOpen={isSendAlert}
title={"Fields required"}
handleClose={() => setIsSendAlert(false)}
>
<div className="h-full p-[20px]">
<p>
Please add at least one signature field for all roles.
</p>
</div>
</ModalUi>
<ModalUi
isOpen={!IsReceipent}
title={"Roles"}
handleClose={() => setIsReceipent(true)}
>
<div className="h-full p-[20px] text-center font-medium">
<p>Please add roles first</p>
</div>
</ModalUi>
{/* this modal is used show send mail message and after send mail success message */}
<ModalUi
isOpen={isCreateDocModal}
title={"Create Document"}
handleClose={() => setIsCreateDocModal(false)}
>
<div className="h-full p-[20px]">
<p>
Do you want to create a document using the template you
just created ?
</p>
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
{currentEmail.length > 0 && (
<>
<button
onClick={() => {
handleCreateDocModal();
}}
type="button"
className="op-btn op-btn-primary"
>
Yes
</button>
<button
onClick={() => {
setIsCreateDocModal(false);
}}
type="button"
className="op-btn op-btn-secondary ml-2"
>
No
</button>
</>
)}
</div>
</ModalUi>
{isCreateDoc && <LoaderWithMsg isLoading={isLoading} />}
<ModalUi
isOpen={isShowEmail}
title={"signers alert"}
handleClose={() => {
setIsShowEmail(false);
}}
>
<div className="h-full p-[20px]">
<p>Please select signer for add placeholder!</p>
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
{/* pdf render view */}
<div
style={{
marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px",
marginRight: !isMobile && pdfOriginalWidth > 500 && "20px"
}}
>
{/* this modal is used show alert set placeholder for all signers before send mail */}
<ModalUi
isOpen={isSendAlert}
title={"Fields required"}
handleClose={() => setIsSendAlert(false)}
>
<div className="h-full p-[20px]">
<p>Please add at least one signature field for all roles.</p>
</div>
</ModalUi>
<ModalUi
isOpen={!IsReceipent}
title={"Roles"}
handleClose={() => setIsReceipent(true)}
>
<div className="h-full p-[20px] text-center font-medium">
<p>Please add roles first</p>
</div>
</ModalUi>
{/* this modal is used show send mail message and after send mail success message */}
<ModalUi
isOpen={isCreateDocModal}
title={"Create Document"}
handleClose={() => setIsCreateDocModal(false)}
>
<div className="h-full p-[20px]">
<p>
Do you want to create a document using the template you just
created ?
</p>
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
{currentEmail.length > 0 && (
<>
<button
onClick={() => {
setIsShowEmail(false);
}}
onClick={() => handleCreateDocModal()}
type="button"
className="op-btn op-btn-primary"
>
Ok
Yes
</button>
</div>
</ModalUi>
<DropdownWidgetOption
type={radioButtonWidget}
title="Radio group"
showDropdown={isRadio}
setShowDropdown={setIsRadio}
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
handleClose={handleNameModal}
isSubscribe={isSubscribe}
/>
<DropdownWidgetOption
type="checkbox"
title="Checkbox"
showDropdown={isCheckbox}
setShowDropdown={setIsCheckbox}
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
handleClose={handleNameModal}
isSubscribe={isSubscribe}
/>
<DropdownWidgetOption
type="dropdown"
title="Dropdown options"
showDropdown={showDropdown}
setShowDropdown={setShowDropdown}
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
handleClose={handleNameModal}
isSubscribe={isSubscribe}
/>
<PlaceholderCopy
isPageCopy={isPageCopy}
setIsPageCopy={setIsPageCopy}
xyPostion={signerPos}
setXyPostion={setSignerPos}
allPages={allPages}
<button
onClick={() => {
setIsCreateDocModal(false);
}}
type="button"
className="op-btn op-btn-secondary ml-2"
>
No
</button>
</>
)}
</div>
</ModalUi>
{isCreateDoc && <LoaderWithMsg isLoading={isLoading} />}
<ModalUi
isOpen={isShowEmail}
title={"signers alert"}
handleClose={() => {
setIsShowEmail(false);
}}
>
<div className="h-full p-[20px]">
<p>Please select signer for add placeholder!</p>
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
<button
onClick={() => setIsShowEmail(false)}
type="button"
className="op-btn op-btn-primary"
>
Ok
</button>
</div>
</ModalUi>
<DropdownWidgetOption
type={radioButtonWidget}
title="Radio group"
showDropdown={isRadio}
setShowDropdown={setIsRadio}
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
handleClose={handleNameModal}
isSubscribe={isSubscribe}
/>
<DropdownWidgetOption
type="checkbox"
title="Checkbox"
showDropdown={isCheckbox}
setShowDropdown={setIsCheckbox}
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
handleClose={handleNameModal}
isSubscribe={isSubscribe}
/>
<DropdownWidgetOption
type="dropdown"
title="Dropdown options"
showDropdown={showDropdown}
setShowDropdown={setShowDropdown}
handleSaveWidgetsOptions={handleSaveWidgetsOptions}
currWidgetsDetails={currWidgetsDetails}
setCurrWidgetsDetails={setCurrWidgetsDetails}
handleClose={handleNameModal}
isSubscribe={isSubscribe}
/>
<PlaceholderCopy
isPageCopy={isPageCopy}
setIsPageCopy={setIsPageCopy}
xyPostion={signerPos}
setXyPostion={setSignerPos}
allPages={allPages}
pageNumber={pageNumber}
signKey={signKey}
// signerObjId={signerObjId}
Id={uniqueId}
/>
{/* pdf header which contain finish, back button */}
<Header
completeBtnTitle={"Save"}
isPlaceholder={true}
pageNumber={pageNumber}
allPages={allPages}
changePage={changePage}
pdfDetails={pdfDetails}
signerPos={signerPos}
signersdata={signersdata}
isMailSend={isMailSend}
alertSendEmail={alertSendEmail}
isShowHeader={true}
currentSigner={true}
setIsEditTemplate={handleEditTemplateModal}
dataTut4="reactourFour"
/>
<div data-tut="reactourThird">
{containerWH && (
<RenderPdf
pageNumber={pageNumber}
signKey={signKey}
// signerObjId={signerObjId}
Id={uniqueId}
/>
{/* pdf header which contain funish back button */}
<Header
completeBtnTitle={"Next"}
isPlaceholder={true}
pageNumber={pageNumber}
allPages={allPages}
changePage={changePage}
pdfOriginalWidth={pdfOriginalWidth}
pdfNewWidth={pdfNewWidth}
pdfDetails={pdfDetails}
signerPos={signerPos}
signersdata={signersdata}
isMailSend={isMailSend}
alertSendEmail={alertSendEmail}
isShowHeader={true}
currentSigner={true}
setIsEditTemplate={handleEditTemplateModal}
dataTut4="reactourFour"
/>
<div
ref={divRef}
data-tut="reactourThird"
className="h-[95%]"
>
{containerWH && (
<RenderPdf
pageNumber={pageNumber}
pdfNewWidth={pdfNewWidth}
pdfDetails={pdfDetails}
signerPos={signerPos}
successEmail={false}
numPages={numPages}
pageDetails={pageDetails}
placeholder={true}
drop={drop}
handleDeleteSign={handleDeleteSign}
handleTabDrag={handleTabDrag}
handleStop={handleStop}
setPdfLoad={setPdfLoad}
pdfLoad={pdfLoad}
setSignerPos={setSignerPos}
containerWH={containerWH}
setIsResize={setIsResize}
setZIndex={setZIndex}
handleLinkUser={handleLinkUser}
setUniqueId={setUniqueId}
signersdata={signersdata}
setIsPageCopy={setIsPageCopy}
setSignKey={setSignKey}
setSignerObjId={setSignerObjId}
isDragging={isDragging}
setShowDropdown={setShowDropdown}
setCurrWidgetsDetails={setCurrWidgetsDetails}
setWidgetType={setWidgetType}
setIsRadio={setIsRadio}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
setIsCheckbox={setIsCheckbox}
handleNameModal={setIsNameModal}
handleTextSettingModal={handleTextSettingModal}
pdfOriginalWH={pdfOriginalWH}
setScale={setScale}
scale={scale}
/>
)}
</div>
</div>
</div>
{/* signature button */}
{isMobile ? (
<div>
<WidgetComponent
dataTut2="reactourSecond"
pdfUrl={isMailSend}
dragSignature={dragSignature}
signRef={signRef}
handleDivClick={handleDivClick}
handleMouseLeave={handleMouseLeave}
isDragSign={isDragSign}
dragStamp={dragStamp}
dragRef={dragRef}
isDragStamp={isDragStamp}
isSignYourself={false}
addPositionOfSignature={addPositionOfSignature}
signerPos={signerPos}
signersdata={signersdata}
isSelectListId={isSelectListId}
setSignerObjId={setSignerObjId}
setIsSelectId={setIsSelectId}
setContractName={setContractName}
isSigners={isSigners}
setIsShowEmail={setIsShowEmail}
isMailSend={isMailSend}
setSelectedEmail={setSelectedEmail}
selectedEmail={selectedEmail}
handleAddSigner={handleAddSigner}
successEmail={false}
numPages={numPages}
pageDetails={pageDetails}
placeholder={true}
drop={drop}
handleDeleteSign={handleDeleteSign}
handleTabDrag={handleTabDrag}
handleStop={handleStop}
setPdfLoadFail={setPdfLoadFail}
pdfLoadFail={pdfLoadFail}
setSignerPos={setSignerPos}
containerWH={containerWH}
setIsResize={setIsResize}
setZIndex={setZIndex}
handleLinkUser={handleLinkUser}
setUniqueId={setUniqueId}
setRoleName={setRoleName}
handleDeleteUser={handleDeleteUser}
handleRoleChange={handleRoleChange}
handleOnBlur={handleOnBlur}
title={"Roles"}
initial={true}
isTemplateFlow={true}
sendInOrder={pdfDetails[0].SendinOrder}
setSignersData={setSignersData}
blockColor={blockColor}
setBlockColor={setBlockColor}
signersdata={signersdata}
setIsPageCopy={setIsPageCopy}
setSignKey={setSignKey}
setSignerObjId={setSignerObjId}
isDragging={isDragging}
setShowDropdown={setShowDropdown}
setCurrWidgetsDetails={setCurrWidgetsDetails}
setWidgetType={setWidgetType}
setIsRadio={setIsRadio}
setSelectWidgetId={setSelectWidgetId}
selectWidgetId={selectWidgetId}
setIsCheckbox={setIsCheckbox}
handleNameModal={setIsNameModal}
/>
</div>
) : (
<div
className={`w-[23%] bg-[#FFFFFF] min-h-screen overflow-y-auto hide-scrollbar`}
>
<div className={`max-h-screen`}>
)}
</div>
</div>
{/* signature button */}
{isMobile ? (
<div>
<WidgetComponent
dataTut="reactourFirst"
dataTut2="reactourSecond"
pdfUrl={isMailSend}
dragSignature={dragSignature}
signRef={signRef}
handleDivClick={handleDivClick}
handleMouseLeave={handleMouseLeave}
isDragSign={isDragSign}
dragStamp={dragStamp}
dragRef={dragRef}
isDragStamp={isDragStamp}
isSignYourself={false}
addPositionOfSignature={addPositionOfSignature}
signerPos={signerPos}
signersdata={signersdata}
isSelectListId={isSelectListId}
setSignerObjId={setSignerObjId}
setIsSelectId={setIsSelectId}
setContractName={setContractName}
isSigners={isSigners}
setIsShowEmail={setIsShowEmail}
isMailSend={isMailSend}
setSelectedEmail={setSelectedEmail}
selectedEmail={selectedEmail}
handleAddSigner={handleAddSigner}
setUniqueId={setUniqueId}
setRoleName={setRoleName}
handleDeleteUser={handleDeleteUser}
handleRoleChange={handleRoleChange}
handleOnBlur={handleOnBlur}
title={"Roles"}
initial={true}
isTemplateFlow={true}
sendInOrder={pdfDetails[0].SendinOrder}
setSignersData={setSignersData}
blockColor={blockColor}
setBlockColor={setBlockColor}
/>
</div>
) : (
<div>
<div className="hidden md:block w-[180px] h-full bg-base-100">
<div
style={{ maxHeight: window.innerHeight - 70 + "px" }}
className="overflow-y-auto hide-scrollbar"
>
<SignerListPlace
isMailSend={isMailSend}
signerPos={signerPos}
@@ -1608,7 +1500,7 @@ const TemplatePlaceholder = () => {
blockColor={blockColor}
setBlockColor={setBlockColor}
/>
<div data-tut="addWidgets">
<div data-tut="reactourSecond">
<WidgetComponent
isMailSend={isMailSend}
dragSignature={dragSignature}
@@ -1628,60 +1520,49 @@ const TemplatePlaceholder = () => {
</div>
</div>
</div>
)}
</div>
</div>
)}
</div>
)}
<div data-tut="reactourAddbtn--observe">
<AddRoleModal
isModalRole={isModalRole}
roleName={roleName}
signersdata={signersdata}
setRoleName={setRoleName}
handleAddRole={handleAddRole}
handleCloseRoleModal={handleCloseRoleModal}
/>
</div>
<div>
<LinkUserModal
handleAddUser={handleAddUser}
isAddUser={isAddUser}
uniqueId={uniqueId}
closePopup={closePopup}
signersData={signersdata}
/>
</div>
<ModalUi
title={"Edit Template"}
isOpen={isEditTemplate}
handleClose={handleEditTemplateModal}
>
<EditTemplate
template={pdfDetails?.[0]}
onSuccess={handleEditTemplateForm}
/>
</ModalUi>
<WidgetNameModal
widgetName={widgetName}
defaultdata={currWidgetsDetails}
isOpen={isNameModal}
handleClose={handleNameModal}
handleData={handleWidgetdefaultdata}
isSubscribe={isSubscribe}
/>
<TextFontSetting
isTextSetting={isTextSetting}
setIsTextSetting={setIsTextSetting}
fontSize={fontSize}
setFontSize={setFontSize}
fontColor={fontColor}
setFontColor={setFontColor}
handleSaveFontSize={handleSaveFontSize}
currWidgetsDetails={currWidgetsDetails}
/>
</DndProvider>
</>
<div data-tut="reactourAddbtn--observe">
<AddRoleModal
isModalRole={isModalRole}
roleName={roleName}
signersdata={signersdata}
setRoleName={setRoleName}
handleAddRole={handleAddRole}
handleCloseRoleModal={handleCloseRoleModal}
/>
</div>
<div>
<LinkUserModal
handleAddUser={handleAddUser}
isAddUser={isAddUser}
uniqueId={uniqueId}
closePopup={closePopup}
signersData={signersdata}
/>
</div>
<ModalUi
title={"Edit Template"}
isOpen={isEditTemplate}
handleClose={handleEditTemplateModal}
>
<EditTemplate
template={pdfDetails?.[0]}
onSuccess={handleEditTemplateForm}
/>
</ModalUi>
<WidgetNameModal
widgetName={widgetName}
defaultdata={currWidgetsDetails}
isOpen={isNameModal}
handleClose={handleNameModal}
handleData={handleWidgetdefaultdata}
isSubscribe={isSubscribe}
/>
</div>
);
};
+1 -1
View File
@@ -315,7 +315,7 @@ function UserProfile() {
{userNameError}
</div>
)} */}
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box w-[450px]">
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow rounded-xl w-[450px]">
<div className="flex flex-col justify-center items-center my-4">
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
<img
+135 -111
View File
@@ -1,6 +1,7 @@
import React, { useEffect, useState } from "react";
import Title from "../components/Title";
import axios from "axios";
import { useNavigate } from "react-router-dom";
import Alert from "../primitives/Alert";
import ModalUi from "../primitives/ModalUi";
import { isEnableSubscription } from "../constant/const";
@@ -9,24 +10,19 @@ import Parse from "parse";
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
import Tooltip from "../primitives/Tooltip";
import Loader from "../primitives/Loader";
import SubscribeCard from "../primitives/SubscribeCard";
import Tour from "reactour";
const tourSteps = [
{
selector: '[data-tut="webhooksubscribe"]',
content: "Upgrade now to set webhook"
}
];
function Webhook() {
const navigation = useNavigate();
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
const [webhook, setWebhook] = useState();
const [isLoader, setIsLoader] = useState(true);
const [isGenerate, setIsGenerate] = useState(false);
const [isErr, setIsErr] = useState(false);
const [isModal, setIsModal] = useState(false);
const [isSubscribe, setIsSubscribe] = useState(false);
const [error, setError] = useState("");
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
const [isTour, setIsTour] = useState(false);
useEffect(() => {
fetchWebhook();
// eslint-disable-next-line
@@ -64,22 +60,31 @@ function Webhook() {
"X-Parse-Application-Id": parseAppId,
sessiontoken: localStorage.getItem("accesstoken")
};
const res = await axios.post(url, params, { headers: headers });
if (res.data && res.data.result && res.data.result.Webhook) {
setWebhook(res.data.result.Webhook);
setIsAlert({ type: "success", msg: "Webhook added successfully." });
} else {
console.error("Error while generating webhook");
setIsAlert({ type: "danger", msg: "Something went wrong." });
}
await axios.post(url, params, { headers: headers }).then((res) => {
if (res.data && res.data.result && res.data.result.Webhook) {
setWebhook(res.data.result.Webhook);
setIsGenerate(true);
setTimeout(() => {
setIsGenerate(false);
}, 1500);
setIsLoader(false);
} else {
console.error("Error while generating webhook");
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsErr(false);
}, 1500);
}
});
} catch (error) {
setIsAlert({ type: "danger", msg: "Something went wrong." });
console.log("err while generating webhook", error);
} finally {
setIsLoader(false);
setIsErr(true);
setTimeout(() => {
setIsAlert({ type: "success", msg: "" });
setIsErr(false);
}, 1500);
console.log("err", error);
}
} else {
setError("The webhook url should always start with https://");
@@ -89,112 +94,131 @@ function Webhook() {
}
};
const handleModal = () => {
if (!isSubscribe && isEnableSubscription) {
setIsTour(true);
} else {
setIsModal(!isModal);
}
};
const handleModal = () => setIsModal(!isModal);
return (
<React.Fragment>
<Title title={"Webhook"} />
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
{isGenerate && <Alert type="success">Webhook added successfully.</Alert>}
{isErr && <Alert type="danger">Something went wrong.</Alert>}
{isLoader ? (
<div className="h-[100vh] flex justify-center items-center">
<Loader />
</div>
) : (
<>
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box mb-3">
{!isEnableSubscription && <PremiumAlertHeader />}
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
OpenSign Webhook{" "}
<Tooltip
url={"https://docs.opensignlabs.com/docs/API-docs/get-webhook"}
isSubscribe={true}
/>
</h1>
<ul className={"w-full flex flex-col p-2 text-sm"}>
<li className="flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2">
<div className="w-[70%] flex-col md:flex-row flex items-center gap-5">
<span className="">Webhook:</span>{" "}
<span id="token" className=" md:text-end cursor-pointer">
{webhook ? webhook : "_____"}
</span>
</div>
<button
type="button"
onClick={handleModal}
className="op-btn op-btn-primary"
>
{webhook ? "Update Webhook" : "Add Webhook"}
</button>
</li>
</ul>
<div className="flex items-center justify-center">
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow rounded">
{!isEnableSubscription && <PremiumAlertHeader />}
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
OpenSign Webhook{" "}
<Tooltip
url={"https://docs.opensignlabs.com/docs/API-docs/get-webhook"}
isSubscribe={true}
/>
</h1>
<ul
className={
isSubscribe || !isEnableSubscription
? "w-full flex flex-col p-2 text-sm "
: "w-full flex flex-col p-2 text-sm opacity-20 pointer-events-none select-none"
}
>
<li
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
>
<div className="w-[70%] flex-col md:flex-row flex items-center gap-5 ">
<span className="">Webhook:</span>{" "}
<span id="token" className=" md:text-end cursor-pointer">
{webhook ? webhook : "_____"}
</span>
</div>
<button
type="button"
onClick={() =>
openInNewTab(
"https://docs.opensignlabs.com/docs/API-docs/save-update-webhook"
)
}
className="op-btn op-btn-secondary mt-2 mb-3 px-7"
onClick={handleModal}
className="op-btn op-btn-primary "
>
View Docs
{webhook ? "Update Webhook" : "Add Webhook"}
</button>
</div>
<ModalUi
isOpen={isModal}
title={"Regenerate Token"}
handleClose={handleModal}
</li>
</ul>
<div className="flex items-center justify-center ">
<button
type="button"
onClick={() =>
openInNewTab(
"https://docs.opensignlabs.com/docs/API-docs/save-update-webhook"
)
}
className="op-btn op-btn-secondary my-2"
>
{error && <Alert type="danger">{error}</Alert>}
<div className="m-[20px]">
<div className="text-lg font-normal text-base-content">
<label className="text-sm ml-2">Webhook</label>
<input
value={webhook}
onChange={(e) => setWebhook(e.target.value)}
placeholder="Enter webhook url"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<hr className="bg-[#ccc] mt-3" />
<div className="flex items-center mt-3 gap-2">
<button
onClick={handleSubmit}
className="op-btn op-btn-primary ml-[2px]"
>
Yes
</button>
<button
onClick={handleModal}
className="op-btn op-btn-secondary"
>
No
</button>
</div>
</div>
</ModalUi>
View Docs
</button>
</div>
{!isSubscribe && isEnableSubscription && (
<div data-tut="webhooksubscribe">
<SubscribeCard />
</div>
<>
<h1 className={"ml-4 mt-3 mb-2 font-semibold"}>
Upgrade to PRO Plan
</h1>
<ul className={"w-full flex flex-col p-2 text-sm "}>
<li
className={`flex flex-col md:flex-row justify-between items-center border-y-[1px] border-gray-300 break-all py-2`}
>
<div className="w-[70%] flex-col md:flex-row flex items-center gap-3 ">
<span className="">$29.99/month:</span>{" "}
<span id="token" className=" md:text-end cursor-pointer">
First 100 documents included, then just $0.15 per
document.
</span>
</div>
{!isSubscribe && isEnableSubscription && (
<button
type="button"
onClick={() => navigation("/subscription")}
className="rounded hover:bg-[#15b4e9] border-[1px] border-[#15b4e9] text-[#15b4e9] hover:text-white px-11 py-2 text-xs md:text-base focus:outline-none"
>
Upgrade Now
</button>
)}
</li>
</ul>
</>
)}
</>
<ModalUi
isOpen={isModal}
title={"Regenerate Token"}
handleClose={handleModal}
>
{error && <Alert type="danger">{error}</Alert>}
<div className="m-[20px]">
<div className="text-lg font-normal text-base-content">
<label className="text-sm ml-2">Webhook</label>
<input
value={webhook}
onChange={(e) => setWebhook(e.target.value)}
placeholder="Enter webhook url"
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
/>
</div>
<hr className="bg-[#ccc] mt-3" />
<div className="flex items-center mt-3 gap-2">
<button
onClick={handleSubmit}
className="op-btn op-btn-primary ml-[2px]"
>
Yes
</button>
<button
onClick={handleModal}
className="op-btn op-btn-secondary"
>
No
</button>
</div>
</div>
</ModalUi>
</div>
)}
<Tour
onRequestClose={() => setIsTour(false)}
steps={tourSteps}
isOpen={isTour}
closeWithMask={false}
disableKeyboardNavigation={["esc"]}
scrollOffset={-100}
rounded={5}
/>
</React.Fragment>
);
}
+2 -1
View File
@@ -1,6 +1,7 @@
import React, { useState, useEffect } from "react";
import Parse from "parse";
import axios from "axios";
import "../styles/AddUser.css";
import Loader from "./Loader";
const AddContact = (props) => {
const [name, setName] = useState("");
@@ -202,7 +203,7 @@ const AddContact = (props) => {
</div>
)}
<div className="w-full mx-auto p-[8px]">
<div className="text-[14px] font-[700]">Add Contact</div>
<div className="text-[14px] font-[700]">Add User</div>
{isUserExist && (
<div className="mb-[0.75rem] flex items-center mt-1">
<input
@@ -1,51 +0,0 @@
import React, { useState, useEffect } from "react";
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
import Loader from "./Loader";
const LottieWithLoader = () => {
const [isLoaded, setIsLoaded] = useState(false);
const [hasError, setHasError] = useState(false);
const [animationSrc, setAnimationSrc] = useState(null);
const src =
"https://lottie.host/00a72a09-f2d4-493a-9b2d-2843bf067638/Ic7jJ44wLJ.json";
useEffect(() => {
fetch(src)
.then((response) => {
if (!response.ok) {
throw new Error("Network response was not ok");
}
return response.blob();
})
.then((blob) => {
const objectURL = URL.createObjectURL(blob);
setAnimationSrc(objectURL);
setIsLoaded(true);
})
.catch((error) => {
console.error("faild to load animation of send request:", error);
setHasError(true);
});
}, [src]);
return (
<div>
{!isLoaded && !hasError && (
<div className="loader">
{" "}
<Loader />
</div>
)}
{hasError && <div className="error">Failed to load animation</div>}
{isLoaded && animationSrc && (
<DotLottieReact
src={animationSrc}
loop
autoplay
style={{ display: "block" }}
/>
)}
</div>
);
};
export default LottieWithLoader;
@@ -951,7 +951,7 @@ const ReportTable = (props) => {
<i
data-tut="reactourFirst"
onClick={() => navigate("/form/template")}
className="fa-light fa-square-plus text-accent text-[40px]"
className="fa-solid fa-square-plus text-accent text-[25px]"
></i>
)}
{props.form && (
@@ -959,13 +959,13 @@ const ReportTable = (props) => {
className="cursor-pointer"
onClick={() => handleContactFormModal()}
>
<i className="fa-light fa-square-plus text-accent text-[40px]"></i>
<i className="fa-solid fa-square-plus text-accent text-[25px]"></i>
</div>
)}
</div>
<div
className={`${
isDashboard && props.List?.length > 0 ? "h-[317px]" : "h-full"
isDashboard ? "h-[317px]" : "h-full"
} overflow-x-auto w-full`}
>
<table className="op-table border-collapse w-full">
@@ -1000,7 +1000,7 @@ const ReportTable = (props) => {
<td className="px-4 py-2 font-semibold">
{item?.Name}{" "}
</td>
<td className="px-4 py-2 ">{item?.Email || "-"}</td>
<td className="px-4 py-2">{item?.Email || "-"}</td>
<td className="px-4 py-2">{item?.Phone || "-"}</td>
<td className="px-3 py-2 text-white grid grid-cols-2">
{props.actions?.length > 0 &&
@@ -1053,7 +1053,7 @@ const ReportTable = (props) => {
{startIndex + index + 1}
</th>
)}
<td className="px-4 py-2 font-semibold min-w-56 max-w-56">
<td className="px-4 py-2 font-semibold min-w-56">
{item?.Name}{" "}
</td>
{props.heading.includes("Note") && (
@@ -1303,56 +1303,46 @@ const ReportTable = (props) => {
))}
</div>
{isViewShare[item.objectId] && (
<ModalUi
isOpen
showHeader={
props.ReportName === "Templates" && true
}
title={"Signers"}
reduceWidth={"md:max-w-[450px]"}
handleClose={() => setIsViewShare({})}
>
{props.ReportName !== "Templates" && (
<div className="fixed z-[999] inset-0 w-full h-full bg-black bg-opacity-[75%]">
<div className="fixed top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 text-sm bg-white rounded shadow-md max-h-90 min-w-[90%] md:min-w-[400px] overflow-y-auto max-h-[340px] md:max-h-[400px] hide-scrollbar">
<div
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-1 z-40"
className="cursor-pointer absolute text-white text-[22px] font-medium rounded-full z-50 top-1 right-3"
onClick={() => setIsViewShare({})}
>
&times;
</div>
)}
<table className="op-table w-full overflow-auto">
<thead className="h-[38px] sticky top-0 text-base-content text-sm pt-[15px] px-[20px]">
<tr>
{props.ReportName === "Templates" && (
<th className="p-2 pl-3 w-[30%]">
Roles
</th>
)}
<th className="pl-3 py-2">
{props.ReportName === "Templates"
? "Email"
: "Signers"}
</th>
</tr>
</thead>
<tbody>
{item.Placeholders.map((x, i) => (
<tr key={i} className="text-sm font-medium">
<table className="table-auto w-full">
<thead className="text-white h-[38px] sticky top-0 bg-[#32a3ac]">
<tr>
{props.ReportName === "Templates" && (
<td className="text-[12px] p-2 pl-3 w-[30%]">
{x.Role && x.Role}
</td>
<th className="p-2 pl-3">Roles</th>
)}
<td className="pl-3 text-[12px] py-2 break-all">
{x.email
? x.email
: x?.signerPtr?.Email || "-"}
</td>
<th className="p-2">Signers</th>
</tr>
))}
</tbody>
</table>
</ModalUi>
</thead>
<tbody>
{item.Placeholders.map((x, i) => (
<tr
key={i}
className="text-sm font-normal text-black odd:bg-white even:bg-gray-200"
>
{props.ReportName === "Templates" && (
<td className="text-[12px] p-2 pl-3">
{x.Role && x.Role}
</td>
)}
<td className="text-[12px] p-2 break-all">
{x.email
? x.email
: x?.signerPtr?.Email || "-"}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
)}
{isDeleteModal[item.objectId] && (
<ModalUi
@@ -1408,7 +1398,6 @@ const ReportTable = (props) => {
handleClose={() => {
setIsShare({});
setActLoader({});
setCopied(false);
}}
>
<div className="m-[20px]">
@@ -1417,26 +1406,25 @@ const ReportTable = (props) => {
key={i}
className="text-sm font-normal text-black flex my-2 justify-between items-center"
>
<span className="w-[150px] mr-[5px] md:mr-0 md:w-[300px] whitespace-nowrap overflow-hidden text-ellipsis text-sm font-semibold">
<span className="text-sm font-semibold">
{share.email}
</span>
<div className="flex items-center gap-2">
<div>
<RWebShare
data={{
url: share.url,
title: "Sign url"
}}
>
<button className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm ">
<i className="fa-light fa-share-from-square"></i>{" "}
Share
<button className="bg-[#002864] text-white rounded w-[32px] h-[30px] focus:outline-none">
<i className="fa-solid fa-share-from-square"></i>{" "}
</button>
</RWebShare>
<button
className="op-btn op-btn-primary op-btn-outline op-btn-xs md:op-btn-sm"
className="ml-2 bg-[#002864] text-white rounded w-[100px] h-[30px] focus:outline-none"
onClick={() => copytoclipboard(share)}
>
<i className="fa-light fa-link"></i>{" "}
<i className="fa-solid fa-link"></i>{" "}
{copied[share.email]
? "Copied"
: "Copy"}
@@ -1585,11 +1573,11 @@ const ReportTable = (props) => {
</tbody>
</table>
</div>
<div className="op-join flex flex-wrap items-center p-2">
<div className="op-join flex flex-wrap items-center p-2 ">
{props.List.length > props.docPerPage && (
<button
onClick={() => paginateBack()}
className="op-join-item op-btn op-btn-sm"
className="op-join-item op-btn "
>
Prev
</button>
@@ -1601,7 +1589,7 @@ const ReportTable = (props) => {
disabled={x === "..."}
className={`${
x === currentPage ? "op-btn-active" : ""
} op-join-item op-btn op-btn-sm`}
} op-join-item op-btn`}
>
{x}
</button>
@@ -1609,18 +1597,14 @@ const ReportTable = (props) => {
{props.List.length > props.docPerPage && (
<button
onClick={() => paginateFront()}
className="op-join-item op-btn op-btn-sm"
className="op-join-item op-btn"
>
Next
</button>
)}
</div>
{props.List?.length <= 0 && (
<div
className={`${
isDashboard ? "h-[317px]" : ""
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
>
<div className="flex flex-col items-center justify-center w-full bg-base-100 text-base-content rounded-xl py-4">
<div className="w-[60px] h-[60px] overflow-hidden">
<img
className="w-full h-full object-contain"
+1 -1
View File
@@ -2,7 +2,7 @@ import React from "react";
const Loader = () => {
return (
<div className="op-loading op-loading-infinity w-[4rem] text-neutral"></div>
<div className="op-loading op-loading-infinity w-[5rem] text-accent"></div>
);
};
@@ -4,6 +4,7 @@ import Loader from "./Loader";
function LoaderWithMsg({ isLoading }) {
return (
<div className="flex flex-col justify-center items-center h-[100vh]">
{/* <img alt="loader" src={loader} className="w-[80px] h-[80px]" /> */}
<Loader />
<span className="text-[13px] text-base-cotent">{isLoading.message}</span>
</div>
+1 -1
View File
@@ -14,7 +14,7 @@ const Modal = ({ children, Title }) => {
onClick={() => SetIsOpen()}
className="px-2 py-1 bg-gray-400 rounded cursor-pointer"
>
<i className="fa-light fa-xmark"></i>
<i className="fa-solid fa-xmark"></i>
</div>
</div>
<hr />
+2 -3
View File
@@ -12,15 +12,14 @@ const ModalUi = ({
reduceWidth,
showHeaderMessage
}) => {
const width = reduceWidth;
return (
<>
{isOpen && (
<dialog className="op-modal op-modal-open">
<div
className={`${
width || "md:min-w-[500px]"
} op-modal-box p-0 max-h-90 overflow-y-auto hide-scrollbar text-sm`}
reduceWidth || "md:min-w-[500px]"
} op-modal-box p-0 max-h-90 min-w-[90%] overflow-y-auto hide-scrollbar text-sm`}
>
{showHeader && (
<>
@@ -11,7 +11,7 @@ function CustomModal({
}) {
return (
show && (
<dialog className="op-modal op-modal-open absolute z-[998]">
<dialog className="op-modal op-modal-open absolute z-[1999]">
<div className="w-[80%] md:w-[40%] op-modal-box p-0 overflow-y-auto hide-scrollbar text-sm">
<h3 className="text-[#de4337] font-bold text-lg pt-[15px] px-[20px]">
{headMsg && headMsg}
@@ -1,24 +0,0 @@
import React from "react";
import { useNavigate } from "react-router-dom";
const SubscribeCard = () => {
const navigate = useNavigate();
return (
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
<div className="op-card-body">
<h2 className="op-card-title">Upgrade to PRO Plan</h2>
<p>$29.99/month: Sign 100 docs using API. Only $0.15/doc after that.</p>
<div className="op-card-actions justify-end">
<button
onClick={() => navigate("/subscription")}
className="op-btn op-btn-accent"
>
Upgrade Now
</button>
</div>
</div>
</div>
);
};
export default SubscribeCard;
+11 -8
View File
@@ -6,10 +6,13 @@ const Tooltip = ({ id, message, url, iconColor }) =>
<button onClick={() => openInNewTab(url)} className={"text-center"}>
<sup>
<i
className="fa-light fa-question rounded-full border-[1px] py-[1.5px] px-[4px] text-[13px]"
className="fa-solid fa-question rounded-full"
style={{
borderColor: iconColor ? iconColor : "#33bbff",
color: iconColor ? iconColor : "#33bbff"
color: iconColor ? iconColor : "#33bbff",
fontSize: 13,
borderWidth: 1.5,
padding: "1.5px 4px"
}}
></i>
</sup>
@@ -23,18 +26,18 @@ const Tooltip = ({ id, message, url, iconColor }) =>
>
<sup>
<i
className="fa-light fa-question rounded-full border-[1px] py-[1.5px] px-[4px] text-[13px]"
className="fa-solid fa-question rounded-full"
style={{
borderColor: iconColor ? iconColor : "#33bbff",
color: iconColor ? iconColor : "#33bbff"
color: iconColor ? iconColor : "#33bbff",
fontSize: 13,
borderWidth: 1.5,
padding: "1.5px 4px"
}}
></i>
</sup>
</a>
<ReactTooltip
id={id ? id : "my-tooltip"}
className="max-w-[200px] z-[200]"
/>
<ReactTooltip id={id ? id : "my-tooltip"} className="max-w-[200px]" />
</>
);
+1 -1
View File
@@ -9,7 +9,7 @@ function Upgrade({ message }) {
const url = window.location.origin + "/subscription";
openInNewTab(url);
}}
className="op-link op-link-accent text-sm"
className="text-blue-800 text-sm cursor-pointer underline"
>
{message ? message : "Upgrade now"}
</span>
+1 -3
View File
@@ -2,11 +2,9 @@ import { combineReducers } from "redux";
import infoReducer from "./infoReducer";
import ShowTenant from "./ShowTenant";
import TourStepsReducer from "./TourStepsReducer";
import showHeader from "./showHeader";
export default combineReducers({
appInfo: infoReducer,
TourSteps: TourStepsReducer,
ShowTenant,
showHeader
ShowTenant
});
@@ -1,14 +0,0 @@
import { createSlice } from "@reduxjs/toolkit";
const showHeaderSlice = createSlice({
name: "showTenant",
initialState: "",
reducers: {
showHeader: (state, action) => {
return action.payload;
}
}
});
export const { showHeader } = showHeaderSlice.actions;
export default showHeaderSlice.reducer;
+1 -3
View File
@@ -7,12 +7,10 @@ import { configureStore } from "@reduxjs/toolkit";
import infoReducer from "./reducers/infoReducer";
import ShowTenant from "./reducers/ShowTenant";
import TourStepsReducer from "./reducers/TourStepsReducer";
import showHeader from "./reducers/showHeader";
export const store = configureStore({
reducer: {
appInfo: infoReducer,
TourSteps: TourStepsReducer,
ShowTenant,
showHeader
ShowTenant
}
});
+79
View File
@@ -1,3 +1,82 @@
.addusercontainer {
height: 100%;
padding: 10px 20px 10px 20px;
}
.loaderdiv {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
justify-content: center;
align-items: center;
background-color: rgba(0, 0, 0, 0.3);
}
.form-wrapper {
width: 100%;
margin-left: auto;
margin-right: auto;
padding: 8px;
}
.form-section {
margin-bottom: 0.75rem;
}
.checkbox-label {
margin-left: 0.5rem;
color: #4b5563;
}
.addUserInput {
padding: 0.5rem 0.75rem;
width: 100%;
border-width: 1px;
border-color: #d1d5db;
border-radius: 0.375rem;
outline: none;
font-size: 0.75rem;
}
.buttoncontainer {
margin-top: 1rem;
display: flex;
justify-content: flex-start;
}
.submitbutton {
background: #1ab6ce;
border-radius: 2px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
border: none;
text-transform: uppercase;
font-size: 13px;
font-weight: 600;
padding: 0.375rem 0.75rem;
text-align: center;
color: #ffffff;
outline: none;
}
/* For classes: bg-[#188ae2] text-sm text-white px-4 py-2 rounded ml-2 shadow focus:outline-none */
.resetbutton {
background-color: #188ae2;
border-radius: 2px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
border: none;
text-transform: uppercase;
font-size: 13px;
font-weight: 600;
padding: 0.375rem 0.75rem;
text-align: center;
color: #ffffff;
outline: none;
margin-left: 8px;
}
.validationlist {
position: absolute;
left: 0;
+66
View File
@@ -0,0 +1,66 @@
fieldset {
border: 0 !important;
margin: 0 !important;
padding: 0 !important;
}
[class*="loader-"] {
display: inline-block;
width: 1em;
height: 1em;
color: inherit;
vertical-align: middle;
pointer-events: none;
}
.loader-37 {
border-right: 0.1em solid currentcolor;
border-radius: 100%;
-webkit-animation: loader-37 800ms linear infinite;
animation: loader-37 800ms linear infinite;
}
.loader-37:before,
.loader-37:after {
content: "";
width: 0.8em;
height: 0.8em;
display: block;
position: absolute;
top: calc(50% - 0.4em);
left: calc(50% - 0.4em);
border-left: 0.08em solid currentcolor;
border-radius: 100%;
animation: loader-37 400ms linear infinite reverse;
}
.loader-37:after {
width: 0.6em;
height: 0.6em;
top: calc(50% - 0.3em);
left: calc(50% - 0.3em);
border: 0;
border-right: 0.05em solid currentcolor;
-webkit-animation: none;
animation: none;
}
@-webkit-keyframes loader-37 {
from {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
to {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
}
@keyframes loader-37 {
from {
-webkit-transform: rotate(360deg);
transform: rotate(360deg);
}
to {
-webkit-transform: rotate(0deg);
transform: rotate(0deg);
}
}
+145 -8
View File
@@ -1,8 +1,18 @@
.customwarning {
.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;
@@ -28,16 +38,41 @@
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;
}
100% {
25% {
opacity: 1;
visibility: visible;
}
50% {
opacity: 1;
visibility: visible;
}
75% {
opacity: 1;
visibility: visible;
}
100% {
opacity: 0;
visibility: hidden;
}
}
.signature {
@@ -48,15 +83,117 @@
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);
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);
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%;
}
}
+249 -4
View File
@@ -9,8 +9,7 @@
border-radius: 6px;
overflow: hidden;
padding: 5px;
box-shadow:
0px 10px 38px -10px rgba(22, 23, 24, 0.35),
box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35),
0px 10px 20px -15px rgba(22, 23, 24, 0.2);
z-index: 99;
}
@@ -107,14 +106,110 @@
color: var(--violet-11);
}
.itemColor {
font-size: 13px !important;
}
.folderComponent {
padding: 30px;
height: 100%;
border-radius: 5px;
}
.inputStyle {
border: 1.6px solid #ccc !important;
}
.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;
@@ -123,11 +218,17 @@
border-top: 1px solid rgba(0, 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;
@@ -167,6 +268,14 @@
color: #fff;
}
.add {
background-color: #05bbdb;
color: #fff;
padding: 8px 15px;
text-align: center;
display: flex;
margin: 5px;
}
.sort {
padding: 8px 15px;
@@ -183,6 +292,56 @@
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;
@@ -194,6 +353,22 @@
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;
}
@@ -203,8 +378,7 @@ a {
padding: 5px 10px;
width: 170px;
background-color: white;
box-shadow:
hsl(206 22% 7% / 35%) 0px 10px 38px -10px,
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);
@@ -281,14 +455,85 @@ a {
}
}
.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 */
}
.docDeleteBtn {
/* box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18); */
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000),
var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
padding: 7px 17px;
color: white;
font-weight: 600 !important;
font-size: 12px !important;
border: none;
border-radius: 2px;
}
.docDeleteBtn:focus {
border: none;
outline: none;
}
.docDeleteBtn:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
color: white;
}
@media screen and (max-width: 766px) {
.itemColor {
font-size: 10px !important;
}
}
@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;
}
}
+136
View File
@@ -0,0 +1,136 @@
/* Full-width input fields */
.inputt {
width: 100%;
padding: 8px;
margin-bottom: 10px;
/* margin: 5px 0 14px 0; */
display: inline-block;
border: none;
background: #f1f1f1;
color: black;
font-size: 12px;
}
/* Add a background color when the inputs get focus */
.inputt:focus {
background-color: #ddd;
outline: none;
}
.confirmInputt {
width: 100%;
padding: 8px;
/* margin: 5px 0 14px 0; */
display: inline-block;
background: #f1f1f1;
color: black;
font-size: 12px;
}
.inputt::placeholder,
.confirmInputt::placeholder {
color: #474e5d;
opacity: 1;
/* Firefox */
}
.inputt:-ms-input-placeholder,
.confirmInputt:-ms-input-placeholder {
/* Internet Explorer 10-11 */
color: #474e5d;
}
/* Set a style for all buttons */
.signupbtn {
background-color: #15b4e9;
color: white;
padding: 12px 12px;
margin: 8px 0;
border: none;
cursor: pointer;
opacity: 0.9;
float: left;
width: 50%;
}
.signupbtn:hover {
opacity: 1;
}
/* Add padding to pgsignup-container elements */
.pgsignup-container {
padding: 16px;
}
/* The pgsignup (background) */
.pgsignup {
display: none;
/* Hidden by default */
position: fixed;
/* Stay in place */
z-index: 1;
/* Sit on top */
left: 0;
top: 0;
width: 100%;
/* Full width */
height: 100%;
/* Full height */
overflow: auto;
/* Enable scroll if needed */
background-color: #474e5d;
padding-top: 50px;
}
/* pgsignup Content/Box */
.pgsignup-content {
background-color: #fefefe;
margin: 5% auto 15% auto;
/* 5% from the top, 15% from the bottom and centered */
border: 1px solid #888;
width: 50%;
/* Could be more or less, depending on screen size */
}
/* Style the horizontal ruler */
.hrt {
border: 1px solid #f1f1f1;
margin-bottom: 25px;
}
.clearfix {
display: flex;
justify-content: center;
align-items: center;
}
/* Clear floats */
.clearfix::after {
content: "";
clear: both;
display: table;
}
/* Change styles for cancel button and signup button on extra small screens */
@media screen and (max-width: 768px) {
/* pgsignup Content/Box */
.pgsignup-content {
background-color: #fefefe;
margin: 5% auto 15% auto;
/* 5% from the top, 15% from the bottom and centered */
border: 1px solid #888;
width: 90%;
/* Could be more or less, depending on screen size */
}
.signupbtn {
width: 100%;
font-size: 16px;
}
/* Style the horizontal ruler */
.hrt {
border: 1px solid #f1f1f1;
margin-bottom: 16px;
}
}
+757 -14
View File
@@ -3,6 +3,22 @@
@import url("https://fonts.googleapis.com/css2?family=Delicious+Handrawn&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Cedarville+Cursive&display=swap");
.placeholderBlock {
padding: 0px;
position: absolute;
border-style: dashed;
width: 150px;
height: 60px;
background: #daebe0;
text-align: center;
justify-content: center;
border-width: 0.2px;
}
.dragCursor {
cursor: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAAsTAAALEwEAmpwYAAAASElEQVR4nGNgwAMkJSUbpKSkOvCpIaT5PxSTbogUQjMYMwxeIIXmVFIxA8UGDDyQGg0DnIDi6JKUlCxHMqCeZAOghjSAMD5FAKfeaURdUFxCAAAAAElFTkSuQmCC"), auto;
}
.react-datepicker__input-container {
position: initial !important;
}
@@ -14,6 +30,17 @@
user-select: none;
}
.inputPlaceholder {
width: 100%;
height: 100%;
position: absolute;
left: 0px;
top: 0px;
/* font-size: 12px; */
border: 1px solid #007bff;
border-radius: 2px;
}
.radioButton {
width: 100%;
height: 100%;
@@ -25,6 +52,52 @@
border-radius: 50px;
}
.inputPlaceholder:focus {
outline: none;
border: 1px solid #188ae2;
}
.drodown-input {
padding: 5px;
width: 100%;
font-size: 0.75rem;
border: 1px solid #8ad5ce;
/* border: 1px solid #e2dddd; */
/* background-color: #e0e5f5; */
color: black;
font-family: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
font-weight: inherit;
overflow: visible;
}
.drodown-input:focus {
outline: none;
border: 1px solid #099b8d;
}
.dropdownAdd {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
color: white;
font-weight: 600;
font-size: 13px;
border: none;
margin-left: 10px;
}
.dropdownAdd:focus {
outline: none;
}
.dropdownList {
display: flex;
flex-direction: column;
justify-content: center;
width: 50%;
}
.signatureCanvas {
border: 2px solid #888;
background-color: rgb(255, 255, 255);
@@ -50,19 +123,207 @@
width: 460px;
}
.icon {
.penContainerInitial {
width: 183px;
}
.borderResize {
position: absolute;
display: inline-block;
width: 14px;
height: 14px;
}
.borderResize :hover {
cursor: sw-resize;
}
.dropdown-date-menu {
min-width: 7rem;
}
.mailBtn {
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(79 190 241);
border: none !important;
color: white !important;
}
.mailBtn:hover {
box-shadow: 0 2px 4px rgba(154, 36, 36, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
}
.signatureBtn {
border: 1.5px solid #47a3ad;
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;
}
.disableSign {
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;
border: 1px solid rgb(203, 203, 203);
cursor: text;
}
.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;
}
.signatureInput {
width: 80%;
border-radius: 4px;
font-size: 20px;
border: 1px solid #e2dddd;
color: black;
font-family: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
font-weight: inherit;
overflow: visible;
height: 30px;
}
.signatureInput:focus {
outline: none;
border: 1px solid blue;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
}
.resizable-box-overlay {
position: absolute;
border: 2px solid #ddd;
overflow: hidden;
background-color: white;
}
.box-content {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
.close-button {
align-self: flex-end;
margin: 8px;
cursor: pointer;
}
.placeholdCloseBtn {
position: absolute;
right: -5px;
top: -5px;
border-radius: 100%;
font-size: 10px;
cursor: pointer;
padding: 0px 5.1px 1px 5px;
}
.signCloseBtn {
position: absolute;
font-size: 14px;
cursor: pointer;
z-index: 2;
background: white;
}
.ScrollbarsCustom-TrackY {
width: 4px !important;
.signCopy {
position: absolute;
font-size: 13px;
cursor: pointer;
z-index: 2;
background: white;
}
.ScrollbarsCustom-TrackX {
height: 4px !important;
.signUserIcon {
position: absolute;
font-size: 13px;
cursor: pointer;
z-index: 2;
background: white;
}
.settingIcon {
position: absolute;
font-size: 13px;
cursor: pointer;
z-index: 2;
background: white;
}
.ScrollbarsCustom-Track {
width: 4px !important;
}
.signYourselfBlock {
@@ -72,10 +333,19 @@
align-items: center !important;
}
.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;
border-radius: 2px;
}
.sendMail {
box-shadow:
0 1px 3px rgba(0, 0, 0, 0.1),
0 1px 2px rgba(0, 0, 0, 0.18);
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;
@@ -84,11 +354,105 @@
margin-left: 10px;
}
.user {
.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);
}
.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: 90%;
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;
border: "none";
}
.defaultBtn:focus {
border: none;
outline: none;
}
.signerList {
overflow-y: scroll;
max-height: 180px;
}
.signerList::-webkit-scrollbar {
display: none;
}
.showScroll {
height: 100%;
overflow: scroll;
}
.showScroll::-webkit-scrollbar {
display: none;
}
.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;
}
.disabled {
opacity: 0.5;
/* Example: reduce opacity to visually indicate disabled state */
@@ -97,6 +461,26 @@
/* background-color: #888; */
}
.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;
@@ -104,10 +488,70 @@
font-size: 15px !important;
}
.cancelBtn {
color: black;
border: 1px solid #ccc;
}
.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;
position: "relative";
}
.signerComponent {
/* box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; */
/* width: 180px; */
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 {
@@ -175,6 +619,7 @@
gap: 5px;
border: none;
background-color: #887abf;
width: 100px;
white-space: nowrap;
overflow: hidden !important;
@@ -236,8 +681,7 @@ option {
overflow: hidden;
background-color: white;
border-radius: 6px;
box-shadow:
0px 10px 38px -10px rgba(22, 23, 24, 0.35),
box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35),
0px 10px 20px -15px rgba(22, 23, 24, 0.2);
}
@@ -302,6 +746,11 @@ option {
cursor: default;
}
.fontOptionContainer {
border: 1px solid #d6d3d3;
margin: 10px 0px 5px 0px;
}
.dropDownStyle {
width: auto;
}
@@ -318,6 +767,16 @@ option {
width: 76%;
}
.regxSelect {
border: 1px solid #8ad5ce;
width: 80%;
}
.regxSelect:focus {
outline: none;
border: 1px solid #8ad5ce;
}
.radioGroupInput {
width: 100%;
}
@@ -328,18 +787,77 @@ option {
justify-content: flex-start;
}
.labelWidthDesktop {
min-width: 100%;
min-height: 100%;
}
.labelWidthMobile {
width: 100%;
height: 100%;
}
.labelTextArea {
font-size: 12px;
border: 1px solid #007bff;
outline: none;
z-index: 999;
border-radius: 2px;
resize: none;
overflow: hidden;
}
.labelTextArea:focus {
outline: none;
border: 1px solid #188ae2;
}
@media screen and (max-width: 766px) {
.validateInputText {
width: 93%;
}
.regxSelect {
width: 100%;
}
.validateText {
display: flex;
flex-direction: column;
justify-content: flex-start;
}
.showPages {
display: none;
}
.dropdown-menu {
min-width: 0rem !important;
}
.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: 49;
}
/* Navbar links */
@@ -373,13 +891,51 @@ option {
position: fixed;
}
.stickyfooter {
position: fixed;
z-index: 99 !important;
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 {
.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;
}
.signatureText {
margin-right: 5px;
font-size: 12px;
}
}
@media screen and (max-width: 487px) and (min-width: 351px) {
@@ -396,8 +952,17 @@ option {
font-size: 30px;
}
.hidePdf {
display: none;
}
.mobileHead {
display: flex;
}
.signTab {
font-weight: 500 !important;
font-size: 12px !important;
}
}
@@ -415,6 +980,10 @@ option {
width: 280px;
}
.hidePdf {
display: none;
}
.signTab {
font-weight: 500 !important;
@@ -424,6 +993,14 @@ option {
.uploadImgLogo {
font-size: 25px;
}
.uploadImg {
font-size: 10px !important;
}
.mobileHead {
display: flex;
}
}
@media screen and (max-width: 310px) {
@@ -436,12 +1013,178 @@ option {
width: 230px;
}
.hidePdf {
display: none;
}
.signTab {
font-weight: 500 !important;
font-size: 8px !important;
}
.uploadImgLogo {
font-size: 20px;
}
.uploadImg {
font-size: 10px !important;
}
.mobileHead {
display: flex;
}
}
.signature-backdrop {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background-color: #000;
}
.signature-backdrop.fade.in {
opacity: 0.5;
}
.modaloverlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.75);
justify-content: center;
align-items: center;
z-index: 900;
}
.modalcontainer {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
z-index: 901;
max-height: 80%;
min-width: 500px;
overflow-y: auto;
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* Internet Explorer and Edge */
}
.dropdownModal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
z-index: 901;
max-height: 80%;
min-width: 40%;
overflow-y: auto;
scrollbar-width: none;
/* Firefox */
-ms-overflow-style: none;
/* Internet Explorer and Edge */
}
/* Hide scrollbar for Webkit browsers */
.modalcontainer::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for Webkit browsers */
.dropdownModal::-webkit-scrollbar {
display: none;
}
.modalheader {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 20px;
border-bottom: 1px solid #ccc;
color: #ffffff;
}
/* Styling for the modal title */
.modaltitle {
font-size: 1.2rem;
font-weight: normal;
}
/* Styling for the close button */
.closebtn {
background: none;
border: none;
font-size: 1.5rem;
cursor: pointer;
}
.defaultOptions {
font-size: 12px;
margin-left: 5px;
}
.defaultOptions:focus {
outline: none;
}
@media (max-width: 767px) {
.modalcontainer {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
z-index: 1000;
max-height: 80%;
min-width: 90%;
overflow-y: auto;
}
.signatureBtn {
width: max-content;
}
.dropdownModal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
z-index: 1000;
max-height: 80%;
min-width: 60%;
overflow-y: auto;
}
}
@media (max-width: 464px) {
.dropdownModal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.3);
z-index: 1000;
max-height: 80%;
min-width: 78%;
overflow-y: auto;
}
}
+6 -6
View File
@@ -42,14 +42,14 @@ module.exports = {
"sunset",
{
opensigncss: {
primary: "#002864",
"primary-content": "#cacccf",
secondary: "#29354a",
"secondary-content": "#c8d1e0",
primary: "#034687",
"primary-content": "#ccd9e8",
secondary: "#151B25",
"secondary-content": "#cacccf",
accent: "#E10032",
"accent-content": "#ffd8d5",
neutral: "#c1ccdb",
"neutral-content": "#111312",
neutral: "#F0D7D9",
"neutral-content": "#141111",
"base-100": "#ffffff",
"base-200": "#dedede",
"base-300": "#bebebe",
+4 -4
View File
@@ -44,7 +44,7 @@
"mongodb-runner": "^5.6.2",
"nodemon": "^3.1.3",
"nyc": "15.1.0",
"prettier": "^3.3.2",
"prettier": "^3.3.0",
"uglify-js": "^3.17.4"
},
"engines": {
@@ -10298,9 +10298,9 @@
}
},
"node_modules/prettier": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
"integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.0.tgz",
"integrity": "sha512-J9odKxERhCQ10OC2yb93583f6UnYutOeiV5i0zEDS7UGTdUt0u+y8erxl3lBKvwo/JHyyoEdXjwp4dke9oyZ/g==",
"dev": true,
"bin": {
"prettier": "bin/prettier.cjs"
+1 -1
View File
@@ -54,7 +54,7 @@
"mongodb-runner": "^5.6.2",
"nodemon": "^3.1.3",
"nyc": "15.1.0",
"prettier": "^3.3.2",
"prettier": "^3.3.0",
"uglify-js": "^3.17.4"
},
"engines": {