mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-08-17 21:25:54 +02:00
Merge pull request #915 from OpenSignLabs/raktima-opensignlabs-patch-11
feat : implement public profile functionality and develop script for public sign-in
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"presets": ["@babel/preset-env", "@babel/preset-react"]
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
presets: ["@babel/preset-env", "@babel/preset-react"]
|
||||
};
|
||||
Generated
+907
-67
File diff suppressed because it is too large
Load Diff
@@ -51,12 +51,14 @@
|
||||
"ws": "^8.18.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build-webpack": "webpack --config webpack.config.js",
|
||||
"build": "npm run version && npm run build-webpack && react-scripts build",
|
||||
"build-watch": "webpack --config webpack.config.js --watch",
|
||||
"start-dev": "concurrently \"npm run build-watch\" \"react-scripts start\"",
|
||||
"start": "serve -s build",
|
||||
"start-dev": "react-scripts start",
|
||||
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
|
||||
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
|
||||
"build": "npm run version && react-scripts build",
|
||||
"build-win": "npm run version-win && react-scripts build",
|
||||
"build-win": "npm run version-win && npm run build-webpack && react-scripts build",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"release": "standard-version",
|
||||
@@ -86,18 +88,30 @@
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.24.6",
|
||||
"@babel/preset-env": "^7.24.6",
|
||||
"@babel/preset-react": "^7.24.6",
|
||||
"@babel/runtime-corejs2": "^7.24.7",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"babel-loader": "^9.1.3",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"commitizen": "^4.3.0",
|
||||
"concurrently": "^8.2.2",
|
||||
"css-loader": "^7.1.2",
|
||||
"daisyui": "^4.12.10",
|
||||
"dotenv": "^16.4.5",
|
||||
"dotenv-webpack": "^8.1.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-prettier": "^5.1.3",
|
||||
"eslint-plugin-react": "^7.34.3",
|
||||
"lint-staged": "^15.2.7",
|
||||
"mini-css-extract-plugin": "^2.9.0",
|
||||
"postcss": "^8.4.39",
|
||||
"prettier": "^3.3.2",
|
||||
"pretty-quick": "^4.0.0",
|
||||
"tailwindcss": "^3.4.4"
|
||||
"tailwindcss": "^3.4.4",
|
||||
"terser-webpack-plugin": "^5.3.10",
|
||||
"webpack-cli": "^5.1.4"
|
||||
},
|
||||
"overrides": {
|
||||
"nth-check": "$nth-check",
|
||||
|
||||
@@ -28356,7 +28356,7 @@
|
||||
:root {
|
||||
--fa-font-solid: normal 900 1em/1 "Font Awesome 6 Pro";
|
||||
}
|
||||
/* @font-face {
|
||||
@font-face {
|
||||
font-family: "Font Awesome 6 Pro";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
@@ -28364,7 +28364,7 @@
|
||||
src:
|
||||
url(../webfonts/fa-solid-900.woff2) format("woff2"),
|
||||
url(../webfonts/fa-solid-900.ttf) format("truetype");
|
||||
} */
|
||||
}
|
||||
.fa-solid,
|
||||
.fas {
|
||||
font-weight: 900;
|
||||
@@ -28395,14 +28395,14 @@
|
||||
url(../webfonts/fa-brands-400.woff2) format("woff2"),
|
||||
url(../webfonts/fa-brands-400.ttf) format("truetype");
|
||||
}
|
||||
/* @font-face {
|
||||
@font-face {
|
||||
font-family: "Font Awesome 5 Pro";
|
||||
font-display: block;
|
||||
font-weight: 900;
|
||||
src:
|
||||
url(../webfonts/fa-solid-900.woff2) format("woff2"),
|
||||
url(../webfonts/fa-solid-900.ttf) format("truetype");
|
||||
} */
|
||||
}
|
||||
/* @font-face {
|
||||
font-family: "Font Awesome 5 Pro";
|
||||
font-display: block;
|
||||
@@ -28427,13 +28427,13 @@
|
||||
url(../webfonts/fa-duotone-900.woff2) format("woff2"),
|
||||
url(../webfonts/fa-duotone-900.ttf) format("truetype");
|
||||
} */
|
||||
/* @font-face {
|
||||
@font-face {
|
||||
font-family: "FontAwesome";
|
||||
font-display: block;
|
||||
src:
|
||||
url(../webfonts/fa-solid-900.woff2) format("woff2"),
|
||||
url(../webfonts/fa-solid-900.ttf) format("truetype");
|
||||
} */
|
||||
}
|
||||
@font-face {
|
||||
font-family: "FontAwesome";
|
||||
font-display: block;
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 86 KiB |
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
@@ -166,11 +166,16 @@ function App() {
|
||||
path="/pdfRequestFiles/:docId"
|
||||
element={<PdfRequestFiles />}
|
||||
/>
|
||||
|
||||
{/* recipient signature route with no rowlevel data using docId from url */}
|
||||
<Route
|
||||
path="/recipientSignPdf/:docId/:contactBookId"
|
||||
element={<PdfRequestFiles />}
|
||||
/>
|
||||
<Route
|
||||
path="/recipientSignPdf/:docId"
|
||||
element={<PdfRequestFiles />}
|
||||
/>
|
||||
</Route>
|
||||
<Route path="/sso" element={<SSOVerify />} />
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
|
||||
@@ -85,7 +85,13 @@ const Header = ({ showSidebar }) => {
|
||||
document.removeEventListener("click", closeMenuOnOutsideClick);
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
const handleConsoleRedirect = () => {
|
||||
if (window.location.host === "staging-app.opensignlabs.com") {
|
||||
window.open(" https://staging-console.opensignlabs.com/");
|
||||
} else {
|
||||
window.open("https://console.opensignlabs.com/");
|
||||
}
|
||||
};
|
||||
return (
|
||||
<div className="op-navbar bg-base-100 shadow">
|
||||
<div className="flex-none">
|
||||
@@ -188,7 +194,7 @@ const Header = ({ showSidebar }) => {
|
||||
</li>
|
||||
<li
|
||||
onClick={() => {
|
||||
window.open("https://console.opensignlabs.com/");
|
||||
handleConsoleRedirect();
|
||||
}}
|
||||
>
|
||||
<span>
|
||||
|
||||
@@ -104,7 +104,7 @@ function DriveBody(props) {
|
||||
const signedUrl = data.SignedUrl;
|
||||
//checking if document has completed and request signature flow
|
||||
if (data?.IsCompleted && signerExist?.length > 0) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
}
|
||||
//checking if document has completed and signyour-self flow
|
||||
else if (!signerExist && !isPlaceholder) {
|
||||
@@ -112,7 +112,7 @@ function DriveBody(props) {
|
||||
}
|
||||
//checking if document has declined by someone
|
||||
else if (isDecline) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
//checking draft type document
|
||||
} else if (
|
||||
signerExist?.length > 0 &&
|
||||
@@ -123,7 +123,7 @@ function DriveBody(props) {
|
||||
}
|
||||
//Inprogress document
|
||||
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
} //placeholder draft document
|
||||
else if (
|
||||
(signerExist?.length > 0 &&
|
||||
|
||||
@@ -1,23 +1,19 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import LoaderWithMsg from "../../primitives/LoaderWithMsg";
|
||||
import { contractDocument } from "../../constant/Utils";
|
||||
import HandleError from "../../primitives/HandleError";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
function useQuery() {
|
||||
return new URLSearchParams(useLocation().search);
|
||||
}
|
||||
function DraftDocument() {
|
||||
const navigate = useNavigate();
|
||||
const query = useQuery();
|
||||
const docId = query.get("docId");
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoader: true,
|
||||
message: "This might take some time"
|
||||
});
|
||||
|
||||
const rowLevel =
|
||||
localStorage.getItem("rowlevel") &&
|
||||
JSON.parse(localStorage.getItem("rowlevel"));
|
||||
const docId =
|
||||
rowLevel && rowLevel?.id
|
||||
? rowLevel.id
|
||||
: rowLevel?.objectId && rowLevel.objectId;
|
||||
|
||||
useEffect(() => {
|
||||
getDocumentDetails();
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
@@ -53,7 +49,7 @@ function DraftDocument() {
|
||||
const signedUrl = data.SignedUrl;
|
||||
//checking if document has completed and request signature flow
|
||||
if (data?.IsCompleted && signerExist?.length > 0) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
}
|
||||
//checking if document has completed and signyour-self flow
|
||||
else if (!signerExist && !isPlaceholder) {
|
||||
@@ -61,7 +57,7 @@ function DraftDocument() {
|
||||
}
|
||||
//checking if document has declined by someone
|
||||
else if (isDecline) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
//checking draft type document
|
||||
} else if (
|
||||
signerExist?.length > 0 &&
|
||||
@@ -72,7 +68,7 @@ function DraftDocument() {
|
||||
}
|
||||
//Inprogress document
|
||||
else if (isPlaceholder?.length > 0 && signerExist?.length > 0) {
|
||||
navigate(`/pdfRequestFiles/${data.objectId}`);
|
||||
navigate(`/recipientSignPdf/${data.objectId}`);
|
||||
} //placeholder draft document
|
||||
else if (
|
||||
(signerExist?.length > 0 &&
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
} from "../../constant/Utils";
|
||||
import "../../styles/signature.css";
|
||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import ModalUi from "../../primitives/ModalUi";
|
||||
import Loader from "../../primitives/Loader";
|
||||
|
||||
@@ -33,12 +32,12 @@ function Header({
|
||||
isSignYourself,
|
||||
setIsEmail,
|
||||
completeBtnTitle,
|
||||
setIsEditTemplate
|
||||
setIsEditTemplate,
|
||||
isPublicTemplate
|
||||
}) {
|
||||
const filterPrefill =
|
||||
signerPos && signerPos?.filter((data) => data.Role !== "prefill");
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const navigate = useNavigate();
|
||||
const [isDownloading, setIsDownloading] = useState("");
|
||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||
|
||||
@@ -61,7 +60,7 @@ function Header({
|
||||
}}
|
||||
>
|
||||
<div className="flex justify-between items-center py-[5px] px-[10px] ">
|
||||
<div onClick={() => navigate(-1)}>
|
||||
<div onClick={() => window.history.go(-2)}>
|
||||
<i
|
||||
className="fa-light fa-arrow-left text-base-content"
|
||||
aria-hidden="true"
|
||||
@@ -272,7 +271,7 @@ function Header({
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={() => navigate(-1)}
|
||||
onClick={() => window.history.go(-2)}
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||
>
|
||||
@@ -338,7 +337,7 @@ function Header({
|
||||
) : (
|
||||
<div className="flex" data-tut="reactourFifth">
|
||||
<button
|
||||
onClick={() => navigate(-1)}
|
||||
onClick={() => window.history.go(-2)}
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||
>
|
||||
@@ -414,10 +413,24 @@ function Header({
|
||||
<span className="hidden lg:block ml-1">Mail</span>
|
||||
</button>
|
||||
</div>
|
||||
) : isPublicTemplate ? (
|
||||
<>
|
||||
<div className="flex">
|
||||
<button
|
||||
type="button"
|
||||
className="op-btn op-btn-primary op-btn-sm shadow"
|
||||
onClick={() => {
|
||||
embedWidgetsData();
|
||||
}}
|
||||
>
|
||||
Sign Now
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div className="flex">
|
||||
<button
|
||||
onClick={() => navigate(-1)}
|
||||
onClick={() => window.history.go(-2)}
|
||||
type="button"
|
||||
className="op-btn op-btn-ghost op-btn-sm mr-[3px]"
|
||||
>
|
||||
|
||||
@@ -234,25 +234,29 @@ function Placeholder(props) {
|
||||
setDraggingEnabled(false);
|
||||
}
|
||||
if ((props.isNeedSign || props.isSignYourself) && !props.isDragging) {
|
||||
if (props.pos.type) {
|
||||
if (
|
||||
props.pos.type === "signature" ||
|
||||
props.pos.type === "stamp" ||
|
||||
props.pos.type === "image"
|
||||
) {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos.isStamp);
|
||||
} else if (props.pos.type === "initials") {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos.isStamp);
|
||||
props.setIsInitial(true);
|
||||
}
|
||||
if (props?.ispublicTemplate) {
|
||||
props.handleUserDetails();
|
||||
} else {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos?.isStamp ? props.pos.isStamp : false);
|
||||
if (props.pos.type) {
|
||||
if (
|
||||
props.pos.type === "signature" ||
|
||||
props.pos.type === "stamp" ||
|
||||
props.pos.type === "image"
|
||||
) {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos.isStamp);
|
||||
} else if (props.pos.type === "initials") {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos.isStamp);
|
||||
props.setIsInitial(true);
|
||||
}
|
||||
} else {
|
||||
props.setIsSignPad(true);
|
||||
props.setSignKey(props.pos.key);
|
||||
props.setIsStamp(props.pos?.isStamp ? props.pos.isStamp : false);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
props.isPlaceholder &&
|
||||
@@ -295,6 +299,12 @@ function Placeholder(props) {
|
||||
}
|
||||
if (props.isNeedSign && props.data?.signerObjId === props.signerObjId) {
|
||||
handleWidgetIdandPopup();
|
||||
} else if (
|
||||
props?.isNeedSign &&
|
||||
props?.uniqueId &&
|
||||
props.data?.Id === props?.uniqueId
|
||||
) {
|
||||
handleWidgetIdandPopup();
|
||||
} else if (props.isPlaceholder || props.isSignYourself) {
|
||||
handleWidgetIdandPopup();
|
||||
}
|
||||
@@ -660,6 +670,19 @@ function Placeholder(props) {
|
||||
}
|
||||
};
|
||||
|
||||
const getCursor = () => {
|
||||
if (props.data && props.isNeedSign) {
|
||||
if (props?.signerObjId && props.data?.signerObjId === props.signerObjId) {
|
||||
return "pointer";
|
||||
} else if (props?.uniqueId && props.data?.Id === props.uniqueId) {
|
||||
return "pointer";
|
||||
} else {
|
||||
return "not-allowed";
|
||||
}
|
||||
} else {
|
||||
return "all-scroll";
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Rnd
|
||||
id={props.pos.key}
|
||||
@@ -710,12 +733,7 @@ function Placeholder(props) {
|
||||
props.pos.type !== "company" &&
|
||||
props.pos.type !== "job title" &&
|
||||
"center",
|
||||
cursor:
|
||||
props.data && props.isNeedSign
|
||||
? props.data?.signerObjId === props.signerObjId
|
||||
? "pointer"
|
||||
: "not-allowed"
|
||||
: "all-scroll",
|
||||
cursor: getCursor(),
|
||||
zIndex:
|
||||
props.pos.type === "date"
|
||||
? props.pos.key === props.selectWidgetId
|
||||
|
||||
@@ -57,7 +57,7 @@ function RenderAllPdfPage({
|
||||
<div className="absolute z-20 top-[1px] -right-[13px] -translate-x-1/2 -translate-y-1/2">
|
||||
<i
|
||||
style={{ color: bookmarkColor || "red" }}
|
||||
className="fa-light fa-bookmark"
|
||||
className="fa-solid fa-bookmark"
|
||||
></i>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -58,7 +58,9 @@ function RenderPdf({
|
||||
uniqueId,
|
||||
pdfOriginalWH,
|
||||
scale,
|
||||
setIsSelectId
|
||||
setIsSelectId,
|
||||
ispublicTemplate,
|
||||
handleUserDetails
|
||||
}) {
|
||||
const isMobile = window.innerWidth < 767;
|
||||
//check isGuestSigner is present in local if yes than handle login flow header in mobile view
|
||||
@@ -195,6 +197,8 @@ function RenderPdf({
|
||||
containerWH={containerWH}
|
||||
pdfOriginalWH={pdfOriginalWH}
|
||||
pageNumber={pageNumber}
|
||||
ispublicTemplate={ispublicTemplate}
|
||||
handleUserDetails={handleUserDetails}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
@@ -430,7 +434,7 @@ function RenderPdf({
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: containerWH.width && containerWH.width * scale
|
||||
width: containerWH?.width && containerWH?.width * scale
|
||||
}}
|
||||
ref={drop}
|
||||
id="container"
|
||||
|
||||
@@ -164,8 +164,8 @@ function SignPad({
|
||||
}
|
||||
}
|
||||
|
||||
const trimmedName = currentUserName.trim();
|
||||
const firstCharacter = trimmedName.charAt(0);
|
||||
const trimmedName = currentUserName && currentUserName.trim();
|
||||
const firstCharacter = trimmedName?.charAt(0);
|
||||
const userName = isInitial ? firstCharacter : currentUserName;
|
||||
setSignValue(userName);
|
||||
setFontSelect("Fasthand");
|
||||
|
||||
@@ -35,7 +35,9 @@ function SignerListComponent(props) {
|
||||
className="flex w-[30px] h-[30px] rounded-full justify-center items-center mx-1"
|
||||
>
|
||||
<span className="text-[12px] text-center font-bold text-black uppercase">
|
||||
{getFirstLetter(props?.obj?.Name || props?.obj?.Role)}
|
||||
{getFirstLetter(
|
||||
props.obj?.Name || props.obj?.email || props.obj?.Role
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function reportJson(id) {
|
||||
hoverLabel: "Sign",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-signature",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
}
|
||||
],
|
||||
@@ -69,7 +69,7 @@ export default function reportJson(id) {
|
||||
hoverLabel: "View",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-eye",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
@@ -207,7 +207,7 @@ export default function reportJson(id) {
|
||||
hoverLabel: "View",
|
||||
btnColor: "op-btn-secondary",
|
||||
btnIcon: "fa-light fa-eye",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
},
|
||||
{
|
||||
@@ -258,7 +258,7 @@ export default function reportJson(id) {
|
||||
hoverLabel: "Sign",
|
||||
btnColor: "op-btn-primary",
|
||||
btnIcon: "fa-light fa-signature",
|
||||
redirectUrl: "pdfRequestFiles",
|
||||
redirectUrl: "draftDocument",
|
||||
action: "redirect"
|
||||
}
|
||||
]
|
||||
|
||||
@@ -67,6 +67,8 @@ const HomeLayout = () => {
|
||||
const indexOfFirstDot = domainName.indexOf(".");
|
||||
// Remove the first dot and get the substring starting from the next character
|
||||
const updateDomain = domainName.substring(indexOfFirstDot); //.opensignlabs.com
|
||||
const serverUrl = localStorage.getItem("baseUrl");
|
||||
const parseAppId = localStorage.getItem("parseAppId");
|
||||
setCookie("accesstoken", localStorage.getItem("accesstoken"), {
|
||||
secure: true,
|
||||
domain: updateDomain
|
||||
@@ -75,6 +77,14 @@ const HomeLayout = () => {
|
||||
secure: true,
|
||||
domain: updateDomain
|
||||
});
|
||||
setCookie("server_url", serverUrl, {
|
||||
secure: true,
|
||||
domain: updateDomain
|
||||
});
|
||||
setCookie("parse_app_id", parseAppId, {
|
||||
secure: true,
|
||||
domain: updateDomain
|
||||
});
|
||||
};
|
||||
|
||||
async function checkIsSubscribed() {
|
||||
|
||||
@@ -6,7 +6,6 @@ import Parse from "parse";
|
||||
import axios from "axios";
|
||||
import { DndProvider } from "react-dnd";
|
||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||
import { useLocation, useNavigate, useParams } from "react-router-dom";
|
||||
import SignPad from "../components/pdf/SignPad";
|
||||
import RenderAllPdfPage from "../components/pdf/RenderAllPdfPage";
|
||||
import Tour from "reactour";
|
||||
@@ -49,15 +48,7 @@ import SignerListComponent from "../components/pdf/SignerListComponent";
|
||||
import VerifyEmail from "../components/pdf/VerifyEmail";
|
||||
import PdfZoom from "../components/pdf/PdfZoom";
|
||||
|
||||
function useQuery() {
|
||||
return new URLSearchParams(useLocation().search);
|
||||
}
|
||||
function PdfRequestFiles() {
|
||||
const { docId } = useParams();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
const query = useQuery();
|
||||
const sendmail = query.get("sendmail");
|
||||
function PdfRequestFiles(props) {
|
||||
const [pdfDetails, setPdfDetails] = useState([]);
|
||||
const [signedSigners, setSignedSigners] = useState([]);
|
||||
const [unsignedSigners, setUnSignedSigners] = useState([]);
|
||||
@@ -129,19 +120,18 @@ function PdfRequestFiles() {
|
||||
const [zoomPercent, setZoomPercent] = useState(0);
|
||||
const [totalZoomPercent, setTotalZoomPercent] = useState();
|
||||
const [scale, setScale] = useState(1);
|
||||
const [uniqueId, setUniqueId] = useState("");
|
||||
const [isPublicTemplate, setIsPublicTemplate] = useState(false);
|
||||
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
||||
const [isOtp, setIsOtp] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [res, setRes] = useState({});
|
||||
const [documentId, setDocumentId] = useState("");
|
||||
const [isPublicContact, setIsPublicContact] = useState(false);
|
||||
const isHeader = useSelector((state) => state.showHeader);
|
||||
const divRef = useRef(null);
|
||||
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const rowLevel =
|
||||
localStorage.getItem("rowlevel") &&
|
||||
JSON.parse(localStorage.getItem("rowlevel"));
|
||||
|
||||
const objectId =
|
||||
rowLevel && rowLevel.id
|
||||
? rowLevel.id
|
||||
: rowLevel?.objectId && rowLevel.objectId;
|
||||
const documentId = docId ? docId : objectId && objectId;
|
||||
|
||||
const senderUser =
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
@@ -151,12 +141,36 @@ function PdfRequestFiles() {
|
||||
);
|
||||
const jsonSender = JSON.parse(senderUser);
|
||||
|
||||
let isGuestSignFlow = false;
|
||||
let sendmail;
|
||||
let getDocId = "";
|
||||
const route = !props.templateId && window.location.pathname;
|
||||
const getQuery =
|
||||
!props.templateId &&
|
||||
window.location?.search &&
|
||||
window.location?.search?.split("?");
|
||||
|
||||
if (getQuery) {
|
||||
sendmail = getQuery[1].split("=")[1];
|
||||
}
|
||||
const checkSplit = route && route?.split("/");
|
||||
|
||||
if (checkSplit && checkSplit.length > 4) {
|
||||
isGuestSignFlow = true;
|
||||
getDocId = checkSplit[3];
|
||||
} else {
|
||||
getDocId = checkSplit[2];
|
||||
}
|
||||
let getDocumentId = getDocId || documentId;
|
||||
useEffect(() => {
|
||||
if (documentId) {
|
||||
getDocumentDetails();
|
||||
if (getDocumentId) {
|
||||
setDocumentId(getDocumentId);
|
||||
getDocumentDetails(getDocumentId);
|
||||
} else if (props.templateId) {
|
||||
getTemplateDetails();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
}, [props.templateId, getDocumentId]);
|
||||
useEffect(() => {
|
||||
const updateSize = () => {
|
||||
if (divRef.current) {
|
||||
@@ -171,7 +185,6 @@ function PdfRequestFiles() {
|
||||
|
||||
// Use setTimeout to wait for the transition to complete
|
||||
const timer = setTimeout(updateSize, 100); // match the transition duration
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [divRef.current, isHeader]);
|
||||
@@ -208,7 +221,7 @@ function PdfRequestFiles() {
|
||||
setOtp("");
|
||||
alert(resEmail.message);
|
||||
setIsVerifyModal(false);
|
||||
// handleRecipientSign();
|
||||
//handleRecipientSign();
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
} finally {
|
||||
@@ -225,7 +238,7 @@ function PdfRequestFiles() {
|
||||
await handleSendOTP(currentUser?.email);
|
||||
};
|
||||
async function checkIsSubscribed(extUserId, contactId) {
|
||||
const isGuestSign = location.pathname.includes("/load/") || false;
|
||||
const isGuestSign = isGuestSignFlow || false;
|
||||
const res = await fetchSubscription(extUserId, contactId, isGuestSign);
|
||||
const plan = res.plan;
|
||||
const billingDate = res?.billingDate;
|
||||
@@ -237,10 +250,10 @@ function PdfRequestFiles() {
|
||||
setIsSubscribed(true);
|
||||
return true;
|
||||
} else {
|
||||
if (location.pathname.includes("/load/")) {
|
||||
if (isGuestSign) {
|
||||
setIsSubscriptionExpired(true);
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
window.location.href = "/subscription";
|
||||
}
|
||||
}
|
||||
} else if (isGuestSign) {
|
||||
@@ -254,15 +267,92 @@ function PdfRequestFiles() {
|
||||
if (isGuestSign) {
|
||||
setIsSubscriptionExpired(true);
|
||||
} else {
|
||||
navigate(`/subscription`);
|
||||
window.location.href = "/subscription";
|
||||
}
|
||||
}
|
||||
}
|
||||
//function for get document details for perticular signer with signer'object id
|
||||
const getDocumentDetails = async (isNextUser) => {
|
||||
const getTemplateDetails = async () => {
|
||||
try {
|
||||
const params = { templateId: props.templateId, ispublic: true };
|
||||
const templateDeatils = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
|
||||
params,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
sessiontoken: localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
);
|
||||
const documentData =
|
||||
templateDeatils.data && templateDeatils.data.result
|
||||
? [templateDeatils.data.result]
|
||||
: [];
|
||||
|
||||
if (documentData && documentData.length > 0) {
|
||||
setIsPublicTemplate(true);
|
||||
const getPublicRole = documentData[0].PublicRole[0];
|
||||
const getUniqueIdDetails = documentData[0].Placeholders.find(
|
||||
(x) => x.Role === getPublicRole
|
||||
);
|
||||
if (getUniqueIdDetails) {
|
||||
setUniqueId(getUniqueIdDetails.Id);
|
||||
}
|
||||
setSignerPos(documentData[0].Placeholders);
|
||||
let placeholdersOrSigners = [];
|
||||
// const placeholder = documentData[0]?.Placeholders;
|
||||
for (const placeholder of documentData[0].Placeholders) {
|
||||
//`emailExist` variable to handle condition for quick send flow and show unsigned signers list
|
||||
const signerIdExist = placeholder?.signerObjId;
|
||||
if (signerIdExist) {
|
||||
const getSignerData = documentData[0].Signers.find(
|
||||
(data) => data.objectId === placeholder?.signerObjId
|
||||
);
|
||||
placeholdersOrSigners.push(getSignerData);
|
||||
} else {
|
||||
placeholdersOrSigners.push(placeholder);
|
||||
}
|
||||
}
|
||||
|
||||
setUnSignedSigners(placeholdersOrSigners);
|
||||
|
||||
setPdfDetails(documentData);
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
} else if (
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(documentData.result && documentData.result.error)
|
||||
) {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
} else {
|
||||
setHandleError("No Data Found!");
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log("err ", err);
|
||||
if (err?.response?.data?.code === 101) {
|
||||
setHandleError("Error: Template not found!");
|
||||
} else {
|
||||
setHandleError("Error: Something went wrong!");
|
||||
}
|
||||
}
|
||||
};
|
||||
//function for get document details for perticular signer with signer'object id
|
||||
const getDocumentDetails = async (docId, isNextUser) => {
|
||||
let currUserId;
|
||||
//getting document details
|
||||
const documentData = await contractDocument(documentId);
|
||||
const documentData = await contractDocument(documentId || docId);
|
||||
if (documentData && documentData.length > 0) {
|
||||
setExtUserId(documentData[0]?.ExtUserPtr?.objectId);
|
||||
const isCompleted =
|
||||
@@ -336,8 +426,7 @@ function PdfRequestFiles() {
|
||||
setCurrentSigner(true);
|
||||
}
|
||||
}
|
||||
|
||||
const isGuestSign = location.pathname.includes("/load/");
|
||||
const isGuestSign = isGuestSignFlow;
|
||||
if (
|
||||
!isGuestSign &&
|
||||
!isCompleted &&
|
||||
@@ -436,14 +525,14 @@ function PdfRequestFiles() {
|
||||
const placeholdersOrSigners = [];
|
||||
for (const placeholder of documentData[0].Placeholders) {
|
||||
//`emailExist` variable to handle condition for quick send flow and show unsigned signers list
|
||||
const emailExist = placeholder?.email;
|
||||
if (emailExist) {
|
||||
placeholdersOrSigners.push(placeholder);
|
||||
} else {
|
||||
const signerIdExist = placeholder?.signerObjId;
|
||||
if (signerIdExist) {
|
||||
const getSignerData = documentData[0].Signers.find(
|
||||
(data) => data.objectId === placeholder?.signerObjId
|
||||
);
|
||||
placeholdersOrSigners.push(getSignerData);
|
||||
} else {
|
||||
placeholdersOrSigners.push(placeholder);
|
||||
}
|
||||
}
|
||||
//condition to check already signed document by someone
|
||||
@@ -872,7 +961,12 @@ function PdfRequestFiles() {
|
||||
`${pdfDetails?.[0].objectId}/${user.Email}`
|
||||
);
|
||||
}
|
||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||
// let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
||||
const hostPublicUrl =
|
||||
"https://staging-app.opensignlabs.com";
|
||||
let signPdf = props?.templateId
|
||||
? `${hostPublicUrl}/login/${encodeBase64}`
|
||||
: `${hostUrl}/login/${encodeBase64}`;
|
||||
const openSignUrl =
|
||||
"https://www.opensignlabs.com/contact-us";
|
||||
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
||||
@@ -1075,7 +1169,6 @@ function PdfRequestFiles() {
|
||||
return newState; // Update the state with the modified copy
|
||||
});
|
||||
};
|
||||
|
||||
//function for save button to save signature or image url
|
||||
const saveSign = (type, isDefaultSign, width, height) => {
|
||||
const isTypeText = width && height ? true : false;
|
||||
@@ -1357,9 +1450,141 @@ function PdfRequestFiles() {
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const handleUserDetails = () => {
|
||||
setIsPublicContact(true);
|
||||
};
|
||||
|
||||
//`handlePublicUser` function to use create user from public role and create document from public template
|
||||
const handlePublicUser = async (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
try {
|
||||
const params = {
|
||||
...contact,
|
||||
templateid: pdfDetails[0]?.objectId,
|
||||
role: pdfDetails[0]?.PublicRole[0]
|
||||
};
|
||||
const userRes = await axios.post(
|
||||
`${localStorage.getItem(
|
||||
"baseUrl"
|
||||
)}/functions/publicuserlinkcontacttodoc`,
|
||||
params,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (userRes?.data?.result) {
|
||||
setRes(userRes.data.result);
|
||||
await SendOtp();
|
||||
} else {
|
||||
alert("something went wrong");
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("e", e);
|
||||
// setIsLoader(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputChange = (e) => {
|
||||
setContact((prev) => ({ ...prev, [e.target.name]: e.target.value }));
|
||||
};
|
||||
|
||||
const SendOtp = async () => {
|
||||
try {
|
||||
const params = { email: contact.email, docId: res.docId };
|
||||
|
||||
const Otp = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}/functions/SendOTPMailV1`,
|
||||
params,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (Otp) {
|
||||
setIsOtp(true);
|
||||
setLoading(false);
|
||||
}
|
||||
} catch (error) {
|
||||
alert("something went wrong!");
|
||||
}
|
||||
};
|
||||
|
||||
//verify OTP send on via email
|
||||
const VerifyOTP = async (e) => {
|
||||
e.preventDefault();
|
||||
setLoading(true);
|
||||
const serverUrl =
|
||||
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
|
||||
const parseId =
|
||||
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
|
||||
if (otp) {
|
||||
// setLoading(true);
|
||||
try {
|
||||
let url = `${serverUrl}/functions/AuthLoginAsMail/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId
|
||||
};
|
||||
let body = {
|
||||
email: contact.email,
|
||||
otp: otp
|
||||
};
|
||||
let user = await axios.post(url, body, { headers: headers });
|
||||
if (user.data.result === "Invalid Otp") {
|
||||
alert("Invalid Otp");
|
||||
setLoading(false);
|
||||
} else if (user.data.result === "user not found!") {
|
||||
alert("User not found!");
|
||||
setLoading(false);
|
||||
} else {
|
||||
let _user = user.data.result;
|
||||
const parseId = localStorage.getItem("parseAppId");
|
||||
const contractUserDetails = await contractUsers(_user.email);
|
||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||
localStorage.setItem(
|
||||
`Parse/${parseId}/currentUser`,
|
||||
JSON.stringify(_user)
|
||||
);
|
||||
if (contractUserDetails && contractUserDetails.length > 0) {
|
||||
localStorage.setItem(
|
||||
"Extand_Class",
|
||||
JSON.stringify(contractUserDetails)
|
||||
);
|
||||
}
|
||||
|
||||
localStorage.setItem("username", _user.name);
|
||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||
setLoading(false);
|
||||
// navigate(`/load/recipientSignPdf/${res?.docId}/${res?.contactId}`);
|
||||
// document.getElementById("my_modal").close();
|
||||
setIsPublicContact(false);
|
||||
setIsPublicTemplate(false);
|
||||
setIsLoading({
|
||||
isLoad: false
|
||||
});
|
||||
setDocumentId(res?.docId);
|
||||
getDocumentDetails(res?.docId);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("err ", error);
|
||||
}
|
||||
} else {
|
||||
alert("Please Enter OTP!");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
<Title title={"Request Sign"} />
|
||||
<Title title={props.templateId ? "Public Sign" : "Request Sign"} />
|
||||
{isSubscriptionExpired ? (
|
||||
<ModalUi
|
||||
title={"Subscription Expired"}
|
||||
@@ -1406,7 +1631,9 @@ function PdfRequestFiles() {
|
||||
}}
|
||||
className="relative op-card overflow-hidden flex flex-col md:flex-row justify-between bg-base-300"
|
||||
>
|
||||
{!requestSignTour && requestSignTourFunction()}
|
||||
{!requestSignTour &&
|
||||
signerObjectId &&
|
||||
requestSignTourFunction()}
|
||||
<ModalUi
|
||||
isOpen={isAlert.isShow}
|
||||
title={"Alert message"}
|
||||
@@ -1481,6 +1708,147 @@ function PdfRequestFiles() {
|
||||
/>
|
||||
)}
|
||||
|
||||
<ModalUi
|
||||
isOpen={isPublicContact}
|
||||
title={"Contact Details"}
|
||||
handleClose={() => {
|
||||
setIsPublicContact(false);
|
||||
}}
|
||||
>
|
||||
<div className="h-full p-[20px]">
|
||||
{isOtp ? (
|
||||
<form onSubmit={VerifyOTP}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span>You will get a OTP via Email</span>
|
||||
<label className="op-input op-input-bordered flex items-center gap-2 ">
|
||||
<input
|
||||
type="number"
|
||||
name="otp"
|
||||
className="grow"
|
||||
placeholder="Enter Verification Code"
|
||||
required
|
||||
value={otp}
|
||||
onChange={(e) => setOtp(e.target.value)}
|
||||
disabled={loading}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div className="op-modal-action">
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
className="op-btn op-btn-ghost"
|
||||
onClick={() => {
|
||||
// document.getElementById("my_modal").close();
|
||||
setIsPublicContact(false);
|
||||
setLoading(false);
|
||||
setIsOtp(false);
|
||||
setOtp();
|
||||
setContact({
|
||||
name: "",
|
||||
email: "",
|
||||
phone: ""
|
||||
});
|
||||
}}
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button
|
||||
className="op-btn op-btn-primary"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "Loading..." : "Verify"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
<form onSubmit={handlePublicUser}>
|
||||
<div className="flex flex-col gap-2">
|
||||
<label className="op-input op-input-bordered flex items-center gap-2 ">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
className="w-4 h-4 opacity-70"
|
||||
>
|
||||
<path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM12.735 14c.618 0 1.093-.561.872-1.139a6.002 6.002 0 0 0-11.215 0c-.22.578.254 1.139.872 1.139h9.47Z" />
|
||||
</svg>
|
||||
<input
|
||||
type="text"
|
||||
className="grow"
|
||||
name="name"
|
||||
value={contact.name}
|
||||
onChange={handleInputChange}
|
||||
placeholder="name"
|
||||
required
|
||||
disabled={loading}
|
||||
/>
|
||||
</label>
|
||||
<label className="op-input op-input-bordered flex items-center gap-2 ">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
className="w-4 h-4 opacity-70"
|
||||
>
|
||||
<path d="M2.5 3A1.5 1.5 0 0 0 1 4.5v.793c.026.009.051.02.076.032L7.674 8.51c.206.1.446.1.652 0l6.598-3.185A.755.755 0 0 1 15 5.293V4.5A1.5 1.5 0 0 0 13.5 3h-11Z" />
|
||||
<path d="M15 6.954 8.978 9.86a2.25 2.25 0 0 1-1.956 0L1 6.954V11.5A1.5 1.5 0 0 0 2.5 13h11a1.5 1.5 0 0 0 1.5-1.5V6.954Z" />
|
||||
</svg>
|
||||
<input
|
||||
type="text"
|
||||
className="grow"
|
||||
name="email"
|
||||
value={contact.email}
|
||||
onChange={handleInputChange}
|
||||
placeholder="Email"
|
||||
required
|
||||
disabled={loading}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<label className="op-input op-input-bordered flex items-center gap-2 ">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 16 16"
|
||||
fill="currentColor"
|
||||
className="w-4 h-4 opacity-70"
|
||||
>
|
||||
<path d="M8 8a3 3 0 1 0 0-6 3 3 0 0 0 0 6ZM12.735 14c.618 0 1.093-.561.872-1.139a6.002 6.002 0 0 0-11.215 0c-.22.578.254 1.139.872 1.139h9.47Z" />
|
||||
</svg>
|
||||
<input
|
||||
value={contact.phone}
|
||||
onChange={handleInputChange}
|
||||
type="text"
|
||||
name="phone"
|
||||
className="grow"
|
||||
placeholder="phone"
|
||||
disabled={loading}
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<div className="op-modal-action">
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
className="op-btn op-btn-ghost"
|
||||
onClick={() => {
|
||||
// document.getElementById("my_modal").close();
|
||||
setIsPublicContact(false);
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
className="op-btn op-btn-primary"
|
||||
disabled={loading}
|
||||
>
|
||||
{loading ? "Loading..." : "Submit"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</ModalUi>
|
||||
<ModalUi
|
||||
isOpen={defaultSignAlert.isShow}
|
||||
title={"Auto sign"}
|
||||
@@ -1673,7 +2041,7 @@ function PdfRequestFiles() {
|
||||
/>
|
||||
{/* pdf header which contain funish back button */}
|
||||
<Header
|
||||
isPdfRequestFiles={true}
|
||||
isPdfRequestFiles={isPublicTemplate ? false : true}
|
||||
pageNumber={pageNumber}
|
||||
allPages={allPages}
|
||||
changePage={changePage}
|
||||
@@ -1681,7 +2049,9 @@ function PdfRequestFiles() {
|
||||
signerPos={signerPos}
|
||||
isSigned={isSigned}
|
||||
isCompleted={isCompleted.isCertificate}
|
||||
embedWidgetsData={embedWidgetsData}
|
||||
embedWidgetsData={
|
||||
isPublicTemplate ? handleUserDetails : embedWidgetsData
|
||||
}
|
||||
isShowHeader={true}
|
||||
setIsDecline={setIsDecline}
|
||||
decline={true}
|
||||
@@ -1696,6 +2066,7 @@ function PdfRequestFiles() {
|
||||
containerWH={containerWH}
|
||||
setZoomPercent={setZoomPercent}
|
||||
zoomPercent={zoomPercent}
|
||||
isPublicTemplate={isPublicTemplate}
|
||||
/>
|
||||
|
||||
<div ref={divRef} data-tut="pdfArea" className="h-[95%]">
|
||||
@@ -1732,6 +2103,9 @@ function PdfRequestFiles() {
|
||||
setTotalZoomPercent={setTotalZoomPercent}
|
||||
setScale={setScale}
|
||||
scale={scale}
|
||||
uniqueId={uniqueId}
|
||||
ispublicTemplate={isPublicTemplate}
|
||||
handleUserDetails={handleUserDetails}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -170,16 +170,7 @@ function PlaceHolderSign() {
|
||||
isDragStamp: !!monitor.isDragging()
|
||||
})
|
||||
});
|
||||
|
||||
const rowLevel =
|
||||
localStorage.getItem("rowlevel") &&
|
||||
JSON.parse(localStorage.getItem("rowlevel"));
|
||||
const objectId =
|
||||
rowLevel && rowLevel.id
|
||||
? rowLevel.id
|
||||
: rowLevel?.objectId && rowLevel.objectId;
|
||||
|
||||
const documentId = docId ? docId : objectId && objectId;
|
||||
const documentId = docId;
|
||||
useEffect(() => {
|
||||
if (documentId) {
|
||||
getDocumentDetails();
|
||||
@@ -633,8 +624,6 @@ function PlaceHolderSign() {
|
||||
setShowDropdown(true);
|
||||
} else if (dragTypeValue === "checkbox") {
|
||||
setIsCheckbox(true);
|
||||
} else if (dragTypeValue === radioButtonWidget) {
|
||||
setIsRadio(true);
|
||||
} else if (
|
||||
[
|
||||
textInputWidget,
|
||||
@@ -647,6 +636,8 @@ function PlaceHolderSign() {
|
||||
) {
|
||||
setFontSize(12);
|
||||
setFontColor("black");
|
||||
} else if (dragTypeValue === radioButtonWidget) {
|
||||
setIsRadio(true);
|
||||
}
|
||||
setWidgetType(dragTypeValue);
|
||||
setSignKey(key);
|
||||
|
||||
@@ -22,6 +22,7 @@ const Report = () => {
|
||||
const [form, setForm] = useState("");
|
||||
const [tourData, setTourData] = useState([]);
|
||||
const [isDontShow, setIsDontShow] = useState(false);
|
||||
const [isPublic, setIsPublic] = useState({});
|
||||
const abortController = new AbortController();
|
||||
const docPerPage = 10;
|
||||
|
||||
@@ -156,6 +157,13 @@ const Report = () => {
|
||||
? [...prevRecord, ...res.data.result]
|
||||
: res.data.result
|
||||
);
|
||||
const listData = res.data.result;
|
||||
setIsPublic(
|
||||
listData.reduce((acc, item) => {
|
||||
acc[item.objectId] = item?.IsPublic || false;
|
||||
return acc;
|
||||
}, {})
|
||||
);
|
||||
}
|
||||
}
|
||||
setIsLoader(false);
|
||||
@@ -193,6 +201,8 @@ const Report = () => {
|
||||
report_help={reporthelp}
|
||||
tourData={tourData}
|
||||
isDontShow={isDontShow}
|
||||
setIsPublic={setIsPublic}
|
||||
isPublic={isPublic}
|
||||
/>
|
||||
) : (
|
||||
<PageNotFound prefix={"Report"} />
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
import React, {
|
||||
useState,
|
||||
useEffect
|
||||
// useRef
|
||||
} from "react";
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import { Navigate, useNavigate } from "react-router-dom";
|
||||
import Parse from "parse";
|
||||
import { SaveFileSize } from "../constant/saveFileSize";
|
||||
@@ -32,10 +28,11 @@ function UserProfile() {
|
||||
const [percentage, setpercentage] = useState(0);
|
||||
const [isDisableDocId, setIsDisableDocId] = useState(false);
|
||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||
// const [publicUserName, setPublicUserName] = useState(
|
||||
// extendUser && extendUser?.[0]?.UserName
|
||||
// );
|
||||
// const previousPublicUserName = useRef(publicUserName);
|
||||
const [isUpgrade, setIsUpgrade] = useState(false);
|
||||
const [publicUserName, setPublicUserName] = useState(
|
||||
extendUser && extendUser?.[0]?.UserName
|
||||
);
|
||||
const previousPublicUserName = useRef(publicUserName);
|
||||
const [company, setCompany] = useState(
|
||||
extendUser && extendUser?.[0]?.Company
|
||||
);
|
||||
@@ -46,7 +43,10 @@ function UserProfile() {
|
||||
const [otp, setOtp] = useState("");
|
||||
const [otpLoader, setOtpLoader] = useState(false);
|
||||
const [isEmailVerified, setIsEmailVerified] = useState(false);
|
||||
// const [userNameError, setUserNameError] = useState("");
|
||||
const [userNameError, setUserNameError] = useState("");
|
||||
const [tagLine, setTagLine] = useState(
|
||||
extendUser && extendUser?.[0]?.Tagline
|
||||
);
|
||||
useEffect(() => {
|
||||
getUserDetail();
|
||||
}, []);
|
||||
@@ -85,31 +85,31 @@ function UserProfile() {
|
||||
}
|
||||
};
|
||||
//function to check public username already exist
|
||||
// const handleCheckPublicUserName = async () => {
|
||||
// try {
|
||||
// const res = await Parse.Cloud.run("getpublicusername", {
|
||||
// username: publicUserName
|
||||
// });
|
||||
// if (res) {
|
||||
// setIsLoader(false);
|
||||
// setUserNameError("user name already exist");
|
||||
// setTimeout(() => {
|
||||
// setUserNameError("");
|
||||
// }, 3000);
|
||||
// return res;
|
||||
// }
|
||||
// } catch (e) {
|
||||
// console.log("error in getpublicusername cloud function");
|
||||
// }
|
||||
// };
|
||||
const handleCheckPublicUserName = async () => {
|
||||
try {
|
||||
const res = await Parse.Cloud.run("getpublicusername", {
|
||||
username: publicUserName
|
||||
});
|
||||
if (res) {
|
||||
setIsLoader(false);
|
||||
setUserNameError("user name already exist");
|
||||
setTimeout(() => {
|
||||
setUserNameError("");
|
||||
}, 3000);
|
||||
return res;
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("error in getpublicusername cloud function");
|
||||
}
|
||||
};
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
let phn = Phone,
|
||||
res = "";
|
||||
//condition to call cloud function when user change publicUserName
|
||||
// if (previousPublicUserName.current !== publicUserName) {
|
||||
// res = await handleCheckPublicUserName();
|
||||
// }
|
||||
if (previousPublicUserName.current !== publicUserName) {
|
||||
res = await handleCheckPublicUserName();
|
||||
}
|
||||
if (!res) {
|
||||
setIsLoader(true);
|
||||
try {
|
||||
@@ -162,8 +162,9 @@ function UserProfile() {
|
||||
Name: obj.Name,
|
||||
HeaderDocId: isDisableDocId,
|
||||
JobTitle: jobTitle,
|
||||
Company: company
|
||||
// UserName: publicUserName || ""
|
||||
Company: company,
|
||||
UserName: publicUserName || "",
|
||||
Tagline: tagLine || ""
|
||||
};
|
||||
|
||||
await axios.put(
|
||||
@@ -277,23 +278,19 @@ function UserProfile() {
|
||||
alert("OTP sent on you email");
|
||||
};
|
||||
//function to handle onchange username and restrict 6-characters username for free users
|
||||
// const handleOnchangeUserName = (e) => {
|
||||
// const value = e.target.value;
|
||||
// if (value.length > 6 && !isSubscribe) {
|
||||
// setUserNameError("Please upgrade to allow more than 6 characters.");
|
||||
// setTimeout(() => {
|
||||
// setUserNameError("");
|
||||
// }, 2000);
|
||||
// } else {
|
||||
// setPublicUserName(e.target.value);
|
||||
// }
|
||||
// };
|
||||
const handleOnchangeUserName = (e) => {
|
||||
setPublicUserName(e.target.value);
|
||||
};
|
||||
|
||||
const handleOnchangeTagLine = (e) => {
|
||||
setTagLine(e.target.value);
|
||||
};
|
||||
const handleCancel = () => {
|
||||
setEditMode(false);
|
||||
SetName(localStorage.getItem("username"));
|
||||
SetPhone(UserProfile && UserProfile.phone);
|
||||
setImage(localStorage.getItem("profileImg"));
|
||||
// setPublicUserName(extendUser && extendUser?.[0]?.UserName);
|
||||
setPublicUserName(extendUser && extendUser?.[0]?.UserName);
|
||||
setCompany(extendUser && extendUser?.[0]?.Company);
|
||||
setJobTitle(extendUser?.[0]?.JobTitle);
|
||||
setIsDisableDocId(extendUser?.[0]?.HeaderDocId);
|
||||
@@ -307,13 +304,13 @@ function UserProfile() {
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex justify-center items-center w-full relative">
|
||||
{/* {userNameError && (
|
||||
{userNameError && (
|
||||
<div
|
||||
className={`z-[1000] fixed top-[50%] transform border-[1px] text-sm border-[#f0a8a8] bg-[#f4bebe] text-[#c42121] rounded py-[.75rem] px-[1.25rem]`}
|
||||
>
|
||||
{userNameError}
|
||||
</div>
|
||||
)} */}
|
||||
)}
|
||||
<div className="bg-base-100 text-base-content flex flex-col justify-center shadow-md rounded-box w-[450px]">
|
||||
<div className="flex flex-col justify-center items-center my-4">
|
||||
<div className="w-[200px] h-[200px] overflow-hidden rounded-full">
|
||||
@@ -441,37 +438,75 @@ function UserProfile() {
|
||||
)}
|
||||
</span>
|
||||
</li>
|
||||
{/* {isEnableSubscription && (
|
||||
<li className="flex justify-between items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||
<span className="font-semibold">
|
||||
Public profile :{" "}
|
||||
<Tooltip
|
||||
message={`this is your public URL. Copy or share it
|
||||
{isEnableSubscription && (
|
||||
<>
|
||||
<li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||
<span className="font-semibold flex gap-1">
|
||||
Public profile :{" "}
|
||||
<Tooltip
|
||||
maxWidth="max-w-[250px]"
|
||||
message={`this is your public URL. Copy or share it
|
||||
with the signer, and you will be able to see
|
||||
all your publicly set templates.`}
|
||||
/>
|
||||
</span>
|
||||
<div className="flex text-xs items-center">
|
||||
<span>opensign-me.vercel.app/</span>
|
||||
{editmode ? (
|
||||
<input
|
||||
onChange={handleOnchangeUserName}
|
||||
value={publicUserName}
|
||||
disabled={!editmode}
|
||||
placeholder="enter user name"
|
||||
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
value={extendUser?.[0]?.UserName}
|
||||
disabled
|
||||
placeholder="enter user name"
|
||||
className="op-input op-input-bordered op-input-xs"
|
||||
</span>
|
||||
<div className="flex md:flex-row flex-col md:items-center">
|
||||
<span className="mb-1 md:mb-1">opensign.me/</span>
|
||||
{editmode ? (
|
||||
<input
|
||||
maxLength={40}
|
||||
style={{
|
||||
border:
|
||||
!isSubscribe &&
|
||||
publicUserName.length > 0 &&
|
||||
publicUserName.length < 9 &&
|
||||
"solid red"
|
||||
}}
|
||||
onChange={handleOnchangeUserName}
|
||||
value={publicUserName}
|
||||
disabled={!editmode}
|
||||
placeholder="enter user name"
|
||||
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
value={extendUser?.[0]?.UserName}
|
||||
disabled
|
||||
placeholder="enter user name"
|
||||
className="op-input op-input-bordered op-input-xs"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
<li className="flex md:flex-row flex-col md:justify-between md:items-center border-t-[1px] border-gray-300 py-2 break-all">
|
||||
<span className="font-semibold flex gap-1">
|
||||
Tagline :{" "}
|
||||
<Tooltip
|
||||
maxWidth="max-w-[250px]"
|
||||
message={`This Tagline will appear on your OpenSign public profile for ex. https://opensign.me/alex`}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
)} */}
|
||||
</span>
|
||||
<div className="flex md:flex-row flex-col md:items-center">
|
||||
{editmode ? (
|
||||
<input
|
||||
onChange={handleOnchangeTagLine}
|
||||
value={tagLine}
|
||||
disabled={!editmode}
|
||||
placeholder="enter tagline"
|
||||
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-xs"
|
||||
/>
|
||||
) : (
|
||||
<input
|
||||
value={extendUser?.[0]?.Tagline}
|
||||
disabled
|
||||
placeholder="enter tagline"
|
||||
className="op-input op-input-bordered op-input-xs"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</li>
|
||||
</>
|
||||
)}
|
||||
<li className="border-y-[1px] border-gray-300 break-all">
|
||||
<div className="flex justify-between items-center py-2">
|
||||
<span
|
||||
@@ -517,9 +552,17 @@ function UserProfile() {
|
||||
<div className="flex justify-center gap-2 pt-2 pb-3 md:pt-3 md:pb-4">
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) =>
|
||||
editmode ? handleSubmit(e) : setEditMode(true)
|
||||
}
|
||||
onClick={(e) => {
|
||||
if (
|
||||
!isSubscribe &&
|
||||
publicUserName.length > 0 &&
|
||||
publicUserName.length < 9
|
||||
) {
|
||||
setIsUpgrade(true);
|
||||
} else {
|
||||
editmode ? handleSubmit(e) : setEditMode(true);
|
||||
}
|
||||
}}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
{editmode ? "Save" : "Edit"}
|
||||
@@ -576,6 +619,38 @@ function UserProfile() {
|
||||
)}
|
||||
</ModalUi>
|
||||
)}
|
||||
{isUpgrade && (
|
||||
<div className="op-modal op-modal-open">
|
||||
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
||||
<>
|
||||
<div
|
||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-primary-content absolute right-2 top-2 z-40"
|
||||
onClick={() => setIsUpgrade(false)}
|
||||
>
|
||||
✕
|
||||
</div>
|
||||
|
||||
<div className="op-card op-bg-primary text-primary-content w-full shadow-lg">
|
||||
<div className="op-card-body">
|
||||
<h2 className="op-card-title">Upgrade to Plan</h2>
|
||||
<p>
|
||||
To have a username less than 8 character please
|
||||
subscribe
|
||||
</p>
|
||||
<div className="op-card-actions justify-end">
|
||||
<button
|
||||
onClick={() => navigate("/subscription")}
|
||||
className="op-btn op-btn-accent"
|
||||
>
|
||||
Upgrade Now
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { useLocation, useNavigate } from "react-router-dom";
|
||||
import axios from "axios";
|
||||
import ModalUi from "./ModalUi";
|
||||
import AddSigner from "../components/AddSigner";
|
||||
// import { isEnableSubscription } from "../constant/const";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import Alert from "./Alert";
|
||||
import Tooltip from "./Tooltip";
|
||||
import { RWebShare } from "react-web-share";
|
||||
@@ -13,10 +13,10 @@ import Parse from "parse";
|
||||
import { saveAs } from "file-saver";
|
||||
import {
|
||||
checkIsSubscribedTeam,
|
||||
// copytoData,
|
||||
copytoData,
|
||||
replaceMailVaribles
|
||||
} from "../constant/Utils";
|
||||
// import Confetti from "react-confetti";
|
||||
import Confetti from "react-confetti";
|
||||
import EditorToolbar, {
|
||||
module1,
|
||||
formats
|
||||
@@ -26,7 +26,6 @@ import "react-quill/dist/quill.snow.css";
|
||||
import BulkSendUi from "../components/BulkSendUi";
|
||||
import Loader from "./Loader";
|
||||
import Select from "react-select";
|
||||
import { isEnableSubscription } from "../constant/const";
|
||||
import SubscribeCard from "./SubscribeCard";
|
||||
|
||||
const ReportTable = (props) => {
|
||||
@@ -48,7 +47,7 @@ const ReportTable = (props) => {
|
||||
const [isTour, setIsTour] = useState(false);
|
||||
const [tourStatusArr, setTourStatusArr] = useState([]);
|
||||
const [isResendMail, setIsResendMail] = useState({});
|
||||
// const [isMakePublic, setIsMakePublic] = useState({});
|
||||
const [isMakePublic, setIsMakePublic] = useState({});
|
||||
const [mail, setMail] = useState({ subject: "", body: "" });
|
||||
const [userDetails, setUserDetails] = useState({});
|
||||
const [isNextStep, setIsNextStep] = useState({});
|
||||
@@ -60,12 +59,10 @@ const ReportTable = (props) => {
|
||||
const [teamList, setTeamList] = useState([]);
|
||||
const [selectedTeam, setSelectedTeam] = useState([]);
|
||||
const onChange = (selectedOptions) => setSelectedTeam(selectedOptions);
|
||||
// const [selectedPublicRole, setSelectedPublicRole] = useState("");
|
||||
// const [isCelebration, setIsCelebration] = useState(false);
|
||||
// const [currentLists, setCurrentLists] = useState([]);
|
||||
// const [isPublic, setIsPublic] = useState({});
|
||||
// const [isPublicProfile, setIsPublicProfile] = useState({});
|
||||
// const [publicUserName, setIsPublicUserName] = useState("");
|
||||
const [selectedPublicRole, setSelectedPublicRole] = useState("");
|
||||
const [isCelebration, setIsCelebration] = useState(false);
|
||||
const [isPublicProfile, setIsPublicProfile] = useState({});
|
||||
const [publicUserName, setIsPublicUserName] = useState("");
|
||||
const [isViewShare, setIsViewShare] = useState({});
|
||||
const [isSubscribe, setIsSubscribe] = useState(true);
|
||||
const [reason, setReason] = useState("");
|
||||
@@ -139,7 +136,7 @@ const ReportTable = (props) => {
|
||||
checkTourStatus();
|
||||
fetchTeamList();
|
||||
return () => setCurrentPage(1);
|
||||
// eslint-disable-next-line
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
// `fetchTeamList` is used to fetch team list for share with functionality
|
||||
@@ -200,7 +197,9 @@ const ReportTable = (props) => {
|
||||
} else {
|
||||
setActLoader({ [`${item.objectId}_${act.btnId}`]: true });
|
||||
try {
|
||||
const params = { templateId: item.objectId };
|
||||
const params = {
|
||||
templateId: item.objectId
|
||||
};
|
||||
const templateDeatils = await axios.post(
|
||||
`${localStorage.getItem("baseUrl")}functions/getTemplate`,
|
||||
params,
|
||||
@@ -329,9 +328,7 @@ const ReportTable = (props) => {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
localStorage.removeItem("rowlevel");
|
||||
navigate(`/${act.redirectUrl}`);
|
||||
localStorage.setItem("rowlevel", JSON.stringify(item));
|
||||
navigate(`/${act.redirectUrl}?docId=${item?.objectId}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -370,19 +367,6 @@ const ReportTable = (props) => {
|
||||
const indexOfLastDoc = currentPage * props.docPerPage;
|
||||
const indexOfFirstDoc = indexOfLastDoc - props.docPerPage;
|
||||
const currentList = props.List?.slice(indexOfFirstDoc, indexOfLastDoc);
|
||||
// useEffect(() => {
|
||||
// // `currentLists` is total record render on current page
|
||||
// const currentList = props.List?.slice(indexOfFirstDoc, indexOfLastDoc);
|
||||
// //check public template and save in a object to show public and private template
|
||||
// // setIsPublic(
|
||||
// // currentList.reduce((acc, item) => {
|
||||
// // acc[item.objectId] = item?.IsPublic || false;
|
||||
// // return acc;
|
||||
// // }, {})
|
||||
// // );
|
||||
// setCurrentLists(currentList);
|
||||
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
// }, [indexOfLastDoc, indexOfFirstDoc]);
|
||||
|
||||
// Change page
|
||||
const paginateFront = () => setCurrentPage(currentPage + 1);
|
||||
@@ -444,19 +428,19 @@ const ReportTable = (props) => {
|
||||
setActLoader({});
|
||||
}
|
||||
};
|
||||
const handleClose = () => {
|
||||
const handleClose = (item) => {
|
||||
setIsRevoke({});
|
||||
setIsDeleteModal({});
|
||||
setIsMakePublic({});
|
||||
setSelectedPublicRole("");
|
||||
setIsPublicProfile({});
|
||||
if (item?.objectId) {
|
||||
props.setIsPublic((prevStates) => ({
|
||||
...prevStates,
|
||||
[item.objectId]: !prevStates[item.objectId]
|
||||
}));
|
||||
}
|
||||
setReason("");
|
||||
// setIsMakePublic({});
|
||||
// setSelectedPublicRole("");
|
||||
// setIsPublicProfile({});
|
||||
// if (item?.objectId) {
|
||||
// setIsPublic((prevStates) => ({
|
||||
// ...prevStates,
|
||||
// [item.objectId]: !prevStates[item.objectId]
|
||||
// }));
|
||||
// }
|
||||
};
|
||||
|
||||
const handleShare = (item) => {
|
||||
@@ -856,131 +840,148 @@ const ReportTable = (props) => {
|
||||
};
|
||||
|
||||
//function to make template public and set public role
|
||||
// const handlePublicTemplate = async (item) => {
|
||||
// if (selectedPublicRole || !isPublic[item.objectId]) {
|
||||
// setActLoader({ [item.objectId]: true });
|
||||
// setIsMakePublic(false);
|
||||
// try {
|
||||
// const res = await Parse.Cloud.run("createpublictemplate", {
|
||||
// templateid: item.objectId,
|
||||
// ispublic: isPublic[item.objectId],
|
||||
// publicrole: [selectedPublicRole]
|
||||
// });
|
||||
const handlePublicTemplate = async (item) => {
|
||||
if (selectedPublicRole || !props.isPublic[item.objectId]) {
|
||||
setActLoader({ [item.objectId]: true });
|
||||
setIsMakePublic(false);
|
||||
try {
|
||||
const res = await Parse.Cloud.run("createpublictemplate", {
|
||||
templateid: item.objectId,
|
||||
ispublic: props.isPublic[item.objectId],
|
||||
publicrole: [selectedPublicRole]
|
||||
});
|
||||
|
||||
// if (res.status === "success") {
|
||||
// setIsAlert(true);
|
||||
// setTimeout(() => setIsAlert(false), 1500);
|
||||
// if (isPublic[item.objectId]) {
|
||||
// setAlertMsg({
|
||||
// type: "success",
|
||||
// message: "You have successfully made the template public."
|
||||
// });
|
||||
// setIsCelebration(true);
|
||||
// setTimeout(() => {
|
||||
// setIsCelebration(false);
|
||||
// }, 5000);
|
||||
// setIsPublicProfile({ [item.objectId]: isPublic[item.objectId] });
|
||||
// } else {
|
||||
// setAlertMsg({
|
||||
// type: "success",
|
||||
// message: "You have successfully made the template private."
|
||||
// });
|
||||
// setSelectedPublicRole("");
|
||||
// }
|
||||
// const updateList = props.List.map((x) =>
|
||||
// x.objectId === item.objectId
|
||||
// ? { ...x, IsPublic: isPublic[item.objectId] }
|
||||
// : x
|
||||
// );
|
||||
// props.setList(updateList);
|
||||
// setActLoader({});
|
||||
// }
|
||||
// } catch (e) {
|
||||
// console.log("error in createpublictemplate", e);
|
||||
// setIsAlert(true);
|
||||
// setAlertMsg({
|
||||
// type: "danger",
|
||||
// message: "Something went wrong, Please try again later!"
|
||||
// });
|
||||
// setTimeout(() => setIsAlert(false), 1500);
|
||||
// setIsPublic((prevStates) => ({
|
||||
// ...prevStates,
|
||||
// [item.objectId]: !prevStates[item.objectId]
|
||||
// }));
|
||||
// }
|
||||
// } else {
|
||||
// setIsAlert(true);
|
||||
// setAlertMsg({
|
||||
// type: "danger",
|
||||
// message: "You need to select a role for the public signers."
|
||||
// });
|
||||
// setTimeout(() => setIsAlert(false), 1500);
|
||||
// }
|
||||
// };
|
||||
if (res.status === "success") {
|
||||
setIsAlert(true);
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
if (props.isPublic[item.objectId]) {
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: "You have successfully made the template public."
|
||||
});
|
||||
setIsCelebration(true);
|
||||
setTimeout(() => {
|
||||
setIsCelebration(false);
|
||||
}, 5000);
|
||||
setIsPublicProfile({
|
||||
[item.objectId]: props.isPublic[item.objectId]
|
||||
});
|
||||
} else {
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: "You have successfully made the template private."
|
||||
});
|
||||
setSelectedPublicRole("");
|
||||
}
|
||||
const updateList = props.List.map((x) =>
|
||||
x.objectId === item.objectId
|
||||
? { ...x, IsPublic: props.isPublic[item.objectId] }
|
||||
: x
|
||||
);
|
||||
props.setList(updateList);
|
||||
setActLoader({});
|
||||
}
|
||||
} catch (e) {
|
||||
console.log("error in createpublictemplate", e);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: "Something went wrong, Please try again later!"
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
props.setIsPublic((prevStates) => ({
|
||||
...prevStates,
|
||||
[item.objectId]: !prevStates[item.objectId]
|
||||
}));
|
||||
}
|
||||
} else {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: "You need to select a role for the public signers."
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
}
|
||||
};
|
||||
|
||||
const handleViewSigners = (item) => {
|
||||
setIsViewShare({ [item.objectId]: true });
|
||||
};
|
||||
//function to handle change template status is public or private
|
||||
// const handlePublicChange = async (e, item) => {
|
||||
// const getPlaceholder = item?.Placeholders;
|
||||
// //condiiton to check role is exist or not
|
||||
// if (getPlaceholder && getPlaceholder.length > 0) {
|
||||
// const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
||||
// placeholderObj?.placeHolder?.some((holder) =>
|
||||
// holder?.pos?.some((posItem) => posItem?.type === "signature")
|
||||
// )
|
||||
// );
|
||||
// if (checkIsSignatureExistt) {
|
||||
// let extendUser = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||
// const userName = extendUser[0]?.UserName;
|
||||
// setIsPublicUserName(extendUser[0]?.UserName);
|
||||
// //condition to check user have public url or not
|
||||
// if (userName) {
|
||||
// setIsPublic((prevStates) => ({
|
||||
// ...prevStates,
|
||||
// [item.objectId]: e.target.checked
|
||||
// }));
|
||||
// const getPlaceholder = item?.Placeholders;
|
||||
// if (getPlaceholder.length === 1) {
|
||||
// setSelectedPublicRole(getPlaceholder[0]?.Role);
|
||||
// }
|
||||
const handlePublicChange = async (e, item) => {
|
||||
const getPlaceholder = item?.Placeholders;
|
||||
//condiiton to check role is exist or not
|
||||
if (getPlaceholder && getPlaceholder.length > 0) {
|
||||
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
||||
placeholderObj?.placeHolder?.some((holder) =>
|
||||
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
||||
)
|
||||
);
|
||||
const signers = item?.Signers;
|
||||
if (getPlaceholder.length - 1 === signers?.length) {
|
||||
if (checkIsSignatureExistt) {
|
||||
let extendUser = JSON.parse(localStorage.getItem("Extand_Class"));
|
||||
const userName = extendUser[0]?.UserName;
|
||||
setIsPublicUserName(extendUser[0]?.UserName);
|
||||
//condition to check user have public url or not
|
||||
if (userName) {
|
||||
props.setIsPublic((prevStates) => ({
|
||||
...prevStates,
|
||||
[item.objectId]: e.target.checked
|
||||
}));
|
||||
const getRole = item.Placeholders.find((data) => !data.signerObjId);
|
||||
if (getRole?.Role) {
|
||||
setSelectedPublicRole(getRole?.Role);
|
||||
}
|
||||
|
||||
// setIsMakePublic({ [item.objectId]: true });
|
||||
// } else {
|
||||
// setIsPublicProfile({ [item.objectId]: true });
|
||||
// }
|
||||
// } else {
|
||||
// setIsAlert(true);
|
||||
// setAlertMsg({
|
||||
// type: "danger",
|
||||
// message:
|
||||
// " Please ensure there's at least one signature widget added for all recipients."
|
||||
// });
|
||||
// setTimeout(() => setIsAlert(false), 5000);
|
||||
// }
|
||||
// } else {
|
||||
// setIsAlert(true);
|
||||
// setAlertMsg({
|
||||
// type: "danger",
|
||||
// message: "Please assign at least one role to make this template public."
|
||||
// });
|
||||
// setTimeout(() => setIsAlert(false), 5000);
|
||||
// }
|
||||
// };
|
||||
setIsMakePublic({ [item.objectId]: true });
|
||||
} else {
|
||||
setIsPublicProfile({ [item.objectId]: true });
|
||||
}
|
||||
} else {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message:
|
||||
" Please ensure there's at least one signature widget added for all recipients."
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 5000);
|
||||
}
|
||||
} else {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message:
|
||||
"Please attach signers to all remaining users except the public role user."
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 5000);
|
||||
}
|
||||
} else {
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "danger",
|
||||
message: "Please assign at least one role to make this template public."
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 5000);
|
||||
}
|
||||
};
|
||||
|
||||
//function to copy public profile links
|
||||
// const copytoProfileLink = () => {
|
||||
// const url = `https://opensign-me.vercel.app/${publicUserName}`;
|
||||
// copytoData(url);
|
||||
// setIsAlert(true);
|
||||
// setAlertMsg({
|
||||
// type: "success",
|
||||
// message: "Copied."
|
||||
// });
|
||||
// setTimeout(() => setIsAlert(false), 1500);
|
||||
// };
|
||||
// function to copy public profile links
|
||||
const copytoProfileLink = () => {
|
||||
const url = `https://opensign.me/${publicUserName}`;
|
||||
copytoData(url);
|
||||
setIsAlert(true);
|
||||
setAlertMsg({
|
||||
type: "success",
|
||||
message: "Copied."
|
||||
});
|
||||
setTimeout(() => setIsAlert(false), 1500);
|
||||
};
|
||||
|
||||
const handleShowRole = (item) => {
|
||||
const getRole = item.Placeholders.find((data) => !data.signerObjId);
|
||||
return getRole?.Role;
|
||||
};
|
||||
// `handleShareWith` is used to save teams in sharedWith field
|
||||
const handleShareWith = async (e, template) => {
|
||||
e.preventDefault();
|
||||
@@ -1024,11 +1025,11 @@ const ReportTable = (props) => {
|
||||
</div>
|
||||
)}
|
||||
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
||||
{/* {isCelebration && (
|
||||
{isCelebration && (
|
||||
<div className="relative z-[1000]">
|
||||
<Confetti width={window.innerWidth} height={window.innerHeight} />
|
||||
</div>
|
||||
)} */}
|
||||
)}
|
||||
{isAlert && <Alert type={alertMsg.type}>{alertMsg.message}</Alert>}
|
||||
{props.tourData && props.ReportName === "Templates" && (
|
||||
<Tour
|
||||
@@ -1077,9 +1078,9 @@ const ReportTable = (props) => {
|
||||
<th className="px-4 py-2">{item}</th>
|
||||
</React.Fragment>
|
||||
))}
|
||||
{/* {props.ReportName === "Templates" && isEnableSubscription && (
|
||||
<th className="px-4 py-2">Public</th>
|
||||
)} */}
|
||||
{props.ReportName === "Templates" && isEnableSubscription && (
|
||||
<th className="px-4 py-2">Public</th>
|
||||
)}
|
||||
{props.actions?.length > 0 && (
|
||||
<th className="px-4 py-2 text-transparent pointer-events-none">
|
||||
Action
|
||||
@@ -1193,164 +1194,161 @@ const ReportTable = (props) => {
|
||||
"-"
|
||||
)}
|
||||
</td>
|
||||
{/* {props.ReportName === "Templates" &&
|
||||
isEnableSubscription && (
|
||||
<td className=" pl-[20px] py-2">
|
||||
{props.ReportName === "Templates" && (
|
||||
<div className="flex flex-row">
|
||||
<label
|
||||
className={
|
||||
"cursor-pointer relative inline-flex items-center mb-0"
|
||||
{props.ReportName === "Templates" &&
|
||||
isEnableSubscription && (
|
||||
<td className=" pl-[20px] py-2">
|
||||
{props.ReportName === "Templates" && (
|
||||
<div className="flex flex-row">
|
||||
<label
|
||||
className={
|
||||
"cursor-pointer relative inline-flex items-center mb-0"
|
||||
}
|
||||
>
|
||||
<input
|
||||
checked={props.isPublic?.[item.objectId]}
|
||||
onChange={(e) =>
|
||||
handlePublicChange(e, item)
|
||||
}
|
||||
type="checkbox"
|
||||
value=""
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-black rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-black peer-checked:bg-blue-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{isMakePublic[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={
|
||||
props.isPublic[item.objectId]
|
||||
? "Make template public"
|
||||
: "Make template private"
|
||||
}
|
||||
handleClose={() => {
|
||||
setIsMakePublic({});
|
||||
setSelectedPublicRole("");
|
||||
props.setIsPublic((prevStates) => ({
|
||||
...prevStates,
|
||||
[item.objectId]:
|
||||
!prevStates[item.objectId]
|
||||
}));
|
||||
}}
|
||||
>
|
||||
<div className="m-[20px]">
|
||||
<div className="font-normal text-black">
|
||||
<p className="text-lg">
|
||||
{props.isPublic[item.objectId]
|
||||
? `Are you sure you want to make this template public ?`
|
||||
: `Are you sure you want to make this template private ? This will remove it from your public profile ?`}
|
||||
</p>
|
||||
{props.isPublic[item.objectId] && (
|
||||
<div className="flex mt-2 gap-2 md:items-center">
|
||||
<p className="text-[15px]">
|
||||
Public role :{" "}
|
||||
</p>
|
||||
{/* {item?.Placeholders?.length > 1 ? (
|
||||
<select
|
||||
className="w-[60%] md:w-[70%] border-[1px] border-gray-200 rounded-sm p-[2px]"
|
||||
name="textvalidate"
|
||||
value={selectedPublicRole}
|
||||
onChange={(e) =>
|
||||
setSelectedPublicRole(
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
>
|
||||
<option
|
||||
disabled
|
||||
style={{ fontSize: "13px" }}
|
||||
value=""
|
||||
>
|
||||
Select...
|
||||
</option>
|
||||
{handleShowRole(item)}
|
||||
</select>
|
||||
) : ( */}
|
||||
<input
|
||||
className="op-input op-input-bordered focus:outline-none hover:border-base-content op-input-sm"
|
||||
value={handleShowRole(item)}
|
||||
/>
|
||||
{/* {item?.Placeholders[0]?.Role} */}
|
||||
{/* {handleShowRole(item)} */}
|
||||
{/* </div> */}
|
||||
{/* )} */}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-2 " />
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
onClick={() =>
|
||||
handlePublicTemplate(item)
|
||||
}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleClose(item)}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
)}
|
||||
{isPublicProfile[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={"Public URL"}
|
||||
handleClose={() => {
|
||||
setIsPublicProfile({});
|
||||
}}
|
||||
reduceWidth={
|
||||
"md:min-w-[440px] md:max-w-[550px]"
|
||||
}
|
||||
>
|
||||
<input
|
||||
checked={isPublic?.[item.objectId]}
|
||||
onChange={(e) =>
|
||||
handlePublicChange(e, item)
|
||||
}
|
||||
type="checkbox"
|
||||
value=""
|
||||
className="sr-only peer"
|
||||
/>
|
||||
<div className="w-9 h-5 bg-gray-200 peer-focus:outline-none peer-focus:ring-1 peer-focus:ring-black rounded-full peer dark:bg-gray-700 peer-checked:after:translate-x-full rtl:peer-checked:after:-translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:start-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all dark:border-black peer-checked:bg-blue-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
{isMakePublic[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={
|
||||
isPublic[item.objectId]
|
||||
? "Make template public"
|
||||
: "Make template private"
|
||||
}
|
||||
handleClose={() => {
|
||||
setIsMakePublic({});
|
||||
setSelectedPublicRole("");
|
||||
setIsPublic((prevStates) => ({
|
||||
...prevStates,
|
||||
[item.objectId]: !prevStates[item.objectId]
|
||||
}));
|
||||
}}
|
||||
>
|
||||
<div className="m-[20px]">
|
||||
<div className="font-normal text-black">
|
||||
<p className="text-lg">
|
||||
{isPublic[item.objectId]
|
||||
? `Are you sure you want to make this template public ?`
|
||||
: `Are you sure you want to make this template private ? This will remove it from your public profile ?`}
|
||||
</p>
|
||||
{isPublic[item.objectId] && (
|
||||
<div className="flex mt-2 gap-2 md:items-center">
|
||||
<p className="text-[15px]">
|
||||
Public role :{" "}
|
||||
<div className="m-[20px]">
|
||||
{publicUserName ? (
|
||||
<div className="font-normal text-black">
|
||||
<p>
|
||||
Here’s your public URL. Copy or share
|
||||
it with the signer, and you will be
|
||||
able to see all your publicly set
|
||||
templates.
|
||||
</p>
|
||||
{item?.Placeholders?.length > 1 ? (
|
||||
<select
|
||||
className="w-[60%] md:w-[70%] border-[1px] border-gray-200 rounded-sm p-[2px]"
|
||||
name="textvalidate"
|
||||
value={selectedPublicRole}
|
||||
onChange={(e) =>
|
||||
setSelectedPublicRole(
|
||||
e.target.value
|
||||
)
|
||||
}
|
||||
>
|
||||
<option
|
||||
disabled
|
||||
style={{ fontSize: "13px" }}
|
||||
value=""
|
||||
>
|
||||
Select...
|
||||
</option>
|
||||
{item?.Placeholders.map(
|
||||
(data, ind) => {
|
||||
return (
|
||||
<option
|
||||
style={{ fontSize: "13px" }}
|
||||
key={ind}
|
||||
value={data?.Role}
|
||||
>
|
||||
{data?.Role}
|
||||
</option>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</select>
|
||||
) : (
|
||||
<div className="w-[60%] md:w-[70%] border-[1px] border-gray-200 rounded-sm p-[2px]">
|
||||
{item?.Placeholders[0]?.Role}
|
||||
</div>
|
||||
)}
|
||||
<div className=" flex items-center gap-5 mt-2 p-[2px] w-[75%]">
|
||||
<span className="font-bold">
|
||||
Public URL :{" "}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => copytoProfileLink()}
|
||||
className="underline underline-offset-2 cursor-pointer"
|
||||
>{`https://opensign-me.vercel.app/${publicUserName}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="font-normal text-black">
|
||||
<p>
|
||||
Please add your public URL, and you
|
||||
will be able to make a public
|
||||
template.
|
||||
</p>
|
||||
<button
|
||||
className="mt-3 op-btn op-btn-primary"
|
||||
onClick={() => navigate("/profile")}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<hr className="bg-[#ccc] mt-2 " />
|
||||
<div className="flex items-center mt-3 gap-2 text-white">
|
||||
<button
|
||||
onClick={() => handlePublicTemplate(item)}
|
||||
className="op-btn op-btn-primary"
|
||||
>
|
||||
Submit
|
||||
</button>
|
||||
<button
|
||||
onClick={() => handleClose(item)}
|
||||
className="op-btn op-btn-secondary"
|
||||
>
|
||||
No
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</ModalUi>
|
||||
)}
|
||||
{isPublicProfile[item.objectId] && (
|
||||
<ModalUi
|
||||
isOpen
|
||||
title={"Public URL"}
|
||||
handleClose={() => {
|
||||
setIsPublicProfile({});
|
||||
}}
|
||||
reduceWidth={
|
||||
"md:min-w-[440px] md:max-w-[400px]"
|
||||
}
|
||||
>
|
||||
<div className="m-[20px]">
|
||||
{publicUserName ? (
|
||||
<div className="font-normal text-black">
|
||||
<p>
|
||||
Here’s your public URL. Copy or share it
|
||||
with the signer, and you will be able to
|
||||
see all your publicly set templates.
|
||||
</p>
|
||||
<div className=" flex items-center gap-5 mt-2 p-[2px] w-[75%]">
|
||||
<span className="font-bold">
|
||||
Public URL :{" "}
|
||||
</span>
|
||||
<span
|
||||
onClick={() => copytoProfileLink()}
|
||||
className="underline underline-offset-2 cursor-pointer"
|
||||
>{`https://opensign.me/${publicUserName}`}</span>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="font-normal text-black">
|
||||
<p>
|
||||
Please add your public URL, and you will
|
||||
be able to make a public template.
|
||||
</p>
|
||||
<button
|
||||
className="mt-3 op-btn op-btn-primary"
|
||||
onClick={() => navigate("/profile")}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</ModalUi>
|
||||
)}
|
||||
</td>
|
||||
)} */}
|
||||
</ModalUi>
|
||||
)}
|
||||
</td>
|
||||
)}
|
||||
<td className="px-2 py-2">
|
||||
<div className="text-base-content flex flex-row gap-x-2 gap-y-1 justify-start items-center">
|
||||
{props.actions?.length > 0 &&
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
import React, { useState } from "react";
|
||||
import Parse from "parse";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import PdfRequestFiles from "../pages/PdfRequestFiles";
|
||||
import { pdfjs } from "react-pdf";
|
||||
import { Provider } from "react-redux";
|
||||
import { store } from "../redux/store";
|
||||
import "../index.css";
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.min.mjs`;
|
||||
|
||||
// Wrapper component to manage props
|
||||
const PublicScriptFileWrapper = ({ initialProps }) => {
|
||||
const [props, setProps] = useState(initialProps);
|
||||
|
||||
// Make the setProps function globally accessible
|
||||
window.updatePublicTemplateProps = setProps;
|
||||
|
||||
return <PdfRequestFiles {...props} />;
|
||||
};
|
||||
|
||||
const appId = process.env.REACT_APP_APPID
|
||||
? process.env.REACT_APP_APPID
|
||||
: "opensign";
|
||||
const serverUrl = process.env.REACT_APP_SERVERURL
|
||||
? process.env.REACT_APP_SERVERURL
|
||||
: window.location.origin + "/api/app";
|
||||
localStorage.setItem("baseUrl", `${serverUrl}/`);
|
||||
localStorage.setItem("parseAppId", appId);
|
||||
Parse.initialize(appId);
|
||||
Parse.serverURL = serverUrl;
|
||||
// Create a new div element and append it to the body
|
||||
const scriptComponent = document.createElement("div");
|
||||
scriptComponent.id = "script-component";
|
||||
document.body.appendChild(scriptComponent);
|
||||
const link = document.createElement("link");
|
||||
link.href = `${process.env.PUBLIC_URL}/css/fonts.css`;
|
||||
link.rel = "stylesheet";
|
||||
document.head.appendChild(link);
|
||||
|
||||
// Create a root and render the wrapper component with initial props
|
||||
const root = ReactDOM.createRoot(document.getElementById("script-component"));
|
||||
root.render(
|
||||
<div>
|
||||
<Provider store={store}>
|
||||
<PublicScriptFileWrapper initialProps={{ text: "templateId" }} />
|
||||
</Provider>
|
||||
</div>
|
||||
);
|
||||
@@ -60,8 +60,8 @@ module.exports = {
|
||||
"success-content": "#f5f5f4",
|
||||
warning: "#ffbe00",
|
||||
"warning-content": "#ccd9e8",
|
||||
error: "#ff0000",
|
||||
"error-content": "#f3f4f6",
|
||||
error: "#ffa1a7",
|
||||
"error-content": "#16090a",
|
||||
"--rounded-btn": "1.9rem",
|
||||
"--tab-border": "2px",
|
||||
"--tab-radius": "0.7rem"
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
const path = require("path");
|
||||
const Dotenv = require("dotenv-webpack");
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); //used to clean directory
|
||||
const TerserPlugin = require("terser-webpack-plugin"); //used to minify and optimize JavaScript files
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //used to extract css file into separate files
|
||||
|
||||
const isProduction = process.env.NODE_ENV;
|
||||
module.exports = {
|
||||
mode: isProduction ? "production" : "development",
|
||||
entry: "./src/script/PublicTemplate.js",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "public", "static", "js"),
|
||||
filename: "public-template.bundle.js",
|
||||
libraryTarget: "umd",
|
||||
umdNamedDefine: true,
|
||||
library: "PublicTemplate",
|
||||
globalObject: "this"
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
exclude: /node_modules/,
|
||||
use: {
|
||||
loader: "babel-loader",
|
||||
options: {
|
||||
presets: ["@babel/preset-react"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: [
|
||||
isProduction ? MiniCssExtractPlugin.loader : "style-loader",
|
||||
"css-loader",
|
||||
"postcss-loader"
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: "file-loader",
|
||||
options: {
|
||||
name: "assets/images/[name].[hash].[ext]"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".js", ".jsx"]
|
||||
},
|
||||
plugins: [
|
||||
new Dotenv(),
|
||||
new CleanWebpackPlugin(),
|
||||
...(isProduction
|
||||
? [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].[contenthash].css"
|
||||
})
|
||||
]
|
||||
: [])
|
||||
],
|
||||
optimization: {
|
||||
minimize: isProduction,
|
||||
minimizer: [new TerserPlugin()]
|
||||
},
|
||||
devtool: isProduction ? "source-map" : "inline-source-map"
|
||||
};
|
||||
@@ -48,6 +48,7 @@ import getUserByOrg from './parsefunction/getUserByOrg.js';
|
||||
import getUserListByOrg from './parsefunction/getUserListByOrg.js';
|
||||
import TeamsAftersave from './parsefunction/TeamsAftersave.js';
|
||||
import SubscriptionAftersave from './parsefunction/SubscriptionAftersave.js';
|
||||
import PublicUserLinkContactToDoc from './parsefunction/PublicUserLinkContactToDoc.js';
|
||||
|
||||
// This afterSave function triggers after an object is added or updated in the specified class, allowing for post-processing logic.
|
||||
Parse.Cloud.afterSave('contracts_Document', DocumentAftersave);
|
||||
@@ -105,3 +106,4 @@ Parse.Cloud.define('ssosign', ssoSignin);
|
||||
Parse.Cloud.define('isextenduser', isextenduser);
|
||||
Parse.Cloud.define('getuserbyorg', getUserByOrg);
|
||||
Parse.Cloud.define('getuserlistbyorg', getUserListByOrg);
|
||||
Parse.Cloud.define('publicuserlinkcontacttodoc', PublicUserLinkContactToDoc);
|
||||
|
||||
@@ -21,7 +21,23 @@ async function AuthLoginAsMail(request) {
|
||||
|
||||
if (resOtp === otp) {
|
||||
var result = await getToken(request);
|
||||
return result;
|
||||
if (result && !result?.emailVerified) {
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const user = await userQuery.get(result?.objectId, {
|
||||
sessionToken: result.sessionToken,
|
||||
});
|
||||
// Update the emailVerified field to true
|
||||
user.set('emailVerified', true);
|
||||
// Save the user object
|
||||
const res = await user.save(null, { useMasterKey: true });
|
||||
if (res) {
|
||||
return result;
|
||||
} else {
|
||||
reject('user not found!');
|
||||
}
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
|
||||
async function getToken(request) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
@@ -56,6 +72,7 @@ async function AuthLoginAsMail(request) {
|
||||
.catch(err => {
|
||||
reject('user not found!');
|
||||
});
|
||||
|
||||
// user couldn't find lets sign up!
|
||||
})
|
||||
.catch(() => {
|
||||
|
||||
@@ -4,8 +4,12 @@ async function GetPublicTemplate(request) {
|
||||
if (username) {
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('UserName', username);
|
||||
const res = await extUserQuery.first({ useMasterKey: true });
|
||||
const userId = res.get('UserId').id;
|
||||
const userRes = await extUserQuery.first({ useMasterKey: true });
|
||||
const userId = userRes.get('UserId').id;
|
||||
|
||||
//get _user details
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
const user = await userQuery.get(userId, { useMasterKey: true });
|
||||
if (userId) {
|
||||
const templatQuery = new Parse.Query('contracts_Template');
|
||||
templatQuery.equalTo('CreatedBy', {
|
||||
@@ -13,11 +17,20 @@ async function GetPublicTemplate(request) {
|
||||
className: '_User',
|
||||
objectId: userId,
|
||||
});
|
||||
templatQuery.descending('updatedAt');
|
||||
templatQuery.equalTo('IsPublic', true);
|
||||
const getTemplate = await templatQuery.find({ useMasterKey: true });
|
||||
return getTemplate;
|
||||
|
||||
const extend_Res = await Parse.Cloud.run('getUserDetails', {
|
||||
email: user.get('email'),
|
||||
});
|
||||
if (extend_Res) {
|
||||
return { template: getTemplate, user: user, extend_User: extend_Res };
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found');
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User does not exist');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!');
|
||||
|
||||
@@ -3,55 +3,74 @@ import axios from 'axios';
|
||||
export default async function GetTemplate(request) {
|
||||
const serverUrl = process.env.SERVER_URL;
|
||||
const templateId = request.params.templateId;
|
||||
const ispublic = request.params.ispublic;
|
||||
|
||||
try {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
// console.log("templateId ", templateId)
|
||||
// console.log("userId ",userId)
|
||||
if (templateId && userId) {
|
||||
if (!ispublic) {
|
||||
const userRes = await axios.get(serverUrl + '/users/me', {
|
||||
headers: {
|
||||
'X-Parse-Application-Id': process.env.APP_ID,
|
||||
'X-Parse-Session-Token': request.headers['sessiontoken'],
|
||||
},
|
||||
});
|
||||
const userId = userRes.data && userRes.data.objectId;
|
||||
if (templateId && userId) {
|
||||
try {
|
||||
let template = new Parse.Query('contracts_Template');
|
||||
template.equalTo('objectId', templateId);
|
||||
template.include('ExtUserPtr');
|
||||
template.include('Signers');
|
||||
template.include('CreatedBy');
|
||||
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('Email', userRes.data.email);
|
||||
extUserQuery.include('TeamIds');
|
||||
const extUser = await extUserQuery.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
if (_extUser?.TeamIds && _extUser.TeamIds?.length > 0) {
|
||||
let teamsArr = [];
|
||||
_extUser?.TeamIds?.forEach(x => (teamsArr = [...teamsArr, ...x.Ancestors]));
|
||||
// Create the first query
|
||||
const sharedWithQuery = new Parse.Query('contracts_Template');
|
||||
sharedWithQuery.containedIn('SharedWith', teamsArr);
|
||||
|
||||
// Create the second query
|
||||
const createdByQuery = new Parse.Query('contracts_Template');
|
||||
createdByQuery.equalTo('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
template = Parse.Query.or(sharedWithQuery, createdByQuery);
|
||||
template.equalTo('objectId', templateId);
|
||||
template.include('ExtUserPtr');
|
||||
template.include('Signers');
|
||||
template.include('CreatedBy');
|
||||
}
|
||||
}
|
||||
const res = await template.first({ useMasterKey: true });
|
||||
if (res) {
|
||||
// console.log("res ",res)
|
||||
return res;
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err', err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
} else if (templateId && ispublic) {
|
||||
try {
|
||||
let template = new Parse.Query('contracts_Template');
|
||||
const template = new Parse.Query('contracts_Template');
|
||||
template.equalTo('objectId', templateId);
|
||||
template.include('ExtUserPtr');
|
||||
template.include('Signers');
|
||||
template.include('CreatedBy');
|
||||
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('Email', userRes.data.email);
|
||||
extUserQuery.include('TeamIds');
|
||||
const extUser = await extUserQuery.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
if (_extUser?.TeamIds && _extUser.TeamIds?.length > 0) {
|
||||
let teamsArr = [];
|
||||
_extUser?.TeamIds?.forEach(x => (teamsArr = [...teamsArr, ...x.Ancestors]));
|
||||
// Create the first query
|
||||
const sharedWithQuery = new Parse.Query('contracts_Template');
|
||||
sharedWithQuery.containedIn('SharedWith', teamsArr);
|
||||
|
||||
// Create the second query
|
||||
const createdByQuery = new Parse.Query('contracts_Template');
|
||||
createdByQuery.equalTo('ExtUserPtr', {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Users',
|
||||
objectId: extUser.id,
|
||||
});
|
||||
template = Parse.Query.or(sharedWithQuery, createdByQuery);
|
||||
template.equalTo('objectId', templateId);
|
||||
template.include('ExtUserPtr');
|
||||
template.include('Signers');
|
||||
template.include('CreatedBy');
|
||||
}
|
||||
}
|
||||
const res = await template.first({ useMasterKey: true });
|
||||
// console.log("res ", res)
|
||||
if (res) {
|
||||
// console.log("res ",res)
|
||||
return res;
|
||||
} else {
|
||||
return { error: "You don't have access of this document!" };
|
||||
|
||||
@@ -0,0 +1,218 @@
|
||||
// `saveRoleContact` is used to save user in contracts_Guest role and create contact
|
||||
const saveRoleContact = async contact => {
|
||||
try {
|
||||
const Role = new Parse.Query(Parse.Role);
|
||||
const guestRole = await Role.equalTo('name', 'contracts_Guest').first();
|
||||
if (guestRole) {
|
||||
// Check if the user is already in the role
|
||||
const relation = guestRole.relation('users');
|
||||
const usersInRoleQuery = relation.query();
|
||||
usersInRoleQuery.equalTo('objectId', contact.UserId.objectId);
|
||||
const usersInRole = await usersInRoleQuery.find();
|
||||
if (usersInRole.length > 0) {
|
||||
console.log('User already added to Guest role.');
|
||||
} else {
|
||||
relation.add({ __type: 'Pointer', className: '_User', id: contact.UserId.objectId });
|
||||
await guestRole.save(null, { useMasterKey: true });
|
||||
// console.log('User added to Guest role successfully.');
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in role save', err);
|
||||
}
|
||||
const contactQuery = new Parse.Object('contracts_Contactbook');
|
||||
contactQuery.set('Name', contact.Name);
|
||||
contactQuery.set('Email', contact.Email);
|
||||
if (contact?.Phone) {
|
||||
contactQuery.set('Phone', contact.Phone);
|
||||
}
|
||||
contactQuery.set('CreatedBy', contact.CreatedBy);
|
||||
contactQuery.set('UserId', contact.UserId);
|
||||
contactQuery.set('UserRole', 'contracts_Guest');
|
||||
contactQuery.set('TenantId', contact.TenantId);
|
||||
contactQuery.set('IsDeleted', false);
|
||||
const acl = new Parse.ACL();
|
||||
acl.setReadAccess(contact.CreatedBy.objectId, true);
|
||||
acl.setWriteAccess(contact.CreatedBy.objectId, true);
|
||||
acl.setReadAccess(contact.UserId.objectId, true);
|
||||
acl.setWriteAccess(contact.UserId.objectId, true);
|
||||
contactQuery.setACL(acl);
|
||||
const contactRes = await contactQuery.save();
|
||||
if (contactRes) {
|
||||
return contactRes;
|
||||
}
|
||||
};
|
||||
|
||||
// `createDocumentFromTemplate` is used to create document from template
|
||||
const createDocumentFromTemplate = async (template, existContact, index) => {
|
||||
try {
|
||||
if (template) {
|
||||
const Doc = JSON.parse(JSON.stringify(template));
|
||||
//update contact in placeholder, signers and update ACl in provide document
|
||||
const object = new Parse.Object('contracts_Document');
|
||||
object.set('Name', Doc?.Name);
|
||||
object.set('Description', Doc?.Description);
|
||||
object.set('Note', Doc?.Note);
|
||||
object.set('TimeToCompleteDays', Doc.TimeToCompleteDays || 15);
|
||||
object.set('SendinOrder', Doc?.SendinOrder);
|
||||
object.set('AutomaticReminders', Doc.AutomaticReminders);
|
||||
object.set('RemindOnceInEvery', Doc?.RemindOnceInEvery);
|
||||
object.set('URL', Doc?.URL);
|
||||
object.set('CreatedBy', Doc?.CreatedBy);
|
||||
object.set('ExtUserPtr', Doc?.ExtUserPtr);
|
||||
let signers = Doc?.Signers || [];
|
||||
const signerobj = {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: existContact.id,
|
||||
};
|
||||
signers = [...signers.slice(0, index), signerobj, ...signers.slice(index)];
|
||||
object.set('Signers', signers);
|
||||
object.set('SignedUrl', Doc.URL || Doc.SignedUrl);
|
||||
const Placeholders = Doc?.Placeholders || [];
|
||||
Placeholders[index] = {
|
||||
...Placeholders[index],
|
||||
signerObjId: existContact.id,
|
||||
signerPtr: {
|
||||
__type: 'Pointer',
|
||||
className: 'contracts_Contactbook',
|
||||
objectId: existContact.id,
|
||||
},
|
||||
};
|
||||
object.set('Placeholders', Placeholders);
|
||||
const resDoc = await object.save(null, { useMasterKey: true });
|
||||
return resDoc;
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in create document from template', err);
|
||||
}
|
||||
};
|
||||
|
||||
// `PublicUserLinkContactToDoc` cloud function is used to create contact, add this contact in contracts_Guest role and
|
||||
// create new document from template and save contact pointer in placeholder, signers and ACL of Document
|
||||
export default async function PublicUserLinkContactToDoc(req) {
|
||||
const email = req.params.email;
|
||||
const templateid = req.params.templateid;
|
||||
const name = req.params.name;
|
||||
const phone = req.params.phone;
|
||||
const role = req.params.role;
|
||||
try {
|
||||
if (templateid) {
|
||||
// Execute the query to get the template with the specified 'templateid'
|
||||
const docQuery = new Parse.Query('contracts_Template');
|
||||
docQuery.include('ExtUserPtr');
|
||||
const tempRes = await docQuery.get(templateid, { useMasterKey: true });
|
||||
// Check if the template was found; if not, throw an error indicating the template was not found
|
||||
if (!tempRes) {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.');
|
||||
}
|
||||
const _tempRes = JSON.parse(JSON.stringify(tempRes));
|
||||
const Placeholders = _tempRes?.Placeholders || [];
|
||||
let index;
|
||||
if (role) {
|
||||
index = Placeholders?.findIndex(x => x.Role && x.Role === role);
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, '');
|
||||
}
|
||||
if (index !== -1) {
|
||||
// Execute the query to check if a contact already exists in the 'contracts_Contactbook' class
|
||||
const contactCls = new Parse.Query('contracts_Contactbook');
|
||||
contactCls.equalTo('Email', email);
|
||||
contactCls.equalTo('CreatedBy', _tempRes.CreatedBy);
|
||||
contactCls.notEqualTo('IsDeleted', true);
|
||||
const existContact = await contactCls.first({ useMasterKey: true });
|
||||
if (existContact) {
|
||||
//update contact in placeholder, signers and update ACl in provide document
|
||||
const docRes = await createDocumentFromTemplate(tempRes, existContact, index);
|
||||
if (docRes) {
|
||||
return { contactId: existContact.id, docId: docRes.id };
|
||||
}
|
||||
} else {
|
||||
// Execute the query to check if a user already exists in the 'contracts_Users' class
|
||||
const extUserQuery = new Parse.Query('contracts_Users');
|
||||
extUserQuery.equalTo('Email', email);
|
||||
const extUser = await extUserQuery.first({ useMasterKey: true });
|
||||
if (extUser) {
|
||||
const _extUser = JSON.parse(JSON.stringify(extUser));
|
||||
const contact = {
|
||||
UserId: _extUser.UserId,
|
||||
Name: _extUser.Name,
|
||||
Email: email,
|
||||
Phone: _extUser?.Phone ? _extUser.Phone : '',
|
||||
CreatedBy: _tempRes.CreatedBy,
|
||||
TenantId: _tempRes.ExtUserPtr.TenantId,
|
||||
};
|
||||
// if user present on platform create contact on the basis of extended user details
|
||||
const contactRes = await saveRoleContact(contact);
|
||||
const docRes = await createDocumentFromTemplate(tempRes, contactRes, index);
|
||||
if (docRes) {
|
||||
return { contactId: contactRes.id, docId: docRes.id };
|
||||
}
|
||||
} else if (name) {
|
||||
try {
|
||||
// Execute the query to check if a user already exists in the '_User' class
|
||||
const userQuery = new Parse.Query(Parse.User);
|
||||
userQuery.equalTo('email', email);
|
||||
const userRes = await userQuery.first({ useMasterKey: true });
|
||||
if (userRes) {
|
||||
const contact = {
|
||||
UserId: { __type: 'Pointer', className: '_User', objectId: userRes.id },
|
||||
Name: name,
|
||||
Email: email,
|
||||
Phone: phone,
|
||||
CreatedBy: _tempRes.CreatedBy,
|
||||
TenantId: _tempRes.ExtUserPtr.TenantId,
|
||||
};
|
||||
// Create new contract on the basis provided contact details by user and userId from _User class
|
||||
const contactRes = await saveRoleContact(contact);
|
||||
//update contact in placeholder, signers and update ACl in provide document
|
||||
const docRes = await createDocumentFromTemplate(tempRes, contactRes, index);
|
||||
if (docRes) {
|
||||
return { contactId: contactRes.id, docId: docRes.id };
|
||||
}
|
||||
} else {
|
||||
// create new user in _User class on the basis of details provide by user
|
||||
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 newUserRes = await _user.save();
|
||||
const contact = {
|
||||
UserId: { __type: 'Pointer', className: '_User', objectId: newUserRes.id },
|
||||
Name: name,
|
||||
Email: email,
|
||||
Phone: phone,
|
||||
CreatedBy: _tempRes.CreatedBy,
|
||||
TenantId: _tempRes.ExtUserPtr.TenantId,
|
||||
};
|
||||
// Create new contract on the basis provided contact details by user and userId from _User class
|
||||
const contactRes = await saveRoleContact(contact);
|
||||
//update contact in placeholder, signers and update ACl in provide document
|
||||
const docRes = await createDocumentFromTemplate(tempRes, contactRes, index);
|
||||
if (docRes) {
|
||||
return { contactId: contactRes.id, docId: docRes.id };
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Err', err);
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'User not found.');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Please provide required parameters!');
|
||||
}
|
||||
} else {
|
||||
throw new Parse.Error(Parse.Error.OBJECT_NOT_FOUND, 'Template not found.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('err in publicuserlinkcontacttodoc', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
*
|
||||
* @param {Parse} Parse
|
||||
*/
|
||||
exports.up = async Parse => {
|
||||
// TODO: set className here
|
||||
const className = 'contracts_Users';
|
||||
const schema = new Parse.Schema(className);
|
||||
schema.addString('UserName');
|
||||
schema.addString('Tagline');
|
||||
schema.addBoolean('SearchIndex');
|
||||
// TODO: Set the schema here
|
||||
// Example:
|
||||
// schema.addString('name').addNumber('cash');
|
||||
|
||||
return schema.update();
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {Parse} Parse
|
||||
*/
|
||||
exports.down = async Parse => {
|
||||
// TODO: set className here
|
||||
const className = 'contracts_Users';
|
||||
const schema = new Parse.Schema(className);
|
||||
schema.deleteField('UserName');
|
||||
schema.deleteField('Tagline');
|
||||
schema.deleteField('SearchIndex');
|
||||
// TODO: Set the schema here
|
||||
// Example:
|
||||
// schema.deleteField('name').deleteField('cash');
|
||||
|
||||
return schema.update();
|
||||
};
|
||||
Reference in New Issue
Block a user