mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-17 21:25:54 +02:00
Merge branch 'staging' of https://github.com/OpenSignLabs/OpenSign into validation
This commit is contained in:
@@ -369,7 +369,8 @@
|
||||
"copy-type": {
|
||||
"All pages": "All pages",
|
||||
"All pages but last": "All pages but last",
|
||||
"All pages but first": "All pages but first"
|
||||
"All pages but first": "All pages but first",
|
||||
"Beside to widget":"Beside to widget"
|
||||
},
|
||||
"options": "Options",
|
||||
"minimun-check": "Minimun check",
|
||||
@@ -612,5 +613,8 @@
|
||||
"additional-quicksend": "Please purchase add-on quick send",
|
||||
"quantityofquicksend": "Quantity of Quick send",
|
||||
"quotaerrquicksend": "Quota Reached, You don't have enough credits.",
|
||||
"buycredits": "Buy credits"
|
||||
}
|
||||
"buycredits": "Buy credits",
|
||||
"rotate-right":"Rotate right",
|
||||
"rotate-left":"Rotate left",
|
||||
"rotate-alert-mssg":"All widgets on this page will be lost. Are you sure you want to proceed?"
|
||||
}
|
||||
|
||||
@@ -369,7 +369,8 @@
|
||||
"copy-type": {
|
||||
"All pages": "Toutes les pages",
|
||||
"All pages but last": "Toutes les pages sauf la dernière",
|
||||
"All pages but first": "Toutes les pages sauf la première"
|
||||
"All pages but first": "Toutes les pages sauf la première",
|
||||
"Beside to widget": "À côté du widget"
|
||||
},
|
||||
"options": "Possibilités",
|
||||
"minimun-check": "Vérification minimale",
|
||||
@@ -612,6 +613,8 @@
|
||||
"additional-quicksend":"Veuillez acheter le module complémentaire quick send",
|
||||
"quantityofquicksend": "Quantité de Quick send",
|
||||
"quotaerrquicksend": "Quota atteint, vous n'avez pas assez de crédits.",
|
||||
"buycredits": "Acheter des crédits"
|
||||
|
||||
}
|
||||
"buycredits": "Acheter des crédits",
|
||||
"rotate-right" :"Faire pivoter à droite",
|
||||
"rotate-left" :"Faire pivoter à gauche",
|
||||
"rotate-alert-mssg" :"Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?"
|
||||
}
|
||||
|
||||
@@ -227,11 +227,7 @@ const Header = ({ showSidebar }) => {
|
||||
<i className="fa-light fa-lock"></i> {t("change-password")}
|
||||
</span>
|
||||
</li>
|
||||
<li
|
||||
onClick={() => {
|
||||
handleConsoleRedirect();
|
||||
}}
|
||||
>
|
||||
<li onClick={() => handleConsoleRedirect()}>
|
||||
<span>
|
||||
<i className="fa-light fa-id-card"></i> Console
|
||||
</span>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import React from "react";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function RotateAlert(props) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<ModalUi
|
||||
isOpen={props.isRotate}
|
||||
title={t("Rotation-alert")}
|
||||
handleClose={() => props.setIsRotate({ status: false, degree: 0 })}
|
||||
>
|
||||
{" "}
|
||||
<div className="p-[20px] h-full">
|
||||
<p>{t("rotate-alert-mssg")}</p>
|
||||
<div className="h-[1px] w-full my-[15px] bg-[#9f9f9f]"></div>
|
||||
<div className="flex gap-1">
|
||||
<button
|
||||
onClick={() => props.setIsRotate({ status: false, degree: 0 })}
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost shadow-md"
|
||||
>
|
||||
{t("no")}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => props.handleRemoveWidgets()}
|
||||
type="button"
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
{t("yes")}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
);
|
||||
}
|
||||
|
||||
export default RotateAlert;
|
||||
@@ -34,7 +34,11 @@ function Header({
|
||||
setIsEmail,
|
||||
completeBtnTitle,
|
||||
setIsEditTemplate,
|
||||
isPublicTemplate
|
||||
isPublicTemplate,
|
||||
clickOnZoomIn,
|
||||
clickOnZoomOut,
|
||||
handleRotationFun,
|
||||
isDisableRotate
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const filterPrefill =
|
||||
@@ -73,7 +77,7 @@ function Header({
|
||||
allPages={allPages}
|
||||
changePage={changePage}
|
||||
/>
|
||||
{pdfUrl && alreadySign ? (
|
||||
{isCompleted && alreadySign ? (
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<div className="op-link op-link-primary no-underline text-[16px] font-semibold pr-[3px] pl-[5px]">
|
||||
@@ -184,13 +188,7 @@ function Header({
|
||||
) : (
|
||||
<div
|
||||
data-tut="reactourThird"
|
||||
onClick={() => {
|
||||
if (!pdfUrl) {
|
||||
embedWidgetsData();
|
||||
} else if (isPdfRequestFiles) {
|
||||
embedWidgetsData();
|
||||
}
|
||||
}}
|
||||
onClick={() => embedWidgetsData()}
|
||||
className="border-none font-[650] text-[14px] op-link op-link-primary no-underline"
|
||||
>
|
||||
{t("finish")}
|
||||
@@ -207,7 +205,7 @@ function Header({
|
||||
</DropdownMenu.Trigger>
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
className="bg-white shadow-md rounded-full px-3 py-2"
|
||||
className="bg-white shadow-md rounded-md px-3 py-2"
|
||||
sideOffset={5}
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
@@ -215,7 +213,7 @@ function Header({
|
||||
onClick={() =>
|
||||
handleDownloadPdf(
|
||||
pdfDetails,
|
||||
pdfUrl,
|
||||
pdfDetails[0]?.URL,
|
||||
setIsDownloading
|
||||
)
|
||||
}
|
||||
@@ -226,6 +224,43 @@ function Header({
|
||||
></i>
|
||||
<span className="font-[500]">{t("download")}</span>
|
||||
</DropdownMenu.Item>
|
||||
{!isDisableRotate && (
|
||||
<>
|
||||
<DropdownMenu.Item
|
||||
className="flex flex-row justify-center items-center text-[13px] focus:outline-none cursor-pointer"
|
||||
onClick={() => handleRotationFun(90)}
|
||||
>
|
||||
<i className="fa-light fa-rotate-right text-gray-500 2xl:text-[30px] mr-[3px]"></i>
|
||||
<span className="font-[500]">
|
||||
{t("rotate-right")}
|
||||
</span>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
className="flex flex-row justify-center items-center text-[13px] focus:outline-none cursor-pointer"
|
||||
onClick={() => handleRotationFun(-90)}
|
||||
>
|
||||
<i className="fa-light fa-rotate-left text-gray-500 2xl:text-[30px] mr-[3px]"></i>
|
||||
<span className="font-[500]">
|
||||
{t("rotate-left")}
|
||||
</span>
|
||||
</DropdownMenu.Item>
|
||||
</>
|
||||
)}
|
||||
|
||||
<DropdownMenu.Item
|
||||
className="flex flex-row justify-center items-center text-[13px] focus:outline-none cursor-pointer"
|
||||
onClick={() => clickOnZoomIn()}
|
||||
>
|
||||
<i className="fa-light fa-magnifying-glass-plus text-gray-500 2xl:text-[30px]"></i>
|
||||
<span className="font-[500]">{t("zoom-in")}</span>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
className="flex flex-row justify-center items-center text-[13px] focus:outline-none cursor-pointer"
|
||||
onClick={() => clickOnZoomOut()}
|
||||
>
|
||||
<i className="fa-light fa-magnifying-glass-minus text-gray-500 2xl:text-[30px]"></i>
|
||||
<span className="font-[500]">{t("zoom-out")}</span>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
@@ -423,9 +458,7 @@ function Header({
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-primary op-btn-sm shadow"
|
||||
onClick={() => {
|
||||
embedWidgetsData();
|
||||
}}
|
||||
onClick={() => embedWidgetsData()}
|
||||
>
|
||||
{t("sign-now")}
|
||||
</button>
|
||||
@@ -442,11 +475,7 @@ function Header({
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-primary op-btn-sm mr-[3px]"
|
||||
onClick={() => {
|
||||
if (!pdfUrl) {
|
||||
embedWidgetsData();
|
||||
}
|
||||
}}
|
||||
onClick={() => embedWidgetsData()}
|
||||
>
|
||||
{t("finish")}
|
||||
</button>
|
||||
|
||||
@@ -3,44 +3,37 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
function PdfZoom(props) {
|
||||
const { t } = useTranslation();
|
||||
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="hidden md:flex flex-col gap-1 text-center md:w-[5%] mt-[43px] 2xl:mt-[63px]">
|
||||
<span
|
||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||
onClick={onClickZoomIn}
|
||||
onClick={() => props.clickOnZoomIn()}
|
||||
title={t("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={t("reset")}
|
||||
>
|
||||
<i className="fa-light fa-magnifying-glass-arrows-rotate text-gray-500 2xl:text-[30px]"></i>
|
||||
</span>
|
||||
{!props?.isDisableRotate && (
|
||||
<>
|
||||
<span
|
||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||
onClick={() => props.handleRotationFun(90)}
|
||||
title={t("rotate-right")}
|
||||
>
|
||||
<i className="fa-light fa-rotate-right text-gray-500 2xl:text-[30px]"></i>
|
||||
</span>
|
||||
<span
|
||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px] cursor-pointer"
|
||||
title={t("rotate-left")}
|
||||
onClick={() => props.handleRotationFun(-90)}
|
||||
>
|
||||
<i className="fa-light fa-rotate-left text-gray-500 2xl:text-[30px]"></i>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
<span
|
||||
className="bg-gray-50 px-[4px] 2xl:px-[15px] 2xl:py-[10px]"
|
||||
onClick={onClickZoomOut}
|
||||
onClick={() => props.clickOnZoomOut()}
|
||||
style={{
|
||||
cursor: props.zoomPercent > 0 ? "pointer" : "default"
|
||||
}}
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
import React, { useState } from "react";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import { randomId, textWidget } from "../../constant/Utils";
|
||||
import {
|
||||
handleCopyNextToWidget,
|
||||
randomId,
|
||||
textWidget
|
||||
} from "../../constant/Utils";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
function PlaceholderCopy(props) {
|
||||
const { t } = useTranslation();
|
||||
const copyType = ["All pages", "All pages but last", "All pages but first"];
|
||||
const [selectCopyType, setSelectCopyType] = useState("");
|
||||
const copyType = [
|
||||
{ id: 1, type: "All pages" },
|
||||
{ id: 2, type: "All pages but last" },
|
||||
{ id: 3, type: "All pages but first" },
|
||||
{ id: 4, type: "Beside to widget" }
|
||||
];
|
||||
const [selectCopyType, setSelectCopyType] = useState(1);
|
||||
//function for get copy placeholder position
|
||||
const getCopyPlaceholderPosition = (
|
||||
type,
|
||||
@@ -20,7 +29,7 @@ function PlaceholderCopy(props) {
|
||||
(data) => data.xPosition !== currentPlaceholder.xPosition
|
||||
);
|
||||
//copy all page placeholder at requested position except first page
|
||||
if (newPageNumber === 1 && type === "first") {
|
||||
if (newPageNumber === 1 && type === 3) {
|
||||
if (filterPosition && filterPosition.length > 0) {
|
||||
return {
|
||||
pageNumber: newPageNumber,
|
||||
@@ -29,7 +38,7 @@ function PlaceholderCopy(props) {
|
||||
}
|
||||
}
|
||||
//copy all page placeholder at requested position except last page
|
||||
else if (newPageNumber === props.allPages && type === "last") {
|
||||
else if (newPageNumber === props.allPages && type === 2) {
|
||||
if (existPlaceholderPosition) {
|
||||
return {
|
||||
pageNumber: newPageNumber,
|
||||
@@ -172,20 +181,60 @@ function PlaceholderCopy(props) {
|
||||
|
||||
//function for getting selected type placeholder copy
|
||||
const handleApplyCopy = () => {
|
||||
if (selectCopyType === "All pages") {
|
||||
copyPlaceholder("all");
|
||||
} else if (selectCopyType === "All pages but last") {
|
||||
copyPlaceholder("last");
|
||||
} else if (selectCopyType === "All pages but first") {
|
||||
copyPlaceholder("first");
|
||||
if (selectCopyType === 4) {
|
||||
const signerPosition = props.xyPostion;
|
||||
let currentXYposition;
|
||||
const signerId = props.signerObjId ? props.signerObjId : props.Id;
|
||||
if (signerId) {
|
||||
const filterSignerPosition = signerPosition.filter(
|
||||
(item) => item?.Id === signerId
|
||||
);
|
||||
currentXYposition = filterSignerPosition[0].placeHolder.filter(
|
||||
(data) => data.pageNumber === props?.pageNumber
|
||||
);
|
||||
//get current placeholder position data which user want to copy
|
||||
currentXYposition = currentXYposition[0].pos.find(
|
||||
(position) => position.key === props.signKey
|
||||
);
|
||||
//function to create new widget next to just widget
|
||||
handleCopyNextToWidget(
|
||||
currentXYposition,
|
||||
props.widgetType,
|
||||
props.xyPostion,
|
||||
props.pageNumber,
|
||||
props.setXyPostion,
|
||||
props?.Id
|
||||
);
|
||||
} else {
|
||||
const getIndex = props?.xyPostion.findIndex(
|
||||
(data) => data.pageNumber === props.pageNumber
|
||||
);
|
||||
const placeholderPosition = props?.xyPostion[getIndex];
|
||||
//get current placeholder position data which user want to copy
|
||||
currentXYposition = placeholderPosition.pos.find(
|
||||
(pos) => pos.key === props.signKey
|
||||
);
|
||||
//function to create new widget next to just widget
|
||||
handleCopyNextToWidget(
|
||||
currentXYposition,
|
||||
props.widgetType,
|
||||
props.xyPostion,
|
||||
getIndex,
|
||||
props.setXyPostion
|
||||
);
|
||||
}
|
||||
} else {
|
||||
copyPlaceholder(selectCopyType);
|
||||
}
|
||||
};
|
||||
const handleUniqueId = () => {
|
||||
if (props.widgetType === textWidget) {
|
||||
const signerId = props.signerObjId ? props.signerObjId : props.Id;
|
||||
if (signerId && props.widgetType === textWidget) {
|
||||
props.setUniqueId(props?.tempSignerId);
|
||||
props.setTempSignerId("");
|
||||
}
|
||||
props.setIsPageCopy(false);
|
||||
setSelectCopyType(1);
|
||||
};
|
||||
return (
|
||||
<ModalUi
|
||||
@@ -201,11 +250,11 @@ function PlaceholderCopy(props) {
|
||||
<input
|
||||
className="mr-[8px] op-radio op-radio-xs"
|
||||
type="radio"
|
||||
value={data}
|
||||
onChange={() => setSelectCopyType(data)}
|
||||
checked={selectCopyType === data}
|
||||
value={data.id}
|
||||
onChange={() => setSelectCopyType(data.id)}
|
||||
checked={selectCopyType === data.id}
|
||||
/>
|
||||
{t(`copy-type.${data}`)}
|
||||
{t(`copy-type.${data.type}`)}
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -12,7 +12,8 @@ function RenderAllPdfPage({
|
||||
pageNumber,
|
||||
signerPos,
|
||||
signerObjectId,
|
||||
containerWH
|
||||
containerWH,
|
||||
pdfRotateBase64
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const [signPageNumber, setSignPageNumber] = useState([]);
|
||||
@@ -66,6 +67,7 @@ function RenderAllPdfPage({
|
||||
)
|
||||
);
|
||||
};
|
||||
const pdfDataBase64 = `data:application/pdf;base64,${pdfRotateBase64}`;
|
||||
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">
|
||||
@@ -78,7 +80,7 @@ function RenderAllPdfPage({
|
||||
<Document
|
||||
loading={t("loading-doc")}
|
||||
onLoadSuccess={onDocumentLoad}
|
||||
file={signPdfUrl}
|
||||
file={(pdfRotateBase64 && pdfDataBase64) || signPdfUrl}
|
||||
>
|
||||
{Array.from(new Array(allPages), (el, index) => (
|
||||
<div
|
||||
|
||||
@@ -62,6 +62,7 @@ function RenderPdf({
|
||||
setIsSelectId,
|
||||
ispublicTemplate,
|
||||
handleUserDetails,
|
||||
pdfRotateBase64,
|
||||
fontSize,
|
||||
setFontSize,
|
||||
fontColor,
|
||||
@@ -69,6 +70,7 @@ function RenderPdf({
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const isMobile = window.innerWidth < 767;
|
||||
|
||||
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
|
||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||
|
||||
@@ -252,163 +254,177 @@ function RenderPdf({
|
||||
);
|
||||
}
|
||||
};
|
||||
const pdfDataBase64 = `data:application/pdf;base64,${pdfRotateBase64}`;
|
||||
|
||||
return (
|
||||
<>
|
||||
{successEmail && (
|
||||
<Alert type={"success"}>{t("success-email-alert")}</Alert>
|
||||
)}
|
||||
{isMobile ? (
|
||||
<div
|
||||
data-tut="reactourForth"
|
||||
className={`${
|
||||
isGuestSigner ? "30px" : ""
|
||||
} border-[0.1px] border-[#ebe8e8]`}
|
||||
ref={drop}
|
||||
id="container"
|
||||
<RSC
|
||||
style={{
|
||||
position: "relative",
|
||||
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
||||
height: window.innerHeight - 200,
|
||||
zIndex: 0
|
||||
}}
|
||||
className="h-full"
|
||||
noScrollY={false}
|
||||
noScrollX={scale === 1 ? true : false}
|
||||
>
|
||||
{containerWH?.width &&
|
||||
pdfOriginalWH.length > 0 &&
|
||||
(pdfRequest
|
||||
? signerPos.map((data, key) => {
|
||||
return (
|
||||
<React.Fragment key={key}>
|
||||
{checkSignedSigners(data)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
: placeholder // placeholder mobile
|
||||
? signerPos.map((data, ind) => {
|
||||
<div
|
||||
data-tut="reactourForth"
|
||||
className={`${
|
||||
isGuestSigner ? "30px" : ""
|
||||
} border-[0.1px] border-[#ebe8e8] overflow-x-auto`}
|
||||
style={{
|
||||
width: containerWH?.width && containerWH?.width * scale
|
||||
}}
|
||||
ref={drop}
|
||||
id="container"
|
||||
>
|
||||
{containerWH?.width &&
|
||||
pdfOriginalWH.length > 0 &&
|
||||
(pdfRequest
|
||||
? signerPos.map((data, key) => {
|
||||
return (
|
||||
<React.Fragment key={ind}>
|
||||
{data.placeHolder.map((placeData, index) => {
|
||||
return (
|
||||
<React.Fragment key={index}>
|
||||
{placeData.pageNumber === pageNumber &&
|
||||
placeData.pos.map((pos) => {
|
||||
return (
|
||||
<React.Fragment key={pos.key}>
|
||||
<Placeholder
|
||||
pos={pos}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
setSignKey={setSignKey}
|
||||
handleDeleteSign={handleDeleteSign}
|
||||
setIsStamp={setIsStamp}
|
||||
handleTabDrag={handleTabDrag}
|
||||
handleStop={handleStop}
|
||||
handleSignYourselfImageResize={
|
||||
handleImageResize
|
||||
}
|
||||
index={pageNumber}
|
||||
xyPostion={signerPos}
|
||||
setXyPostion={setSignerPos}
|
||||
setSignerObjId={setSignerObjId}
|
||||
data={data}
|
||||
setIsResize={setIsResize}
|
||||
setShowDropdown={setShowDropdown}
|
||||
isShowBorder={true}
|
||||
isPlaceholder={true}
|
||||
setUniqueId={setUniqueId}
|
||||
handleLinkUser={handleLinkUser}
|
||||
handleUserName={handleUserName}
|
||||
isSignYourself={false}
|
||||
posWidth={posWidth}
|
||||
posHeight={posHeight}
|
||||
isDragging={isDragging}
|
||||
setIsValidate={setIsValidate}
|
||||
setWidgetType={setWidgetType}
|
||||
setIsRadio={setIsRadio}
|
||||
setIsCheckbox={setIsCheckbox}
|
||||
setCurrWidgetsDetails={
|
||||
setCurrWidgetsDetails
|
||||
}
|
||||
setSelectWidgetId={setSelectWidgetId}
|
||||
selectWidgetId={selectWidgetId}
|
||||
handleNameModal={handleNameModal}
|
||||
setTempSignerId={setTempSignerId}
|
||||
uniqueId={uniqueId}
|
||||
handleTextSettingModal={
|
||||
handleTextSettingModal
|
||||
}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
setIsSelectId={setIsSelectId}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
<React.Fragment key={key}>
|
||||
{checkSignedSigners(data)}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
: xyPostion.map((data, ind) => {
|
||||
return (
|
||||
<React.Fragment key={ind}>
|
||||
{data.pageNumber === pageNumber &&
|
||||
data.pos.map((pos) => {
|
||||
: placeholder // placeholder mobile
|
||||
? signerPos.map((data, ind) => {
|
||||
return (
|
||||
<React.Fragment key={ind}>
|
||||
{data.placeHolder.map((placeData, index) => {
|
||||
return (
|
||||
pos && (
|
||||
<Placeholder
|
||||
pos={pos}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
setSignKey={setSignKey}
|
||||
handleDeleteSign={handleDeleteSign}
|
||||
setIsStamp={setIsStamp}
|
||||
handleTabDrag={handleTabDrag}
|
||||
handleStop={handleStop}
|
||||
handleSignYourselfImageResize={
|
||||
handleSignYourselfImageResize
|
||||
}
|
||||
index={index}
|
||||
xyPostion={xyPostion}
|
||||
setXyPostion={setXyPostion}
|
||||
containerWH={containerWH}
|
||||
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}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
/>
|
||||
)
|
||||
<React.Fragment key={index}>
|
||||
{placeData.pageNumber === pageNumber &&
|
||||
placeData.pos.map((pos) => {
|
||||
return (
|
||||
<React.Fragment key={pos.key}>
|
||||
<Placeholder
|
||||
pos={pos}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
setSignKey={setSignKey}
|
||||
handleDeleteSign={handleDeleteSign}
|
||||
setIsStamp={setIsStamp}
|
||||
handleTabDrag={handleTabDrag}
|
||||
handleStop={handleStop}
|
||||
handleSignYourselfImageResize={
|
||||
handleImageResize
|
||||
}
|
||||
index={pageNumber}
|
||||
xyPostion={signerPos}
|
||||
setXyPostion={setSignerPos}
|
||||
setSignerObjId={setSignerObjId}
|
||||
data={data}
|
||||
setIsResize={setIsResize}
|
||||
setShowDropdown={setShowDropdown}
|
||||
isShowBorder={true}
|
||||
isPlaceholder={true}
|
||||
setUniqueId={setUniqueId}
|
||||
handleLinkUser={handleLinkUser}
|
||||
handleUserName={handleUserName}
|
||||
isSignYourself={false}
|
||||
posWidth={posWidth}
|
||||
posHeight={posHeight}
|
||||
isDragging={isDragging}
|
||||
setIsValidate={setIsValidate}
|
||||
setWidgetType={setWidgetType}
|
||||
setIsRadio={setIsRadio}
|
||||
setIsCheckbox={setIsCheckbox}
|
||||
setCurrWidgetsDetails={
|
||||
setCurrWidgetsDetails
|
||||
}
|
||||
setSelectWidgetId={setSelectWidgetId}
|
||||
selectWidgetId={selectWidgetId}
|
||||
handleNameModal={handleNameModal}
|
||||
setTempSignerId={setTempSignerId}
|
||||
uniqueId={uniqueId}
|
||||
handleTextSettingModal={
|
||||
handleTextSettingModal
|
||||
}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
setIsSelectId={setIsSelectId}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
/>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</React.Fragment>
|
||||
);
|
||||
}))}
|
||||
</React.Fragment>
|
||||
);
|
||||
})
|
||||
: xyPostion.map((data, ind) => {
|
||||
return (
|
||||
<React.Fragment key={ind}>
|
||||
{data.pageNumber === pageNumber &&
|
||||
data.pos.map((pos) => {
|
||||
return (
|
||||
pos && (
|
||||
<Placeholder
|
||||
pos={pos}
|
||||
setIsPageCopy={setIsPageCopy}
|
||||
setSignKey={setSignKey}
|
||||
handleDeleteSign={handleDeleteSign}
|
||||
setIsStamp={setIsStamp}
|
||||
handleTabDrag={handleTabDrag}
|
||||
handleStop={handleStop}
|
||||
handleSignYourselfImageResize={
|
||||
handleSignYourselfImageResize
|
||||
}
|
||||
index={index}
|
||||
xyPostion={xyPostion}
|
||||
setXyPostion={setXyPostion}
|
||||
containerWH={containerWH}
|
||||
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}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
/>
|
||||
)
|
||||
);
|
||||
})}
|
||||
</React.Fragment>
|
||||
);
|
||||
}))}
|
||||
|
||||
{/* this component for render pdf document is in middle of the component */}
|
||||
<div className="flex items-center justify-center">
|
||||
<Document
|
||||
onLoadError={() => {
|
||||
setPdfLoad(false);
|
||||
}}
|
||||
onLoadError={() => setPdfLoad(false)}
|
||||
loading={t("loading-doc")}
|
||||
onLoadSuccess={pageDetails}
|
||||
// ref={pdfRef}'
|
||||
@@ -417,9 +433,14 @@ function RenderPdf({
|
||||
setSelectWidgetId("");
|
||||
}
|
||||
}}
|
||||
file={pdfDetails[0]?.SignedUrl || pdfDetails[0]?.URL}
|
||||
file={
|
||||
(pdfRotateBase64 && pdfDataBase64) ||
|
||||
pdfDetails[0]?.SignedUrl ||
|
||||
pdfDetails[0].URL
|
||||
}
|
||||
>
|
||||
<Page
|
||||
scale={scale || 1}
|
||||
key={index}
|
||||
pageNumber={pageNumber}
|
||||
width={containerWH.width}
|
||||
@@ -431,7 +452,7 @@ function RenderPdf({
|
||||
/>
|
||||
</Document>
|
||||
</div>
|
||||
</div>
|
||||
</RSC>
|
||||
) : (
|
||||
<RSC
|
||||
style={{
|
||||
@@ -595,9 +616,7 @@ function RenderPdf({
|
||||
|
||||
{/* this component for render pdf document is in middle of the component */}
|
||||
<Document
|
||||
onLoadError={() => {
|
||||
setPdfLoad(false);
|
||||
}}
|
||||
onLoadError={() => setPdfLoad(false)}
|
||||
loading={t("loading-doc")}
|
||||
onLoadSuccess={pageDetails}
|
||||
onClick={() => {
|
||||
@@ -606,7 +625,11 @@ function RenderPdf({
|
||||
}
|
||||
}}
|
||||
// ref={pdfRef}
|
||||
file={pdfDetails[0]?.SignedUrl || pdfDetails[0].URL}
|
||||
file={
|
||||
(pdfRotateBase64 && pdfDataBase64) ||
|
||||
pdfDetails[0]?.SignedUrl ||
|
||||
pdfDetails[0].URL
|
||||
}
|
||||
>
|
||||
<Page
|
||||
key={index}
|
||||
|
||||
@@ -56,9 +56,7 @@ function VerifyEmail(props) {
|
||||
<button
|
||||
className="op-btn op-btn-primary"
|
||||
type="submit"
|
||||
onClick={() => {
|
||||
props.handleVerifyBtn();
|
||||
}}
|
||||
onClick={() => props.handleVerifyBtn()}
|
||||
>
|
||||
{t("send-otp")}
|
||||
</button>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import axios from "axios";
|
||||
import moment from "moment";
|
||||
import React from "react";
|
||||
import { rgb } from "pdf-lib";
|
||||
import { PDFDocument, rgb, degrees } from "pdf-lib";
|
||||
import Parse from "parse";
|
||||
import { appInfo } from "./appinfo";
|
||||
import { saveAs } from "file-saver";
|
||||
@@ -658,7 +658,12 @@ export const randomId = () => {
|
||||
return randomDigit;
|
||||
};
|
||||
|
||||
export const createDocument = async (template, placeholders, signerData) => {
|
||||
export const createDocument = async (
|
||||
template,
|
||||
placeholders,
|
||||
signerData,
|
||||
pdfUrl
|
||||
) => {
|
||||
if (template && template.length > 0) {
|
||||
const Doc = template[0];
|
||||
|
||||
@@ -681,7 +686,7 @@ export const createDocument = async (template, placeholders, signerData) => {
|
||||
}
|
||||
const data = {
|
||||
Name: Doc.Name,
|
||||
URL: Doc.URL,
|
||||
URL: pdfUrl,
|
||||
SignedUrl: Doc.SignedUrl,
|
||||
SentToOthers: Doc.SentToOthers,
|
||||
Description: Doc.Description,
|
||||
@@ -867,7 +872,6 @@ export const onChangeInput = (
|
||||
}
|
||||
} else {
|
||||
let getXYdata = xyPostion[index].pos;
|
||||
|
||||
const updatePosition = getXYdata.map((positionData) => {
|
||||
if (positionData.key === signKey) {
|
||||
if (dateFormat) {
|
||||
@@ -1077,13 +1081,18 @@ export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
||||
const textContent = documentId && `OpenSign™ DocumentId: ${documentId} `;
|
||||
const pages = pdfDoc.getPages();
|
||||
const page = pages[i];
|
||||
page.drawText(textContent, {
|
||||
x: 10,
|
||||
y: page.getHeight() - 10,
|
||||
size: fontSize,
|
||||
const getObj = compensateRotation(
|
||||
page.getRotation().angle,
|
||||
10,
|
||||
5,
|
||||
1,
|
||||
page.getSize(),
|
||||
fontSize,
|
||||
rgb(0.5, 0.5, 0.5),
|
||||
font,
|
||||
color: rgb(0.5, 0.5, 0.5)
|
||||
});
|
||||
page
|
||||
);
|
||||
page.drawText(textContent, getObj);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1849,29 +1858,26 @@ export const handleCopyNextToWidget = (
|
||||
setXyPostion,
|
||||
userId
|
||||
) => {
|
||||
const isSigners = xyPostion.some((data) => data.signerPtr);
|
||||
let filterSignerPos;
|
||||
//get position of previous widget and create new widget next to that widget on same data except
|
||||
// xPosition and key
|
||||
let newpos = position;
|
||||
let newposition = position;
|
||||
const calculateXPosition =
|
||||
parseInt(position.xPosition) +
|
||||
defaultWidthHeight(widgetType).width +
|
||||
resizeBorderExtraWidth();
|
||||
const newId = randomId();
|
||||
newpos = { ...newpos, xPosition: calculateXPosition, key: newId };
|
||||
newposition = { ...newposition, xPosition: calculateXPosition, key: newId };
|
||||
//if condition to create widget in request-sign flow
|
||||
if (isSigners) {
|
||||
if (userId) {
|
||||
filterSignerPos = xyPostion.filter((data) => data.Id === userId);
|
||||
}
|
||||
const getPlaceHolder = filterSignerPos[0]?.placeHolder;
|
||||
const getPageNumer = getPlaceHolder.filter(
|
||||
if (userId) {
|
||||
filterSignerPos = xyPostion.filter((data) => data.Id === userId);
|
||||
const getPlaceHolder = filterSignerPos && filterSignerPos[0]?.placeHolder;
|
||||
const getPageNumer = getPlaceHolder?.filter(
|
||||
(data) => data.pageNumber === index
|
||||
);
|
||||
const getXYdata = getPageNumer[0].pos;
|
||||
getXYdata.push(newpos);
|
||||
if (getPageNumer.length > 0) {
|
||||
const getXYdata = getPageNumer && getPageNumer[0]?.pos;
|
||||
getXYdata.push(newposition);
|
||||
if (getPageNumer && getPageNumer.length > 0) {
|
||||
const newUpdateSignPos = getPlaceHolder.map((obj) => {
|
||||
if (obj.pageNumber === index) {
|
||||
return { ...obj, pos: getXYdata };
|
||||
@@ -1889,9 +1895,8 @@ export const handleCopyNextToWidget = (
|
||||
setXyPostion(newUpdateSigner);
|
||||
}
|
||||
} else {
|
||||
// else condition to create widget in sign-yourself flow
|
||||
let getXYdata = xyPostion[index].pos;
|
||||
getXYdata.push(newpos);
|
||||
let getXYdata = xyPostion[index]?.pos || [];
|
||||
getXYdata.push(newposition);
|
||||
const updatePlaceholder = xyPostion.map((obj, ind) => {
|
||||
if (ind === index) {
|
||||
return { ...obj, pos: getXYdata };
|
||||
@@ -2192,9 +2197,11 @@ function compensateRotation(
|
||||
font,
|
||||
page
|
||||
) {
|
||||
// Ensure pageRotation is between 0 and 360 degrees
|
||||
pageRotation = ((pageRotation % 360) + 360) % 360;
|
||||
let rotationRads = (pageRotation * Math.PI) / 180;
|
||||
|
||||
//These coords are now from bottom/left
|
||||
// Coordinates are from bottom-left
|
||||
let coordsFromBottomLeft = { x: x / scale };
|
||||
if (pageRotation === 90 || pageRotation === 270) {
|
||||
coordsFromBottomLeft.y = dimensions.width - (y + fontSize) / scale;
|
||||
@@ -2204,6 +2211,7 @@ function compensateRotation(
|
||||
|
||||
let drawX = null;
|
||||
let drawY = null;
|
||||
|
||||
if (pageRotation === 90) {
|
||||
drawX =
|
||||
coordsFromBottomLeft.x * Math.cos(rotationRads) -
|
||||
@@ -2229,8 +2237,8 @@ function compensateRotation(
|
||||
coordsFromBottomLeft.x * Math.sin(rotationRads) +
|
||||
coordsFromBottomLeft.y * Math.cos(rotationRads) +
|
||||
dimensions.height;
|
||||
} else {
|
||||
//no rotation
|
||||
} else if (pageRotation === 0 || pageRotation === 360) {
|
||||
// No rotation or full rotation
|
||||
drawX = coordsFromBottomLeft.x;
|
||||
drawY = coordsFromBottomLeft.y;
|
||||
}
|
||||
@@ -2334,3 +2342,114 @@ export const getDefaultSignature = async (objectId) => {
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
//function to rotate pdf page
|
||||
export async function rotatePdfPage(
|
||||
url,
|
||||
rotateDegree,
|
||||
pageNumber,
|
||||
pdfRotateBase64
|
||||
) {
|
||||
let file;
|
||||
|
||||
//condition to handle pdf base64 in arrayBuffer format
|
||||
if (pdfRotateBase64) {
|
||||
file = base64ToArrayBuffer(pdfRotateBase64);
|
||||
} else {
|
||||
//condition to handle pdf url in arrayBuffer format
|
||||
file = await convertPdfArrayBuffer(url);
|
||||
}
|
||||
// Load the existing PDF
|
||||
const pdfDoc = await PDFDocument.load(file);
|
||||
// Get the page according to page number
|
||||
const page = pdfDoc.getPage(pageNumber);
|
||||
//get current page rotation angle
|
||||
const currentRotation = page.getRotation().angle;
|
||||
// Apply the rotation in the counterclockwise direction
|
||||
let newRotation = (currentRotation + rotateDegree) % 360;
|
||||
// Adjust for negative angles to keep within 0-359 range
|
||||
if (newRotation < 0) {
|
||||
newRotation += 360;
|
||||
}
|
||||
page.setRotation(degrees(newRotation));
|
||||
const pdfbase64 = await pdfDoc.saveAsBase64({ useObjectStreams: false });
|
||||
//convert base64 to arraybuffer is used in pdf-lib
|
||||
//pdfbase64 is used to show pdf rotated format
|
||||
const arrayBuffer = base64ToArrayBuffer(pdfbase64);
|
||||
//`base64` is used to show pdf
|
||||
return { arrayBuffer: arrayBuffer, base64: pdfbase64 };
|
||||
}
|
||||
function base64ToArrayBuffer(base64) {
|
||||
// Decode the base64 string to a binary string
|
||||
const binaryString = atob(base64);
|
||||
// Create a new ArrayBuffer with the same length as the binary string
|
||||
const len = binaryString.length;
|
||||
const bytes = new Uint8Array(len);
|
||||
// Convert the binary string to a byte array
|
||||
for (let i = 0; i < len; i++) {
|
||||
bytes[i] = binaryString.charCodeAt(i);
|
||||
}
|
||||
// Return the ArrayBuffer
|
||||
return bytes.buffer;
|
||||
}
|
||||
|
||||
export const convertBase64ToFile = async (pdfName, pdfBase64) => {
|
||||
const fileName = sanitizeFileName(pdfName) + ".pdf";
|
||||
const pdfFile = new Parse.File(fileName, { base64: pdfBase64 });
|
||||
// Save the Parse File if needed
|
||||
const pdfData = await pdfFile.save();
|
||||
const pdfUrl = pdfData.url();
|
||||
return pdfUrl;
|
||||
};
|
||||
export const onClickZoomIn = (scale, zoomPercent, setScale, setZoomPercent) => {
|
||||
setScale(scale + 0.1 * scale);
|
||||
setZoomPercent(zoomPercent + 10);
|
||||
};
|
||||
export const onClickZoomOut = (
|
||||
zoomPercent,
|
||||
scale,
|
||||
setZoomPercent,
|
||||
setScale
|
||||
) => {
|
||||
if (zoomPercent > 0) {
|
||||
if (zoomPercent === 10) {
|
||||
setScale(1);
|
||||
} else {
|
||||
setScale(scale - 0.1 * scale);
|
||||
}
|
||||
setZoomPercent(zoomPercent - 10);
|
||||
}
|
||||
};
|
||||
|
||||
//function to use remove widgets from current page when user want to rotate page
|
||||
export const handleRemoveWidgets = (
|
||||
setSignerPos,
|
||||
signerPos,
|
||||
pageNumber,
|
||||
setIsRotate
|
||||
) => {
|
||||
const updatedSignerPos = signerPos.map((placeholderObj) => {
|
||||
return {
|
||||
...placeholderObj,
|
||||
placeHolder: placeholderObj?.placeHolder?.filter(
|
||||
(data) => data?.pageNumber !== pageNumber
|
||||
)
|
||||
};
|
||||
});
|
||||
setSignerPos(updatedSignerPos);
|
||||
setIsRotate({
|
||||
status: false,
|
||||
degree: 0
|
||||
});
|
||||
};
|
||||
//function to show warning when user rotate page and there are some already widgets on that page
|
||||
export const handleRotateWarning = (signerPos, pageNumber) => {
|
||||
const placeholderExist = signerPos?.some((placeholderObj) =>
|
||||
placeholderObj?.placeHolder?.some((data) => data?.pageNumber === pageNumber)
|
||||
);
|
||||
if (placeholderExist) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -32,7 +32,9 @@ import {
|
||||
handleToPrint,
|
||||
handleDownloadCertificate,
|
||||
openInNewTab,
|
||||
getDefaultSignature
|
||||
getDefaultSignature,
|
||||
onClickZoomIn,
|
||||
onClickZoomOut
|
||||
} from "../constant/Utils";
|
||||
import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
||||
import HandleError from "../primitives/HandleError";
|
||||
@@ -122,7 +124,6 @@ function PdfRequestFiles(props) {
|
||||
const [otp, setOtp] = useState("");
|
||||
const [contractName, setContractName] = useState("");
|
||||
const [zoomPercent, setZoomPercent] = useState(0);
|
||||
const [totalZoomPercent, setTotalZoomPercent] = useState();
|
||||
const [scale, setScale] = useState(1);
|
||||
const [uniqueId, setUniqueId] = useState("");
|
||||
const [isPublicTemplate, setIsPublicTemplate] = useState(false);
|
||||
@@ -132,6 +133,7 @@ function PdfRequestFiles(props) {
|
||||
const [res, setRes] = useState({});
|
||||
const [documentId, setDocumentId] = useState("");
|
||||
const [isPublicContact, setIsPublicContact] = useState(false);
|
||||
const [pdfArrayBuffer, setPdfArrayBuffer] = useState("");
|
||||
const isHeader = useSelector((state) => state.showHeader);
|
||||
const divRef = useRef(null);
|
||||
|
||||
@@ -140,17 +142,18 @@ function PdfRequestFiles(props) {
|
||||
let isGuestSignFlow = false;
|
||||
let sendmail;
|
||||
let getDocId = "";
|
||||
const route = !props.templateId && window.location.pathname;
|
||||
const route = !props.templateId && window.location.pathname; //'/load/recipientSignPdf/TOAVuhXbfw/fPAKdK1qgX'
|
||||
//window.location.search = ?sendmail=false
|
||||
const getQuery =
|
||||
!props.templateId &&
|
||||
window.location?.search &&
|
||||
window.location?.search?.split("?");
|
||||
window.location?.search?.split("?"); //['','sendmail=false']
|
||||
|
||||
//'sendmail=false'
|
||||
if (getQuery) {
|
||||
sendmail = getQuery[1].split("=")[1];
|
||||
sendmail = getQuery[1].split("=")[1]; //false
|
||||
}
|
||||
const checkSplit = route && route?.split("/");
|
||||
|
||||
const checkSplit = route && route?.split("/"); // ['', 'load', 'recipientSignPdf', 'TOAVuhXbfw', 'fPAKdK1qgX']
|
||||
if (checkSplit && checkSplit.length > 4) {
|
||||
isGuestSignFlow = true;
|
||||
getDocId = checkSplit[3];
|
||||
@@ -298,6 +301,20 @@ function PdfRequestFiles(props) {
|
||||
: [];
|
||||
|
||||
if (documentData && documentData.length > 0) {
|
||||
const url =
|
||||
documentData[0] &&
|
||||
(documentData[0]?.SignedUrl || documentData[0]?.URL);
|
||||
if (url) {
|
||||
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
||||
const arrayBuffer = await convertPdfArrayBuffer(url);
|
||||
if (arrayBuffer === "Error") {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
} else {
|
||||
setPdfArrayBuffer(arrayBuffer);
|
||||
}
|
||||
} else {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
}
|
||||
setIsPublicTemplate(true);
|
||||
const getPublicRole = documentData[0]?.PublicRole[0];
|
||||
const getUniqueIdDetails = documentData[0]?.Placeholders.find(
|
||||
@@ -361,6 +378,20 @@ function PdfRequestFiles(props) {
|
||||
//getting document details
|
||||
const documentData = await contractDocument(documentId || docId);
|
||||
if (documentData && documentData.length > 0) {
|
||||
const url =
|
||||
documentData[0] &&
|
||||
(documentData[0]?.SignedUrl || documentData[0]?.URL);
|
||||
if (url) {
|
||||
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
||||
const arrayBuffer = await convertPdfArrayBuffer(url);
|
||||
if (arrayBuffer === "Error") {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
} else {
|
||||
setPdfArrayBuffer(arrayBuffer);
|
||||
}
|
||||
} else {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
}
|
||||
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
||||
const isCompleted =
|
||||
documentData[0].IsCompleted && documentData[0].IsCompleted;
|
||||
@@ -817,30 +848,9 @@ function PdfRequestFiles(props) {
|
||||
setIsUiLoading(true);
|
||||
// `widgets` is Used to return widgets details with page number of current user
|
||||
const widgets = checkUser?.[0]?.placeHolder;
|
||||
let pdfArrBuffer;
|
||||
//`contractDocument` function used to get updated SignedUrl
|
||||
//resolved issue of sign document by multiple signers simultaneously
|
||||
const documentData = await contractDocument(documentId);
|
||||
if (documentData && documentData.length > 0) {
|
||||
const url = documentData[0]?.SignedUrl || documentData[0]?.URL;
|
||||
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
||||
const arrayBuffer = await convertPdfArrayBuffer(url);
|
||||
if (arrayBuffer === "Error") {
|
||||
setHandleError(t("invalid-document"));
|
||||
} else {
|
||||
pdfArrBuffer = arrayBuffer;
|
||||
}
|
||||
} else if (
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(documentData.result && documentData.result.error)
|
||||
) {
|
||||
setHandleError(t("something-went-wrong-mssg"));
|
||||
} else {
|
||||
setHandleError(t("document-not-found"));
|
||||
}
|
||||
|
||||
// Load a PDFDocument from the existing PDF bytes
|
||||
const existingPdfBytes = pdfArrBuffer;
|
||||
const existingPdfBytes = pdfArrayBuffer;
|
||||
try {
|
||||
const pdfDoc = await PDFDocument.load(existingPdfBytes);
|
||||
const isSignYourSelfFlow = false;
|
||||
@@ -1316,7 +1326,6 @@ function PdfRequestFiles(props) {
|
||||
const handleDontShow = (isChecked) => {
|
||||
setIsDontShow(isChecked);
|
||||
};
|
||||
// console.log("signerpos", signerPos);
|
||||
//function to close tour and save tour status
|
||||
const closeRequestSignTour = async () => {
|
||||
setRequestSignTour(true);
|
||||
@@ -1591,6 +1600,12 @@ function PdfRequestFiles(props) {
|
||||
});
|
||||
};
|
||||
|
||||
const clickOnZoomIn = () => {
|
||||
onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent);
|
||||
};
|
||||
const clickOnZoomOut = () => {
|
||||
onClickZoomOut(zoomPercent, scale, setZoomPercent, setScale);
|
||||
};
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<Title title={props.templateId ? "Public Sign" : "Request Sign"} />
|
||||
@@ -1712,9 +1727,7 @@ function PdfRequestFiles(props) {
|
||||
<ModalUi
|
||||
isOpen={isPublicContact}
|
||||
title={isOtp ? t("verify-email-1") : t("contact-details")}
|
||||
handleClose={() => {
|
||||
handleCloseOtp();
|
||||
}}
|
||||
handleClose={() => handleCloseOtp()}
|
||||
>
|
||||
<div className="h-full p-[20px]">
|
||||
{isOtp ? (
|
||||
@@ -1742,9 +1755,7 @@ function PdfRequestFiles(props) {
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
className="op-btn op-btn-ghost"
|
||||
onClick={() => {
|
||||
handleCloseOtp();
|
||||
}}
|
||||
onClick={() => handleCloseOtp()}
|
||||
>
|
||||
{t("cancel")}
|
||||
</button>
|
||||
@@ -1834,9 +1845,7 @@ function PdfRequestFiles(props) {
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
className="op-btn op-btn-ghost"
|
||||
onClick={() => {
|
||||
handleCloseOtp();
|
||||
}}
|
||||
onClick={() => handleCloseOtp()}
|
||||
>
|
||||
{t("close")}
|
||||
</button>
|
||||
@@ -1914,20 +1923,18 @@ function PdfRequestFiles(props) {
|
||||
{/* pdf render view */}
|
||||
<div className=" w-full md:w-[57%] flex mr-4">
|
||||
<PdfZoom
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
setZoomPercent={setZoomPercent}
|
||||
zoomPercent={zoomPercent}
|
||||
clickOnZoomIn={clickOnZoomIn}
|
||||
clickOnZoomOut={clickOnZoomOut}
|
||||
isDisableRotate={true}
|
||||
/>
|
||||
<div className=" w-full md:w-[95%] ">
|
||||
{/* this modal is used show this document is already sign */}
|
||||
<ModalUi
|
||||
isOpen={isCompleted.isModal}
|
||||
title={t("document-signed")}
|
||||
handleClose={() => {
|
||||
setIsCompleted((prev) => ({ ...prev, isModal: false }));
|
||||
}}
|
||||
handleClose={() =>
|
||||
setIsCompleted((prev) => ({ ...prev, isModal: false }))
|
||||
}
|
||||
reduceWidth={
|
||||
!isCompleted?.message &&
|
||||
"md:min-w-[440px] md:max-w-[400px]"
|
||||
@@ -2059,15 +2066,11 @@ function PdfRequestFiles(props) {
|
||||
currentSigner={currentSigner}
|
||||
pdfUrl={pdfUrl}
|
||||
alreadySign={alreadySign}
|
||||
totalZoomPercent={totalZoomPercent}
|
||||
setTotalZoomPercent={setTotalZoomPercent}
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
containerWH={containerWH}
|
||||
setZoomPercent={setZoomPercent}
|
||||
zoomPercent={zoomPercent}
|
||||
isPublicTemplate={isPublicTemplate}
|
||||
clickOnZoomIn={clickOnZoomIn}
|
||||
clickOnZoomOut={clickOnZoomOut}
|
||||
isDisableRotate={true}
|
||||
/>
|
||||
|
||||
<div ref={divRef} data-tut="pdfArea" className="h-[95%]">
|
||||
@@ -2101,7 +2104,6 @@ function PdfRequestFiles(props) {
|
||||
divRef={divRef}
|
||||
setIsResize={setIsResize}
|
||||
isResize={isResize}
|
||||
setTotalZoomPercent={setTotalZoomPercent}
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
uniqueId={uniqueId}
|
||||
@@ -2181,9 +2183,7 @@ function PdfRequestFiles(props) {
|
||||
<ModalUi
|
||||
isOpen={validateAlert}
|
||||
title={t("validation-alert")}
|
||||
handleClose={() => {
|
||||
setValidateAlert(false);
|
||||
}}
|
||||
handleClose={() => setValidateAlert(false)}
|
||||
>
|
||||
<div className="h-[100%] p-[20px]">
|
||||
<p>{t("validation-alert-1")}</p>
|
||||
|
||||
@@ -35,7 +35,13 @@ import {
|
||||
fetchSubscription,
|
||||
convertPdfArrayBuffer,
|
||||
getContainerScale,
|
||||
openInNewTab
|
||||
openInNewTab,
|
||||
convertBase64ToFile,
|
||||
onClickZoomIn,
|
||||
onClickZoomOut,
|
||||
rotatePdfPage,
|
||||
handleRemoveWidgets,
|
||||
handleRotateWarning
|
||||
} from "../constant/Utils";
|
||||
import RenderPdf from "../components/pdf/RenderPdf";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
@@ -56,6 +62,7 @@ import PdfZoom from "../components/pdf/PdfZoom";
|
||||
import LottieWithLoader from "../primitives/DotLottieReact";
|
||||
import { paidUrl } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import RotateAlert from "../components/RotateAlert";
|
||||
|
||||
function PlaceHolderSign() {
|
||||
const { t } = useTranslation();
|
||||
@@ -133,6 +140,10 @@ function PlaceHolderSign() {
|
||||
const [pdfArrayBuffer, setPdfArrayBuffer] = useState("");
|
||||
const isHeader = useSelector((state) => state.showHeader);
|
||||
const [activeMailAdapter, setActiveMailAdapter] = useState("");
|
||||
const [isRotate, setIsRotate] = useState({
|
||||
status: false,
|
||||
degree: 0
|
||||
});
|
||||
const [isAlreadyPlace, setIsAlreadyPlace] = useState({
|
||||
status: false,
|
||||
message: ""
|
||||
@@ -141,6 +152,8 @@ function PlaceHolderSign() {
|
||||
const [isCustomize, setIsCustomize] = useState(false);
|
||||
const [zoomPercent, setZoomPercent] = useState(0);
|
||||
const [scale, setScale] = useState(1);
|
||||
|
||||
const [pdfRotateBase64, setPdfRotatese64] = useState("");
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const [, drop] = useDrop({
|
||||
accept: "BOX",
|
||||
@@ -837,11 +850,6 @@ function PlaceHolderSign() {
|
||||
const handleMouseLeave = () => {
|
||||
setSignBtnPosition([xySignature]);
|
||||
};
|
||||
|
||||
function sanitizeFileName(fileName) {
|
||||
// Remove spaces and invalid characters
|
||||
return fileName.replace(/[^a-zA-Z0-9._-]/g, "");
|
||||
}
|
||||
//embed prefill label widget data
|
||||
const embedPrefilllData = async () => {
|
||||
const prefillExist = signerPos.filter((data) => data.Role === "prefill");
|
||||
@@ -853,7 +861,7 @@ function PlaceHolderSign() {
|
||||
});
|
||||
const isSignYourSelfFlow = false;
|
||||
try {
|
||||
const pdfBytes = await multiSignEmbed(
|
||||
const pdfBase64 = await multiSignEmbed(
|
||||
placeholder,
|
||||
pdfDoc,
|
||||
isSignYourSelfFlow,
|
||||
@@ -861,19 +869,26 @@ function PlaceHolderSign() {
|
||||
pdfOriginalWH,
|
||||
containerWH
|
||||
);
|
||||
|
||||
const fileName = sanitizeFileName(pdfDetails[0].Name) + ".pdf";
|
||||
const pdfFile = new Parse.File(fileName, { base64: pdfBytes });
|
||||
|
||||
// Save the Parse File if needed
|
||||
const pdfData = await pdfFile.save();
|
||||
const pdfUrl = pdfData.url();
|
||||
const pdfUrl = await convertBase64ToFile(pdfDetails[0].Name, pdfBase64);
|
||||
const tenantId = localStorage.getItem("TenantId");
|
||||
const buffer = atob(pdfBytes);
|
||||
const buffer = atob(pdfBase64);
|
||||
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
||||
return pdfUrl;
|
||||
} catch (e) {
|
||||
console.log("error", e);
|
||||
console.log("error to convertBase64ToFile in placeholder flow", e);
|
||||
}
|
||||
} else if (pdfRotateBase64) {
|
||||
try {
|
||||
const pdfUrl = await convertBase64ToFile(
|
||||
pdfDetails[0].Name,
|
||||
pdfRotateBase64
|
||||
);
|
||||
const tenantId = localStorage.getItem("TenantId");
|
||||
const buffer = atob(pdfRotateBase64);
|
||||
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
||||
return pdfUrl;
|
||||
} catch (e) {
|
||||
console.log("error to convertBase64ToFile in placeholder flow", e);
|
||||
}
|
||||
} else {
|
||||
return pdfDetails[0].URL;
|
||||
@@ -1710,6 +1725,39 @@ function PlaceHolderSign() {
|
||||
});
|
||||
}
|
||||
};
|
||||
const clickOnZoomIn = () => {
|
||||
onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent);
|
||||
};
|
||||
const clickOnZoomOut = () => {
|
||||
onClickZoomOut(zoomPercent, scale, setZoomPercent, setScale);
|
||||
};
|
||||
//`handleRotationFun` function is used to roatate pdf particular page
|
||||
const handleRotationFun = async (rotateDegree) => {
|
||||
const isRotate = handleRotateWarning(signerPos, pageNumber);
|
||||
if (isRotate) {
|
||||
setIsRotate({ status: true, degree: rotateDegree });
|
||||
} else {
|
||||
const urlDetails = await rotatePdfPage(
|
||||
pdfDetails[0].URL,
|
||||
rotateDegree,
|
||||
pageNumber - 1,
|
||||
pdfRotateBase64
|
||||
);
|
||||
setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer);
|
||||
setPdfRotatese64(urlDetails.base64);
|
||||
}
|
||||
};
|
||||
const handleRemovePlaceholder = async () => {
|
||||
handleRemoveWidgets(setSignerPos, signerPos, pageNumber, setIsRotate);
|
||||
const urlDetails = await rotatePdfPage(
|
||||
pdfDetails[0].URL,
|
||||
isRotate.degree,
|
||||
pageNumber - 1,
|
||||
pdfRotateBase64
|
||||
);
|
||||
setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer);
|
||||
setPdfRotatese64(urlDetails.base64);
|
||||
};
|
||||
return (
|
||||
<>
|
||||
<Title title={state?.title ? state.title : "New Document"} />
|
||||
@@ -1758,15 +1806,14 @@ function PlaceHolderSign() {
|
||||
setPageNumber={setPageNumber}
|
||||
setSignBtnPosition={setSignBtnPosition}
|
||||
pageNumber={pageNumber}
|
||||
pdfRotateBase64={pdfRotateBase64}
|
||||
/>
|
||||
{/* pdf render view */}
|
||||
<div className=" w-full md:w-[57%] flex mr-4">
|
||||
<PdfZoom
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
setZoomPercent={setZoomPercent}
|
||||
zoomPercent={zoomPercent}
|
||||
clickOnZoomIn={clickOnZoomIn}
|
||||
clickOnZoomOut={clickOnZoomOut}
|
||||
handleRotationFun={handleRotationFun}
|
||||
/>
|
||||
<div className=" w-full md:w-[95%] ">
|
||||
{/* this modal is used show alert set placeholder for all signers before send mail */}
|
||||
@@ -1894,9 +1941,7 @@ function PlaceHolderSign() {
|
||||
>
|
||||
{isCurrUser && (
|
||||
<button
|
||||
onClick={() => {
|
||||
handleRecipientSign();
|
||||
}}
|
||||
onClick={() => handleRecipientSign()}
|
||||
type="button"
|
||||
className="op-btn op-btn-primary mr-1"
|
||||
>
|
||||
@@ -1921,17 +1966,13 @@ function PlaceHolderSign() {
|
||||
<ModalUi
|
||||
isOpen={isShowEmail}
|
||||
title={t("signers-alert")}
|
||||
handleClose={() => {
|
||||
setIsShowEmail(false);
|
||||
}}
|
||||
handleClose={() => setIsShowEmail(false)}
|
||||
>
|
||||
<div className="h-[100%] p-[20px]">
|
||||
<p>{t("placeholder-alert-7")}</p>
|
||||
<div className="w-full h-[1px] bg-[#9f9f9f] my-[15px]"></div>
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsShowEmail(false);
|
||||
}}
|
||||
onClick={() => setIsShowEmail(false)}
|
||||
type="button"
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
@@ -2012,9 +2053,16 @@ function PlaceHolderSign() {
|
||||
alertSendEmail={alertSendEmail}
|
||||
isShowHeader={true}
|
||||
currentSigner={true}
|
||||
handleRotationFun={handleRotationFun}
|
||||
clickOnZoomIn={clickOnZoomIn}
|
||||
clickOnZoomOut={clickOnZoomOut}
|
||||
/>
|
||||
|
||||
<div ref={divRef} data-tut="pdfArea" className="h-[95%]">
|
||||
<div
|
||||
ref={divRef}
|
||||
data-tut="pdfArea"
|
||||
className="h-full md:h-[95%]"
|
||||
>
|
||||
{containerWH && (
|
||||
<RenderPdf
|
||||
pageNumber={pageNumber}
|
||||
@@ -2056,6 +2104,7 @@ function PlaceHolderSign() {
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
setIsSelectId={setIsSelectId}
|
||||
pdfRotateBase64={pdfRotateBase64}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
@@ -2202,6 +2251,11 @@ function PlaceHolderSign() {
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
/>
|
||||
<RotateAlert
|
||||
isRotate={isRotate.status}
|
||||
setIsRotate={setIsRotate}
|
||||
handleRemoveWidgets={handleRemovePlaceholder}
|
||||
/>
|
||||
</DndProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -34,7 +34,10 @@ import {
|
||||
changeImageWH,
|
||||
handleSendOTP,
|
||||
getContainerScale,
|
||||
getDefaultSignature
|
||||
getDefaultSignature,
|
||||
onClickZoomIn,
|
||||
onClickZoomOut,
|
||||
rotatePdfPage
|
||||
} from "../constant/Utils";
|
||||
import { useParams } from "react-router-dom";
|
||||
import Tour from "reactour";
|
||||
@@ -53,6 +56,7 @@ import VerifyEmail from "../components/pdf/VerifyEmail";
|
||||
import PdfZoom from "../components/pdf/PdfZoom";
|
||||
import Loader from "../primitives/Loader";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import RotateAlert from "../components/RotateAlert";
|
||||
//For signYourself inProgress section signer can add sign and complete doc sign.
|
||||
function SignYourSelf() {
|
||||
const { t } = useTranslation();
|
||||
@@ -123,6 +127,11 @@ function SignYourSelf() {
|
||||
const [zoomPercent, setZoomPercent] = useState(0);
|
||||
const isHeader = useSelector((state) => state.showHeader);
|
||||
const [scale, setScale] = useState(1);
|
||||
const [pdfRotateBase64, setPdfRotatese64] = useState("");
|
||||
const [isRotate, setIsRotate] = useState({
|
||||
status: false,
|
||||
degree: 0
|
||||
});
|
||||
const divRef = useRef(null);
|
||||
const nodeRef = useRef(null);
|
||||
const [, drop] = useDrop({
|
||||
@@ -206,6 +215,7 @@ function SignYourSelf() {
|
||||
return () => clearTimeout(timer);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [divRef.current, isHeader]);
|
||||
|
||||
//function for get document details for perticular signer with signer'object id
|
||||
const getDocumentDetails = async (showComplete) => {
|
||||
try {
|
||||
@@ -794,6 +804,7 @@ function SignYourSelf() {
|
||||
const signedpdf = JSON.parse(JSON.stringify(resSignPdf));
|
||||
setPdfUrl(signedpdf);
|
||||
getDocumentDetails(false);
|
||||
setPdfRotatese64("");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1160,6 +1171,56 @@ function SignYourSelf() {
|
||||
handleTextSettingModal(false);
|
||||
}
|
||||
};
|
||||
const clickOnZoomIn = () => {
|
||||
onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent);
|
||||
};
|
||||
const clickOnZoomOut = () => {
|
||||
onClickZoomOut(zoomPercent, scale, setZoomPercent, setScale);
|
||||
};
|
||||
//`handleRotationFun` function is used to roatate pdf particular page
|
||||
const handleRotationFun = async (rotateDegree) => {
|
||||
const isPlaceholder = handleRotateWarning();
|
||||
if (isPlaceholder) {
|
||||
setIsRotate({ status: true, degree: rotateDegree });
|
||||
} else {
|
||||
const urlDetails = await rotatePdfPage(
|
||||
pdfUrl || pdfDetails[0].URL,
|
||||
rotateDegree,
|
||||
pageNumber - 1,
|
||||
pdfRotateBase64
|
||||
);
|
||||
setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer);
|
||||
setPdfRotatese64(urlDetails.base64);
|
||||
}
|
||||
};
|
||||
|
||||
//function to show warning when user rotate page and there are some already widgets on that page
|
||||
const handleRotateWarning = () => {
|
||||
const placeholderData = xyPostion?.filter(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
if (placeholderData && placeholderData.length > 0) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
//function to use remove widgets from current page when user want to rotate page
|
||||
const handleRemoveWidgets = async () => {
|
||||
const updatePlaceholder = xyPostion.filter(
|
||||
(data) => data.pageNumber !== pageNumber
|
||||
);
|
||||
const urlDetails = await rotatePdfPage(
|
||||
pdfUrl || pdfDetails[0].URL,
|
||||
isRotate.degree,
|
||||
pageNumber - 1,
|
||||
pdfRotateBase64
|
||||
);
|
||||
setPdfArrayBuffer && setPdfArrayBuffer(urlDetails.arrayBuffer);
|
||||
setPdfRotatese64(urlDetails.base64);
|
||||
setXyPostion(updatePlaceholder);
|
||||
setIsRotate({ status: false, degree: 0 });
|
||||
};
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<Title title={"Self Sign"} />
|
||||
@@ -1219,14 +1280,13 @@ function SignYourSelf() {
|
||||
setSignBtnPosition={setSignBtnPosition}
|
||||
pageNumber={pageNumber}
|
||||
containerWH={containerWH}
|
||||
pdfRotateBase64={pdfRotateBase64}
|
||||
/>
|
||||
<div className=" w-full md:w-[57%] flex mr-4">
|
||||
<PdfZoom
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
setZoomPercent={setZoomPercent}
|
||||
zoomPercent={zoomPercent}
|
||||
clickOnZoomIn={clickOnZoomIn}
|
||||
clickOnZoomOut={clickOnZoomOut}
|
||||
handleRotationFun={handleRotationFun}
|
||||
/>
|
||||
<div className="w-full md:w-[95%]">
|
||||
<ModalUi
|
||||
@@ -1245,9 +1305,7 @@ function SignYourSelf() {
|
||||
<ModalUi
|
||||
isOpen={showAlreadySignDoc.status}
|
||||
title={t("document-signed")}
|
||||
handleClose={() => {
|
||||
setShowAlreadySignDoc({ status: false });
|
||||
}}
|
||||
handleClose={() => setShowAlreadySignDoc({ status: false })}
|
||||
>
|
||||
<div className="p-[20px] h-full">
|
||||
<p>{showAlreadySignDoc.mssg}</p>
|
||||
@@ -1284,6 +1342,7 @@ function SignYourSelf() {
|
||||
allPages={allPages}
|
||||
pageNumber={pageNumber}
|
||||
signKey={signKey}
|
||||
widgetType={widgetType}
|
||||
/>
|
||||
{/* this is modal of signature pad */}
|
||||
<SignPad
|
||||
@@ -1334,12 +1393,12 @@ function SignYourSelf() {
|
||||
isSignYourself={true}
|
||||
setIsEmail={setIsEmail}
|
||||
isCompleted={isCompleted}
|
||||
handleRotationFun={handleRotationFun}
|
||||
clickOnZoomIn={clickOnZoomIn}
|
||||
clickOnZoomOut={clickOnZoomOut}
|
||||
widgetsDetails={xyPostion}
|
||||
/>
|
||||
<div
|
||||
ref={divRef}
|
||||
data-tut="reactourSecond"
|
||||
className="h-full md:h-[95%]"
|
||||
>
|
||||
<div ref={divRef} data-tut="reactourSecond" className="h-full">
|
||||
{containerWH?.width && containerWH?.height && (
|
||||
<RenderPdf
|
||||
pageNumber={pageNumber}
|
||||
@@ -1378,6 +1437,7 @@ function SignYourSelf() {
|
||||
handleTextSettingModal={handleTextSettingModal}
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
pdfRotateBase64={pdfRotateBase64}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
@@ -1421,9 +1481,7 @@ function SignYourSelf() {
|
||||
<ModalUi
|
||||
isOpen={validateAlert}
|
||||
title={t("validation-alert")}
|
||||
handleClose={() => {
|
||||
setValidateAlert(false);
|
||||
}}
|
||||
handleClose={() => setValidateAlert(false)}
|
||||
>
|
||||
<div className="p-[20px] h-full">
|
||||
<p>{t("validate-alert-mssg")}</p>
|
||||
@@ -1438,6 +1496,11 @@ function SignYourSelf() {
|
||||
</button>
|
||||
</div>
|
||||
</ModalUi>
|
||||
<RotateAlert
|
||||
isRotate={isRotate.status}
|
||||
setIsRotate={setIsRotate}
|
||||
handleRemoveWidgets={handleRemoveWidgets}
|
||||
/>
|
||||
<TextFontSetting
|
||||
isTextSetting={isTextSetting}
|
||||
setIsTextSetting={setIsTextSetting}
|
||||
|
||||
@@ -26,7 +26,13 @@ import {
|
||||
radioButtonWidget,
|
||||
fetchSubscription,
|
||||
getContainerScale,
|
||||
openInNewTab
|
||||
openInNewTab,
|
||||
convertBase64ToFile,
|
||||
rotatePdfPage,
|
||||
onClickZoomOut,
|
||||
onClickZoomIn,
|
||||
handleRemoveWidgets,
|
||||
handleRotateWarning
|
||||
} from "../constant/Utils";
|
||||
import RenderPdf from "../components/pdf/RenderPdf";
|
||||
import "../styles/AddUser.css";
|
||||
@@ -43,6 +49,7 @@ import { useSelector } from "react-redux";
|
||||
import PdfZoom from "../components/pdf/PdfZoom";
|
||||
import { paidUrl } from "../json/plansArr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import RotateAlert from "../components/RotateAlert";
|
||||
const TemplatePlaceholder = () => {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
@@ -63,6 +70,10 @@ const TemplatePlaceholder = () => {
|
||||
const [isSendAlert, setIsSendAlert] = useState(false);
|
||||
const [isCreateDocModal, setIsCreateDocModal] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
const [isRotate, setIsRotate] = useState({
|
||||
status: false,
|
||||
degree: 0
|
||||
});
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoad: true,
|
||||
message: t("loading-mssg")
|
||||
@@ -93,6 +104,7 @@ const TemplatePlaceholder = () => {
|
||||
const [isNameModal, setIsNameModal] = useState(false);
|
||||
const [isTextSetting, setIsTextSetting] = useState(false);
|
||||
const [pdfLoad, setPdfLoad] = useState(false);
|
||||
const [pdfRotateBase64, setPdfRotatese64] = useState("");
|
||||
const color = [
|
||||
"#93a3db",
|
||||
"#e6c3db",
|
||||
@@ -731,6 +743,7 @@ const TemplatePlaceholder = () => {
|
||||
handleSaveTemplate();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveTemplate = async () => {
|
||||
if (signersdata?.length) {
|
||||
const loadObj = {
|
||||
@@ -752,6 +765,17 @@ const TemplatePlaceholder = () => {
|
||||
}
|
||||
});
|
||||
}
|
||||
let pdfUrl = pdfDetails[0]?.URL;
|
||||
if (pdfRotateBase64) {
|
||||
try {
|
||||
pdfUrl = await convertBase64ToFile(
|
||||
pdfDetails[0].Name,
|
||||
pdfRotateBase64
|
||||
);
|
||||
} catch (e) {
|
||||
console.log("error to convertBase64ToFile in placeholder flow", e);
|
||||
}
|
||||
}
|
||||
try {
|
||||
const data = {
|
||||
Placeholders: signerPos,
|
||||
@@ -762,7 +786,8 @@ const TemplatePlaceholder = () => {
|
||||
SendinOrder: pdfDetails[0]?.SendinOrder || false,
|
||||
AutomaticReminders: pdfDetails[0]?.AutomaticReminders,
|
||||
RemindOnceInEvery: parseInt(pdfDetails[0]?.RemindOnceInEvery),
|
||||
NextReminderDate: pdfDetails[0]?.NextReminderDate
|
||||
NextReminderDate: pdfDetails[0]?.NextReminderDate,
|
||||
URL: pdfUrl
|
||||
};
|
||||
const updateTemplate = new Parse.Object("contracts_Template");
|
||||
updateTemplate.id = templateId;
|
||||
@@ -902,8 +927,21 @@ const TemplatePlaceholder = () => {
|
||||
const handleCreateDocModal = async () => {
|
||||
setIsCreateDocModal(false);
|
||||
setIsCreateDoc(true);
|
||||
let pdfUrl = pdfDetails[0]?.URL;
|
||||
if (pdfRotateBase64) {
|
||||
try {
|
||||
pdfUrl = await convertBase64ToFile(pdfDetails[0].Name, pdfRotateBase64);
|
||||
} catch (e) {
|
||||
console.log("error to convertBase64ToFile in placeholder flow", e);
|
||||
}
|
||||
}
|
||||
// handle create document
|
||||
const res = await createDocument(pdfDetails, signerPos, signersdata);
|
||||
const res = await createDocument(
|
||||
pdfDetails,
|
||||
signerPos,
|
||||
signersdata,
|
||||
pdfUrl
|
||||
);
|
||||
if (res.status === "success") {
|
||||
navigate(`/placeHolderSign/${res.id}`, {
|
||||
state: { title: "Use Template" }
|
||||
@@ -1289,6 +1327,38 @@ const TemplatePlaceholder = () => {
|
||||
setIsCheckbox(false);
|
||||
};
|
||||
|
||||
const clickOnZoomIn = () => {
|
||||
onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent);
|
||||
};
|
||||
const clickOnZoomOut = () => {
|
||||
onClickZoomOut(zoomPercent, scale, setZoomPercent, setScale);
|
||||
};
|
||||
//`handleRotationFun` function is used to roatate pdf particular page
|
||||
const handleRotationFun = async (rotateDegree) => {
|
||||
const isRotate = handleRotateWarning(signerPos, pageNumber);
|
||||
if (isRotate) {
|
||||
setIsRotate({ status: true, degree: rotateDegree });
|
||||
} else {
|
||||
const urlDetails = await rotatePdfPage(
|
||||
pdfDetails[0].URL,
|
||||
rotateDegree,
|
||||
pageNumber - 1,
|
||||
pdfRotateBase64
|
||||
);
|
||||
setPdfRotatese64(urlDetails.base64);
|
||||
}
|
||||
};
|
||||
const handleRemovePlaceholder = async () => {
|
||||
handleRemoveWidgets(setSignerPos, signerPos, pageNumber, setIsRotate);
|
||||
const urlDetails = await rotatePdfPage(
|
||||
pdfDetails[0].URL,
|
||||
isRotate.degree,
|
||||
pageNumber - 1,
|
||||
pdfRotateBase64
|
||||
);
|
||||
setPdfRotatese64(urlDetails.base64);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title title={"Template"} />
|
||||
@@ -1336,11 +1406,9 @@ const TemplatePlaceholder = () => {
|
||||
{/* pdf render view */}
|
||||
<div className=" w-full md:w-[57%] flex mr-4">
|
||||
<PdfZoom
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
containerWH={containerWH}
|
||||
setZoomPercent={setZoomPercent}
|
||||
zoomPercent={zoomPercent}
|
||||
clickOnZoomIn={clickOnZoomIn}
|
||||
clickOnZoomOut={clickOnZoomOut}
|
||||
handleRotationFun={handleRotationFun}
|
||||
/>
|
||||
<div className="w-full md:w-[95%]">
|
||||
{/* this modal is used show alert set placeholder for all signers before send mail */}
|
||||
@@ -1483,6 +1551,9 @@ const TemplatePlaceholder = () => {
|
||||
currentSigner={true}
|
||||
setIsEditTemplate={handleEditTemplateModal}
|
||||
dataTut4="reactourFour"
|
||||
handleRotationFun={handleRotationFun}
|
||||
clickOnZoomIn={clickOnZoomIn}
|
||||
clickOnZoomOut={clickOnZoomOut}
|
||||
/>
|
||||
<div
|
||||
ref={divRef}
|
||||
@@ -1528,6 +1599,7 @@ const TemplatePlaceholder = () => {
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
setIsSelectId={setIsSelectId}
|
||||
pdfRotateBase64={pdfRotateBase64}
|
||||
fontSize={fontSize}
|
||||
setFontSize={setFontSize}
|
||||
fontColor={fontColor}
|
||||
@@ -1671,6 +1743,11 @@ const TemplatePlaceholder = () => {
|
||||
fontColor={fontColor}
|
||||
setFontColor={setFontColor}
|
||||
/>
|
||||
<RotateAlert
|
||||
isRotate={isRotate.status}
|
||||
setIsRotate={setIsRotate}
|
||||
handleRemoveWidgets={handleRemovePlaceholder}
|
||||
/>
|
||||
</DndProvider>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -46,109 +46,125 @@ const AddContact = (props) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsLoader(true);
|
||||
try {
|
||||
const contactQuery = new Parse.Object("contracts_Contactbook");
|
||||
contactQuery.set("Name", name);
|
||||
if (phone) {
|
||||
contactQuery.set("Phone", phone);
|
||||
}
|
||||
contactQuery.set("Email", email);
|
||||
contactQuery.set("UserRole", "contracts_Guest");
|
||||
|
||||
if (localStorage.getItem("TenantId")) {
|
||||
contactQuery.set("TenantId", {
|
||||
__type: "Pointer",
|
||||
className: "partners_Tenant",
|
||||
objectId: localStorage.getItem("TenantId")
|
||||
});
|
||||
}
|
||||
|
||||
if (localStorage.getItem("TenantId")) {
|
||||
try {
|
||||
const _users = Parse.Object.extend("User");
|
||||
const _user = new _users();
|
||||
_user.set("name", name);
|
||||
_user.set("username", email);
|
||||
_user.set("email", email);
|
||||
_user.set("password", email);
|
||||
if (phone) {
|
||||
_user.set("phone", phone);
|
||||
}
|
||||
const user = Parse.User.current();
|
||||
const query = new Parse.Query("contracts_Contactbook");
|
||||
query.equalTo("CreatedBy", user);
|
||||
query.notEqualTo("IsDeleted", true);
|
||||
query.equalTo("Email", email);
|
||||
const res = await query.first();
|
||||
if (!res) {
|
||||
const contactQuery = new Parse.Object("contracts_Contactbook");
|
||||
contactQuery.set("Name", name);
|
||||
if (phone) {
|
||||
contactQuery.set("Phone", phone);
|
||||
}
|
||||
contactQuery.set("Email", email);
|
||||
contactQuery.set("UserRole", "contracts_Guest");
|
||||
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
"CreatedBy",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.set("UserId", user);
|
||||
const acl = new Parse.ACL();
|
||||
acl.setPublicReadAccess(true);
|
||||
acl.setPublicWriteAccess(true);
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
|
||||
contactQuery.setACL(acl);
|
||||
|
||||
const res = await contactQuery.save();
|
||||
|
||||
const parseData = JSON.parse(JSON.stringify(res));
|
||||
props.details(parseData);
|
||||
if (props.closePopup) {
|
||||
props.closePopup();
|
||||
if (localStorage.getItem("TenantId")) {
|
||||
contactQuery.set("TenantId", {
|
||||
__type: "Pointer",
|
||||
className: "partners_Tenant",
|
||||
objectId: localStorage.getItem("TenantId")
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const _users = Parse.Object.extend("User");
|
||||
const _user = new _users();
|
||||
_user.set("name", name);
|
||||
_user.set("username", email);
|
||||
_user.set("email", email);
|
||||
_user.set("password", email);
|
||||
if (phone) {
|
||||
_user.set("phone", phone);
|
||||
}
|
||||
|
||||
const user = await _user.save();
|
||||
if (user) {
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
"CreatedBy",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.set("UserId", user);
|
||||
const acl = new Parse.ACL();
|
||||
acl.setPublicReadAccess(true);
|
||||
acl.setPublicWriteAccess(true);
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
|
||||
contactQuery.setACL(acl);
|
||||
|
||||
const res = await contactQuery.save();
|
||||
|
||||
const parseData = JSON.parse(JSON.stringify(res));
|
||||
props.details(parseData);
|
||||
if (props.closePopup) {
|
||||
props.closePopup();
|
||||
}
|
||||
|
||||
setIsLoader(false);
|
||||
// Reset the form fields
|
||||
setAddYourself(false);
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err ", err);
|
||||
if (err.code === 202) {
|
||||
const params = { email: email };
|
||||
const userRes = await Parse.Cloud.run("getUserId", params);
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
"CreatedBy",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.set("UserId", {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: userRes.id
|
||||
});
|
||||
const acl = new Parse.ACL();
|
||||
acl.setPublicReadAccess(true);
|
||||
acl.setPublicWriteAccess(true);
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
|
||||
contactQuery.setACL(acl);
|
||||
const res = await contactQuery.save();
|
||||
|
||||
const parseData = JSON.parse(JSON.stringify(res));
|
||||
if (props.details) {
|
||||
props.details(parseData);
|
||||
}
|
||||
|
||||
if (props.closePopup) {
|
||||
props.closePopup();
|
||||
}
|
||||
setIsLoader(false);
|
||||
// Reset the form fields
|
||||
setAddYourself(false);
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
alert(t("add-signer-alert"));
|
||||
setIsLoader(false);
|
||||
// Reset the form fields
|
||||
setAddYourself(false);
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err ", err);
|
||||
if (err.code === 202) {
|
||||
const params = { email: email };
|
||||
const userRes = await Parse.Cloud.run("getUserId", params);
|
||||
const currentUser = Parse.User.current();
|
||||
contactQuery.set(
|
||||
"CreatedBy",
|
||||
Parse.User.createWithoutData(currentUser.id)
|
||||
);
|
||||
|
||||
contactQuery.set("UserId", {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: userRes.id
|
||||
});
|
||||
const acl = new Parse.ACL();
|
||||
acl.setPublicReadAccess(true);
|
||||
acl.setPublicWriteAccess(true);
|
||||
acl.setReadAccess(currentUser.id, true);
|
||||
acl.setWriteAccess(currentUser.id, true);
|
||||
|
||||
contactQuery.setACL(acl);
|
||||
const res = await contactQuery.save();
|
||||
|
||||
const parseData = JSON.parse(JSON.stringify(res));
|
||||
if (props.details) {
|
||||
props.details(parseData);
|
||||
}
|
||||
|
||||
if (props.closePopup) {
|
||||
props.closePopup();
|
||||
}
|
||||
setIsLoader(false);
|
||||
// Reset the form fields
|
||||
setAddYourself(false);
|
||||
setName("");
|
||||
setPhone("");
|
||||
setEmail("");
|
||||
}
|
||||
// console.log("err", err);
|
||||
setIsLoader(false);
|
||||
alert(t("something-went-wrong-mssg"));
|
||||
}
|
||||
} catch (err) {
|
||||
// console.log("err", err);
|
||||
} else {
|
||||
setIsLoader(false);
|
||||
alert(t("something-went-wrong-mssg"));
|
||||
}
|
||||
|
||||
@@ -1306,9 +1306,7 @@ const ReportTable = (props) => {
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={t("public-url")}
|
||||
handleClose={() => {
|
||||
setIsPublicProfile({});
|
||||
}}
|
||||
handleClose={() => setIsPublicProfile({})}
|
||||
>
|
||||
<div className="m-[20px]">
|
||||
{publicUserName ? (
|
||||
|
||||
@@ -604,5 +604,8 @@
|
||||
"Add-seats": "Add Seats",
|
||||
"user-name-exist": "user name already exist",
|
||||
"format": "format",
|
||||
"select-date-format": "Select a date format"
|
||||
"select-date-format": "Select a date format",
|
||||
"rotate-right": "Rotate right",
|
||||
"rotate-left": "Rotate left",
|
||||
"rotate-alert-mssg": "All widgets on this page will be lost. Are you sure you want to proceed?"
|
||||
}
|
||||
|
||||
@@ -603,5 +603,8 @@
|
||||
"Select": "sélectionner",
|
||||
"Add-seats": "Ajouter des sièges",
|
||||
"format": "format",
|
||||
"select-date-format": "Sélectionnez un format de date"
|
||||
"select-date-format": "Sélectionnez un format de date",
|
||||
"rotate-right": "Faire pivoter à droite",
|
||||
"rotate-left": "Faire pivoter à gauche",
|
||||
"rotate-alert-mssg" :"Tous les widgets de cette page seront perdus. Êtes-vous sûr de vouloir continuer ?"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user