mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-20 14:42:37 +02:00
Merge branch 'signPdf' of https://github.com/OpenSignLabs/OpenSign into signPdf
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
import React from "react";
|
||||
import { rejectBtn, submitBtn, themeColor } from "../../constant/const";
|
||||
|
||||
function VerifyEmail(props) {
|
||||
return (
|
||||
<div className="bg-black bg-opacity-[75%] absolute z-[999] flex flex-col items-center justify-center w-full h-full rounded">
|
||||
<div className="bg-white rounded outline-none md:w-[40%] w-[80%]">
|
||||
<div
|
||||
style={{ backgroundColor: themeColor }}
|
||||
className=" text-white p-[10px] rounded-t"
|
||||
>
|
||||
OTP verification
|
||||
</div>
|
||||
{props.isVerifyModal ? (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
props.setIsVerifyModal(false);
|
||||
props.handleVerifyEmail(e);
|
||||
}}
|
||||
>
|
||||
<div className="px-6 py-3">
|
||||
<label className="mb-2">Enter OTP</label>
|
||||
<input
|
||||
required
|
||||
type="tel"
|
||||
pattern="[0-9]{4}"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
placeholder="Enter OTP sent on mail"
|
||||
value={props.otp}
|
||||
onChange={(e) => props.setOtp(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<hr />
|
||||
<div className="px-6 my-3">
|
||||
<button type="submit" className={submitBtn}>
|
||||
Verify
|
||||
</button>
|
||||
<button
|
||||
className={`${rejectBtn} ml-2`}
|
||||
onClick={(e) => props.handleResend(e)}
|
||||
>
|
||||
Resend
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
) : props.otpLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "150px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
fontSize: "45px",
|
||||
color: "#3dd3e0"
|
||||
}}
|
||||
className="loader-37"
|
||||
></div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="p-[15px]">
|
||||
<p>Please verify your email !</p>
|
||||
<div className="h-[1px] bg-[#9f9f9f] w-full"></div>
|
||||
<div className="m-[15px] ">
|
||||
<button
|
||||
className={submitBtn}
|
||||
type="submit"
|
||||
onClick={() => {
|
||||
props.handleVerifyBtn();
|
||||
}}
|
||||
>
|
||||
Verify
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default VerifyEmail;
|
||||
@@ -2008,3 +2008,18 @@ 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 {
|
||||
let url = `${localStorage.getItem("baseUrl")}functions/SendOTPMailV1`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||
};
|
||||
const body = { email: email };
|
||||
await axios.post(url, body, { headers: headers });
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useState, useRef, useEffect } from "react";
|
||||
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import "../styles/signature.css";
|
||||
import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import loader from "../assets/images/loader2.gif";
|
||||
import { DndProvider } from "react-dnd";
|
||||
@@ -25,7 +26,8 @@ import {
|
||||
replaceMailVaribles,
|
||||
fetchSubscription,
|
||||
convertPdfArrayBuffer,
|
||||
contractUsers
|
||||
contractUsers,
|
||||
handleSendOTP
|
||||
} from "../constant/Utils";
|
||||
import Loader from "../primitives/LoaderWithMsg";
|
||||
import HandleError from "../primitives/HandleError";
|
||||
@@ -35,6 +37,7 @@ 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";
|
||||
|
||||
function PdfRequestFiles() {
|
||||
const { docId } = useParams();
|
||||
@@ -57,10 +60,12 @@ function PdfRequestFiles() {
|
||||
const imageRef = useRef(null);
|
||||
const [handleError, setHandleError] = useState();
|
||||
const [selectWidgetId, setSelectWidgetId] = useState("");
|
||||
const [otpLoader, setOtpLoader] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
});
|
||||
|
||||
const [defaultSignImg, setDefaultSignImg] = useState();
|
||||
const [isDocId, setIsDocId] = useState(false);
|
||||
const [pdfNewWidth, setPdfNewWidth] = useState();
|
||||
@@ -100,6 +105,9 @@ function PdfRequestFiles() {
|
||||
const [isSubscriptionExpired, setIsSubscriptionExpired] = useState(false);
|
||||
const [extUserId, setExtUserId] = useState("");
|
||||
const [pdfArrayBuffer, setPdfArrayBuffer] = useState("");
|
||||
const [isEmailVerified, setIsEmailVerified] = useState(true);
|
||||
const [isVerifyModal, setIsVerifyModal] = useState(false);
|
||||
const [otp, setOtp] = useState("");
|
||||
const divRef = useRef(null);
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const rowLevel =
|
||||
@@ -139,6 +147,44 @@ function PdfRequestFiles() {
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [divRef.current]);
|
||||
|
||||
//function to use resend otp for email verification
|
||||
const handleResend = async (e) => {
|
||||
e.preventDefault();
|
||||
setOtpLoader(true);
|
||||
await handleSendOTP(Parse.User.current().getEmail());
|
||||
setOtpLoader(false);
|
||||
alert("OTP sent on you email");
|
||||
};
|
||||
//`handleVerifyEmail` function is used to verify email with otp
|
||||
const handleVerifyEmail = async (e) => {
|
||||
e.preventDefault();
|
||||
setOtpLoader(true);
|
||||
try {
|
||||
const resEmail = await Parse.Cloud.run("verifyemail", {
|
||||
otp: otp,
|
||||
email: Parse.User.current().getEmail()
|
||||
});
|
||||
if (resEmail?.message === "Email is verified.") {
|
||||
setIsEmailVerified(true);
|
||||
} else if (resEmail?.message === "Email is already verified.") {
|
||||
setIsEmailVerified(true);
|
||||
}
|
||||
setOtp("");
|
||||
alert(resEmail.message);
|
||||
setIsVerifyModal(false);
|
||||
// handleRecipientSign();
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
} finally {
|
||||
setOtpLoader(false);
|
||||
}
|
||||
};
|
||||
|
||||
//`handleVerifyBtn` function is used to send otp on user mail
|
||||
const handleVerifyBtn = async () => {
|
||||
setIsVerifyModal(true);
|
||||
await handleSendOTP(Parse.User.current().getEmail());
|
||||
};
|
||||
async function checkIsSubscribed(extUserId, contactId) {
|
||||
const isGuestSign = location.pathname.includes("/load/") || false;
|
||||
const res = await fetchSubscription(extUserId, contactId, isGuestSign);
|
||||
@@ -238,6 +284,33 @@ function PdfRequestFiles() {
|
||||
setExpiredDate(expireDateFormat);
|
||||
}
|
||||
|
||||
const isGuestSign = location.pathname.includes("/load/");
|
||||
if (
|
||||
!isGuestSign &&
|
||||
!isCompleted &&
|
||||
!declined &&
|
||||
currDate < expireUpdateDate
|
||||
) {
|
||||
const currentUser = JSON.parse(JSON.stringify(Parse.User.current()));
|
||||
let isEmailVerified;
|
||||
isEmailVerified = currentUser?.emailVerified;
|
||||
if (isEmailVerified) {
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
} else {
|
||||
try {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const user = await userQuery.get(currentUser.objectId, {
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
});
|
||||
if (user) {
|
||||
isEmailVerified = user?.get("emailVerified");
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
}
|
||||
} catch (e) {
|
||||
setHandleError("Error: Something went wrong!");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (documentData.length > 0) {
|
||||
const checkDocIdExist =
|
||||
documentData[0].AuditTrail &&
|
||||
@@ -1179,6 +1252,18 @@ function PdfRequestFiles() {
|
||||
headMsg="Document Expired!"
|
||||
bodyMssg={`This document expired on ${expiredDate} and is no longer available to sign.`}
|
||||
/>
|
||||
{!isEmailVerified && (
|
||||
<VerifyEmail
|
||||
isVerifyModal={isVerifyModal}
|
||||
setIsVerifyModal={setIsVerifyModal}
|
||||
handleVerifyEmail={handleVerifyEmail}
|
||||
setOtp={setOtp}
|
||||
otp={otp}
|
||||
otpLoader={otpLoader}
|
||||
handleVerifyBtn={handleVerifyBtn}
|
||||
handleResend={handleResend}
|
||||
/>
|
||||
)}
|
||||
|
||||
<ModalUi
|
||||
headerColor={defaultSignImg ? themeColor : "#dc3545"}
|
||||
|
||||
@@ -251,6 +251,7 @@ function PlaceHolderSign() {
|
||||
navigate(`/subscription`);
|
||||
}
|
||||
}
|
||||
|
||||
//function for get document details
|
||||
const getDocumentDetails = async () => {
|
||||
fetchTenantDetails();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import "../styles/signature.css";
|
||||
import Parse from "parse";
|
||||
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||
import axios from "axios";
|
||||
import Loader from "../primitives/LoaderWithMsg";
|
||||
@@ -31,7 +32,8 @@ import {
|
||||
checkIsSubscribed,
|
||||
convertPdfArrayBuffer,
|
||||
fetchImageBase64,
|
||||
changeImageWH
|
||||
changeImageWH,
|
||||
handleSendOTP
|
||||
} from "../constant/Utils";
|
||||
import { useParams } from "react-router-dom";
|
||||
import Tour from "reactour";
|
||||
@@ -44,6 +46,7 @@ import TourContentWithBtn from "../primitives/TourContentWithBtn";
|
||||
import Title from "../components/Title";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||
import VerifyEmail from "../components/pdf/VerifyEmail";
|
||||
|
||||
//For signYourself inProgress section signer can add sign and complete doc sign.
|
||||
function SignYourSelf() {
|
||||
@@ -91,6 +94,7 @@ function SignYourSelf() {
|
||||
const [containerWH, setContainerWH] = useState({});
|
||||
const [isPageCopy, setIsPageCopy] = useState(false);
|
||||
const [selectWidgetId, setSelectWidgetId] = useState("");
|
||||
const [otpLoader, setOtpLoader] = useState(false);
|
||||
const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({
|
||||
status: false
|
||||
});
|
||||
@@ -107,6 +111,9 @@ function SignYourSelf() {
|
||||
const [isCompleted, setIsCompleted] = useState(false);
|
||||
const [pdfArrayBuffer, setPdfArrayBuffer] = useState("");
|
||||
const [activeMailAdapter, setActiveMailAdapter] = useState("");
|
||||
const [isEmailVerified, setIsEmailVerified] = useState(true);
|
||||
const [isVerifyModal, setIsVerifyModal] = useState(false);
|
||||
const [otp, setOtp] = useState("");
|
||||
const divRef = useRef(null);
|
||||
const nodeRef = useRef(null);
|
||||
const [, drop] = useDrop({
|
||||
@@ -226,6 +233,29 @@ function SignYourSelf() {
|
||||
setSignBtnPosition([]);
|
||||
}
|
||||
}
|
||||
|
||||
if (!isCompleted) {
|
||||
//check current user email verified or not
|
||||
const currentUser = JSON.parse(JSON.stringify(Parse.User.current()));
|
||||
let isEmailVerified;
|
||||
isEmailVerified = currentUser?.emailVerified;
|
||||
if (isEmailVerified) {
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
} else {
|
||||
try {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const user = await userQuery.get(currentUser.objectId, {
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
});
|
||||
if (user) {
|
||||
isEmailVerified = user?.get("emailVerified");
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
}
|
||||
} catch (e) {
|
||||
setHandleError("Error: Something went wrong!");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(documentData.result && documentData.result.error)
|
||||
@@ -533,6 +563,44 @@ function SignYourSelf() {
|
||||
setSelectWidgetId(key);
|
||||
setSignKey(key);
|
||||
};
|
||||
|
||||
//`handleResend` function is used to resend otp for email verification
|
||||
const handleResend = async (e) => {
|
||||
e.preventDefault();
|
||||
setOtpLoader(true);
|
||||
await handleSendOTP(Parse.User.current().getEmail());
|
||||
setOtpLoader(false);
|
||||
alert("OTP sent on you email");
|
||||
};
|
||||
//`handleVerifyEmail` function is used to verify email with otp
|
||||
const handleVerifyEmail = async (e) => {
|
||||
e.preventDefault();
|
||||
setOtpLoader(true);
|
||||
try {
|
||||
const resEmail = await Parse.Cloud.run("verifyemail", {
|
||||
otp: otp,
|
||||
email: Parse.User.current().getEmail()
|
||||
});
|
||||
if (resEmail?.message === "Email is verified.") {
|
||||
setIsEmailVerified(true);
|
||||
} else if (resEmail?.message === "Email is already verified.") {
|
||||
setIsEmailVerified(true);
|
||||
}
|
||||
setOtp("");
|
||||
alert(resEmail.message);
|
||||
setIsVerifyModal(false);
|
||||
// handleRecipientSign();
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
} finally {
|
||||
setOtpLoader(false);
|
||||
}
|
||||
};
|
||||
//`handleVerifyBtn` function is used to send otp on user mail
|
||||
const handleVerifyBtn = async () => {
|
||||
setIsVerifyModal(true);
|
||||
await handleSendOTP(Parse.User.current().getEmail());
|
||||
};
|
||||
//function for send placeholder's co-ordinate(x,y) position embed signature url or stamp url
|
||||
async function embedWidgetsData() {
|
||||
let showAlert = false;
|
||||
@@ -1037,6 +1105,18 @@ function SignYourSelf() {
|
||||
)}
|
||||
|
||||
<div className="signatureContainer" ref={divRef}>
|
||||
{!isEmailVerified && (
|
||||
<VerifyEmail
|
||||
isVerifyModal={isVerifyModal}
|
||||
setIsVerifyModal={setIsVerifyModal}
|
||||
handleVerifyEmail={handleVerifyEmail}
|
||||
setOtp={setOtp}
|
||||
otp={otp}
|
||||
otpLoader={otpLoader}
|
||||
handleVerifyBtn={handleVerifyBtn}
|
||||
handleResend={handleResend}
|
||||
/>
|
||||
)}
|
||||
{/* this component used for UI interaction and show their functionality */}
|
||||
{pdfLoadFail && !checkTourStatus && (
|
||||
<Tour
|
||||
|
||||
@@ -9,7 +9,7 @@ import axios from "axios";
|
||||
import PremiumAlertHeader from "../primitives/PremiumAlertHeader";
|
||||
import Tooltip from "../primitives/Tooltip";
|
||||
import { isEnableSubscription, rejectBtn, submitBtn } from "../constant/const";
|
||||
import { checkIsSubscribed } from "../constant/Utils";
|
||||
import { checkIsSubscribed, handleSendOTP } from "../constant/Utils";
|
||||
import Upgrade from "../primitives/Upgrade";
|
||||
import ModalUi from "../primitives/ModalUi";
|
||||
|
||||
@@ -53,9 +53,26 @@ function UserProfile() {
|
||||
if (HeaderDocId) {
|
||||
setIsDisableDocId(HeaderDocId);
|
||||
}
|
||||
const isEmailVerified = Parse.User.current()?.attributes?.emailVerified;
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
setIsLoader(false);
|
||||
const currentUser = JSON.parse(JSON.stringify(Parse.User.current()));
|
||||
let isEmailVerified = currentUser?.emailVerified || false;
|
||||
if (isEmailVerified) {
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
setIsLoader(false);
|
||||
} else {
|
||||
try {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const user = await userQuery.get(currentUser.objectId, {
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
});
|
||||
if (user) {
|
||||
isEmailVerified = user?.get("emailVerified");
|
||||
setIsEmailVerified(isEmailVerified);
|
||||
setIsLoader(false);
|
||||
}
|
||||
} catch (e) {
|
||||
alert("something went wrong!");
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
@@ -185,27 +202,15 @@ function UserProfile() {
|
||||
const handleDisableDocId = () => {
|
||||
setIsDisableDocId((prevChecked) => !prevChecked);
|
||||
};
|
||||
//`handleVerifyBtn` function is used to send otp on user mail
|
||||
const handleVerifyBtn = async () => {
|
||||
setIsVerifyModal(true);
|
||||
await handleSendOTP();
|
||||
await handleSendOTP(Parse.User.current().getEmail());
|
||||
};
|
||||
const handleCloseVerifyModal = async () => {
|
||||
setIsVerifyModal(false);
|
||||
};
|
||||
const handleSendOTP = async () => {
|
||||
try {
|
||||
let url = `${parseBaseUrl}functions/SendOTPMailV1`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseAppId
|
||||
};
|
||||
const body = { email: Parse.User.current().getEmail() };
|
||||
await axios.post(url, body, { headers: headers });
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
}
|
||||
};
|
||||
|
||||
//`handleVerifyEmail` function is used to verify email with otp
|
||||
const handleVerifyEmail = async (e) => {
|
||||
e.preventDefault();
|
||||
setOtpLoader(true);
|
||||
@@ -228,7 +233,8 @@ function UserProfile() {
|
||||
setOtpLoader(false);
|
||||
}
|
||||
};
|
||||
const handleReset = async (e) => {
|
||||
//function to use resend otp for email verification
|
||||
const handleResend = async (e) => {
|
||||
e.preventDefault();
|
||||
setOtpLoader(true);
|
||||
await handleSendOTP();
|
||||
@@ -497,6 +503,7 @@ function UserProfile() {
|
||||
<div className="px-6 py-3">
|
||||
<label className="mb-2">Enter OTP</label>
|
||||
<input
|
||||
required
|
||||
type="tel"
|
||||
pattern="[0-9]{4}"
|
||||
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||
@@ -512,7 +519,7 @@ function UserProfile() {
|
||||
</button>
|
||||
<button
|
||||
className={`${rejectBtn} ml-2`}
|
||||
onClick={(e) => handleReset(e)}
|
||||
onClick={(e) => handleResend(e)}
|
||||
>
|
||||
Resend
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user