remove microfrontend and update package-lock file
@@ -1,23 +0,0 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/mfbuild
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -1,70 +0,0 @@
|
||||
# Getting Started with Create React App
|
||||
|
||||
This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm start`
|
||||
|
||||
Runs the app in the development mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in your browser.
|
||||
|
||||
The page will reload when you make changes.\
|
||||
You may also see any lint errors in the console.
|
||||
|
||||
### `npm test`
|
||||
|
||||
Launches the test runner in the interactive watch mode.\
|
||||
See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
|
||||
|
||||
### `npm run build`
|
||||
|
||||
Builds the app for production to the `build` folder.\
|
||||
It correctly bundles React in production mode and optimizes the build for the best performance.
|
||||
|
||||
The build is minified and the filenames include the hashes.\
|
||||
Your app is ready to be deployed!
|
||||
|
||||
See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
|
||||
|
||||
### `npm run eject`
|
||||
|
||||
**Note: this is a one-way operation. Once you `eject`, you can't go back!**
|
||||
|
||||
If you aren't satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
|
||||
|
||||
Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you're on your own.
|
||||
|
||||
You don't have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn't feel obligated to use this feature. However we understand that this tool wouldn't be useful if you couldn't customize it when you are ready for it.
|
||||
|
||||
## Learn More
|
||||
|
||||
You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
|
||||
|
||||
To learn React, check out the [React documentation](https://reactjs.org/).
|
||||
|
||||
### Code Splitting
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting)
|
||||
|
||||
### Analyzing the Bundle Size
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size)
|
||||
|
||||
### Making a Progressive Web App
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app)
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration)
|
||||
|
||||
### Deployment
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment)
|
||||
|
||||
### `npm run build` fails to minify
|
||||
|
||||
This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify)
|
||||
@@ -1,29 +0,0 @@
|
||||
const { dependencies } = require("./package.json");
|
||||
|
||||
module.exports = {
|
||||
name: "signmicroapp", // change me
|
||||
filename: "remoteEntry.js",
|
||||
exposes: {
|
||||
// key e.g"./AppRoutes" is path which will use as moduletoload in host app
|
||||
// value e.g"./src/Routes" is path which will as a bind path to load
|
||||
|
||||
"./AppRoutes": "./src/Routes",
|
||||
},
|
||||
shared: {
|
||||
...dependencies,
|
||||
react: {
|
||||
singleton: true,
|
||||
import: "react", // fallback is also react
|
||||
shareScope: "default",
|
||||
requiredVersion: dependencies.react,
|
||||
},
|
||||
"react-dom": {
|
||||
singleton: true,
|
||||
requiredVersion: dependencies["react-dom"],
|
||||
},
|
||||
"react-router-dom": {
|
||||
singleton: true,
|
||||
requiredVersion: dependencies["react-router-dom"],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -1,62 +0,0 @@
|
||||
{
|
||||
"name": "signmicroapp",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"homepage": "./mfbuild",
|
||||
"dependencies": {
|
||||
"@radix-ui/themes": "^1.1.2",
|
||||
"@react-pdf/renderer": "^3.1.9",
|
||||
"@testing-library/jest-dom": "^5.17.0",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
"axios": "^1.5.1",
|
||||
"file-saver": "^2.0.5",
|
||||
"gh-pages": "^6.0.0",
|
||||
"mf-cra": "^0.0.5",
|
||||
"parse": "^4.2.0",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"print-js": "^1.6.0",
|
||||
"radix-ui": "^1.0.1",
|
||||
"react": "^18.2.0",
|
||||
"react-bootstrap": "^2.9.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dnd-multi-backend": "^8.0.3",
|
||||
"react-dnd-touch-backend": "^16.0.1",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-draggable": "^4.4.6",
|
||||
"react-pdf": "^7.4.0",
|
||||
"react-rnd": "^10.4.1",
|
||||
"react-router-dom": "^6.16.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-scrollbars-custom": "^4.1.1",
|
||||
"react-signature-canvas": "^1.0.6",
|
||||
"reactour": "^1.19.1",
|
||||
"select-dom": "^9.0.0",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "mf-cra start",
|
||||
"build": "CI=false && PUBLIC_URL=./mfbuild BUILD_PATH='./mfbuild' mf-cra build && mv mfbuild ../../apps/OpenSign/public",
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"react-app",
|
||||
"react-app/jest"
|
||||
]
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
">0.2%",
|
||||
"not dead",
|
||||
"not op_mini all"
|
||||
],
|
||||
"development": [
|
||||
"last 1 chrome version",
|
||||
"last 1 firefox version",
|
||||
"last 1 safari version"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.8 KiB |
@@ -1,81 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<!-- <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> -->
|
||||
<link
|
||||
rel="icon"
|
||||
type="image/png"
|
||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC"
|
||||
sizes="40x40"
|
||||
/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
|
||||
integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
|
||||
integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf"
|
||||
crossorigin="anonymous"
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css"
|
||||
/>
|
||||
|
||||
<title>OpenSign™</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!-- <script
|
||||
src="https://code.jquery.com/jquery-3.2.1.slim.min.js"
|
||||
integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
|
||||
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
|
||||
crossorigin="anonymous"
|
||||
></script>
|
||||
<script
|
||||
src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
|
||||
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
|
||||
crossorigin="anonymous"
|
||||
></script> -->
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
Before Width: | Height: | Size: 5.2 KiB |
|
Before Width: | Height: | Size: 9.4 KiB |
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
},
|
||||
{
|
||||
"src": "logo192.png",
|
||||
"type": "image/png",
|
||||
"sizes": "192x192"
|
||||
},
|
||||
{
|
||||
"src": "logo512.png",
|
||||
"type": "image/png",
|
||||
"sizes": "512x512"
|
||||
}
|
||||
],
|
||||
"start_url": ".",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -1,51 +0,0 @@
|
||||
import React from "react";
|
||||
import { HashRouter } from "react-router-dom";
|
||||
import AppRoutes from "./Routes";
|
||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||
import { TouchBackend } from "react-dnd-touch-backend";
|
||||
import {
|
||||
DndProvider,
|
||||
TouchTransition,
|
||||
MouseTransition,
|
||||
Preview
|
||||
} from "react-dnd-multi-backend";
|
||||
import DragElement from "./Component/component/DragElement";
|
||||
export default function App() {
|
||||
const HTML5toTouch = {
|
||||
backends: [
|
||||
{
|
||||
id: "html5",
|
||||
backend: HTML5Backend,
|
||||
transition: MouseTransition,
|
||||
},
|
||||
{
|
||||
id: "touch",
|
||||
backend: TouchBackend,
|
||||
options: { enableMouseEvents: true },
|
||||
preview: true,
|
||||
transition: TouchTransition,
|
||||
},
|
||||
],
|
||||
};
|
||||
const generatePreview = (props) => {
|
||||
const { item, style } = props;
|
||||
const newStyle = {
|
||||
...style,
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={newStyle}>
|
||||
<DragElement {...item} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<DndProvider options={HTML5toTouch}>
|
||||
<Preview>{generatePreview}</Preview>
|
||||
<HashRouter>
|
||||
<AppRoutes />
|
||||
</HashRouter>
|
||||
</DndProvider>
|
||||
);
|
||||
}
|
||||
@@ -1,277 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import "./certificate.css";
|
||||
import opensignLogo from "../../assests/open-sign-logo.png";
|
||||
|
||||
import {
|
||||
Page,
|
||||
Text,
|
||||
View,
|
||||
Document,
|
||||
StyleSheet,
|
||||
Image
|
||||
} from "@react-pdf/renderer";
|
||||
|
||||
function Certificate({ pdfData }) {
|
||||
const [isMultiSigners, setIsMultiSigners] = useState();
|
||||
const [multiSigner, setMultiSigners] = useState([]);
|
||||
const [isLoad, setIsLoad] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
handleSignerData();
|
||||
}, []);
|
||||
|
||||
const handleSignerData = () => {
|
||||
const checkSigners = pdfData.filter((data) => data.Signers);
|
||||
if (checkSigners && checkSigners.length > 0) {
|
||||
setIsMultiSigners(true);
|
||||
|
||||
const checkSignSigners =
|
||||
pdfData[0].AuditTrail &&
|
||||
pdfData[0].AuditTrail.length > 0 &&
|
||||
pdfData[0].AuditTrail.filter((data) => data.Activity === "Signed");
|
||||
|
||||
setMultiSigners(checkSignSigners);
|
||||
} else {
|
||||
setIsMultiSigners(false);
|
||||
}
|
||||
setIsLoad(true);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
page: {
|
||||
borderRadius: "5px",
|
||||
padding: "10px",
|
||||
backgroundColor: "white"
|
||||
},
|
||||
section1: {
|
||||
border: "1px solid rgb(177, 174, 174)",
|
||||
padding: "20px"
|
||||
},
|
||||
textStyle: {
|
||||
fontWeight: "bold",
|
||||
fontSize: "11px",
|
||||
marginBottom: "10px"
|
||||
},
|
||||
textStyle2: {
|
||||
fontWeight: "600",
|
||||
fontSize: "11px",
|
||||
marginBottom: "10px",
|
||||
color: "gray"
|
||||
},
|
||||
image: {
|
||||
width: "71px",
|
||||
height: "17px"
|
||||
}
|
||||
});
|
||||
|
||||
const generatedDate = () => {
|
||||
const newDate = new Date();
|
||||
const utcTime = newDate.toUTCString();
|
||||
|
||||
return (
|
||||
<Text
|
||||
style={{
|
||||
color: "gray",
|
||||
fontSize: "10px"
|
||||
}}
|
||||
>
|
||||
Generated On {utcTime}
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
const changeCompletedDate = () => {
|
||||
const completedOn = pdfData[0].updatedAt;
|
||||
const newDate = new Date(completedOn);
|
||||
const utcTime = newDate.toUTCString();
|
||||
|
||||
return <Text style={styles.textStyle2}>{utcTime}</Text>;
|
||||
};
|
||||
|
||||
const signerName = (data) => {
|
||||
const getSignerName = pdfData[0].Signers.filter(
|
||||
(sign) => sign.objectId === data.UserPtr.objectId
|
||||
);
|
||||
|
||||
return (
|
||||
getSignerName[0] &&
|
||||
getSignerName.length > 0 && (
|
||||
<>
|
||||
<Text style={styles.textStyle}>
|
||||
Name :
|
||||
<Text style={styles.textStyle2}>{getSignerName[0].Name}</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Email :
|
||||
<Text style={styles.textStyle2}>{getSignerName[0].Email}</Text>
|
||||
</Text>
|
||||
</>
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
isLoad && (
|
||||
<Document>
|
||||
{/** Page defines a single page of content. */}
|
||||
<Page size="A4" style={styles.page}>
|
||||
<View style={styles.section1}>
|
||||
<View
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
alignItems: "center",
|
||||
marginBottom: "30px"
|
||||
}}
|
||||
>
|
||||
<Image src={opensignLogo} style={styles.image} />
|
||||
{generatedDate()}
|
||||
</View>
|
||||
|
||||
<View style={{ justifyContent: "center" }}>
|
||||
<Text
|
||||
style={{
|
||||
textAlign: "center",
|
||||
fontSize: "20px",
|
||||
fontWeight: "bold",
|
||||
color: "#31bceb",
|
||||
marginBottom: "10px"
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
Certificate of Completion
|
||||
</Text>
|
||||
<View style={{ border: "1px solid #bdbbbb" }}></View>
|
||||
<View>
|
||||
<View>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
fontWeight: "bold",
|
||||
color: "#31bceb",
|
||||
margin: "10px 0px 10px 0px"
|
||||
}}
|
||||
>
|
||||
Summary
|
||||
</Text>
|
||||
</View>
|
||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
||||
<Text style={styles.textStyle}>
|
||||
Document ID :
|
||||
<Text style={styles.textStyle2}>{pdfData[0].objectId}</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Document Name :
|
||||
<Text style={styles.textStyle2}>{pdfData[0].Name}</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Organization :
|
||||
<Text style={styles.textStyle2}>
|
||||
{pdfData[0].ExtUserPtr.Company}
|
||||
</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Completed on : {changeCompletedDate()}
|
||||
</Text>
|
||||
{multiSigner && multiSigner.length > 0 && (
|
||||
<Text style={styles.textStyle}>
|
||||
Signers :
|
||||
<Text style={styles.textStyle2}>
|
||||
{multiSigner.length}
|
||||
</Text>
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
{isMultiSigners ? (
|
||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
fontWeight: "bold",
|
||||
color: "#31bceb",
|
||||
margin: "10px 0px 10px 0px"
|
||||
}}
|
||||
>
|
||||
Recipients
|
||||
</Text>
|
||||
|
||||
<View>
|
||||
{multiSigner &&
|
||||
multiSigner.map((data, ind) => {
|
||||
return (
|
||||
<View
|
||||
key={ind}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
border: "0.4px solid #bdbbbb",
|
||||
marginBottom: "10px"
|
||||
}}
|
||||
></View>
|
||||
{signerName(data)}
|
||||
|
||||
<Text style={styles.textStyle}>
|
||||
Accessed from :
|
||||
<Text style={styles.textStyle2}>
|
||||
{data.ipAddress}
|
||||
</Text>
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
</View>
|
||||
) : (
|
||||
<View style={{ display: "flex", flexDirection: "column" }}>
|
||||
<Text
|
||||
style={{
|
||||
fontSize: "16px",
|
||||
fontWeight: "bold",
|
||||
color: "#31bceb",
|
||||
margin: "10px 0px 10px 0px"
|
||||
}}
|
||||
>
|
||||
Recipients
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Signers : <Text style={styles.textStyle2}>1</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Name :
|
||||
<Text style={styles.textStyle2}>
|
||||
{pdfData[0].ExtUserPtr.Name}
|
||||
</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Email :
|
||||
<Text style={styles.textStyle2}>
|
||||
{pdfData[0].ExtUserPtr.Email}
|
||||
</Text>
|
||||
</Text>
|
||||
<Text style={styles.textStyle}>
|
||||
Accessed from :
|
||||
<Text style={styles.textStyle2}>
|
||||
{pdfData[0].AuditTrail &&
|
||||
pdfData[0].AuditTrail[0].ipAddress}
|
||||
</Text>
|
||||
</Text>
|
||||
|
||||
<Text style={styles.textStyle}>
|
||||
Signed on : {changeCompletedDate()}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
</Page>
|
||||
</Document>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default Certificate;
|
||||
@@ -1,9 +0,0 @@
|
||||
.containerBox {
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.certificateBox {
|
||||
border: 1px solid rgb(177, 174, 174);
|
||||
padding: 20px;
|
||||
}
|
||||
@@ -1,119 +0,0 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Loader from "./component/loader";
|
||||
import { contractDocument, getHostUrl } from "../utils/Utils";
|
||||
function DraftDocument() {
|
||||
const navigate = useNavigate();
|
||||
const [pdfDetails, setPdfDetails] = useState([]);
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoad: 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(() => {
|
||||
if (docId) {
|
||||
getDocumentDetails();
|
||||
}
|
||||
}, []);
|
||||
|
||||
//get document details
|
||||
const getDocumentDetails = async () => {
|
||||
//getting document details
|
||||
const documentData = await contractDocument(docId);
|
||||
if (documentData && documentData.length > 0) {
|
||||
setPdfDetails(documentData);
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
} else if (
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(documentData.result && documentData.result.error)
|
||||
) {
|
||||
alert("Error: Something went wrong!");
|
||||
} else {
|
||||
alert("No data found!");
|
||||
}
|
||||
};
|
||||
|
||||
//check document type and render on signyour self and placeholder route
|
||||
const handleDraftDoc = () => {
|
||||
const data = pdfDetails[0];
|
||||
const checkSignerExist =
|
||||
pdfDetails[0] && pdfDetails[0].Signers && pdfDetails[0].Signers;
|
||||
const isPlaceholder =
|
||||
pdfDetails[0].Placeholders && pdfDetails[0].Placeholders;
|
||||
const isDecline = data.IsDeclined && data.IsDeclined;
|
||||
const signUrl = data.SignedUrl && data.SignedUrl;
|
||||
const expireDate =
|
||||
pdfDetails[0] &&
|
||||
pdfDetails[0].ExpiryDate.iso &&
|
||||
pdfDetails[0].ExpiryDate.iso;
|
||||
const expireUpdateDate = new Date(expireDate).getTime();
|
||||
const currDate = new Date().getTime();
|
||||
const hostUrl = getHostUrl();
|
||||
|
||||
//checking document is completed and signer exist then navigate to pdfRequestFiles file
|
||||
if (data.IsCompleted && checkSignerExist) {
|
||||
navigate(`${hostUrl}pdfRequestFiles`);
|
||||
}
|
||||
//checking document is completed and signer does not exist then navigate to recipientSignPdf file
|
||||
else if (data.IsCompleted && !checkSignerExist) {
|
||||
navigate(`${hostUrl}signaturePdf`);
|
||||
}
|
||||
//checking document is declined by someone then navigate to pdfRequestFiles file
|
||||
else if (isDecline) {
|
||||
navigate(`${hostUrl}pdfRequestFiles`);
|
||||
}
|
||||
//checking document has expired and signers exist and placeholder does not set yet then navigate to pdfRequestFiles file
|
||||
//draft type request sign document
|
||||
else if (
|
||||
currDate > expireUpdateDate &&
|
||||
checkSignerExist &&
|
||||
!isPlaceholder
|
||||
) {
|
||||
navigate(`${hostUrl}placeHolderSign`);
|
||||
}
|
||||
//checking document has expired and signers does not exist and document not signed yet then navigate to pdfRequestFiles file
|
||||
//draft type signyouselfdocument
|
||||
else if (
|
||||
currDate > expireUpdateDate &&
|
||||
!checkSignerExist &&
|
||||
!isPlaceholder &&
|
||||
!signUrl
|
||||
) {
|
||||
// window.location.hash = `/signaturePdf`;
|
||||
navigate(`${hostUrl}signaturePdf`);
|
||||
}
|
||||
//checking document has expired and signers exist and document then navigate to pdfRequestFiles file
|
||||
else if (currDate > expireUpdateDate) {
|
||||
// window.location.hash = `/pdfRequestFiles`;
|
||||
navigate(`${hostUrl}pdfRequestFiles`);
|
||||
}
|
||||
//checking document has expired not been expired yet and signers exist and placeholder does not set yet then navigate to pdfRequestFiles file
|
||||
//draft type request sign document
|
||||
else if (!signUrl && checkSignerExist) {
|
||||
navigate(`${hostUrl}placeHolderSign`);
|
||||
// window.location.hash = `/placeHolderSign`;
|
||||
} else {
|
||||
// window.location.hash = `/signaturePdf/`;
|
||||
navigate(`${hostUrl}signaturePdf`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isLoading.isLoad ? <Loader isLoading={isLoading} /> : handleDraftDoc()}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DraftDocument;
|
||||
@@ -1,614 +0,0 @@
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
import folder from "../../../assests/folder.png";
|
||||
import "../LegaDrive.css";
|
||||
import draftDoc from "../../../assests/draftDoc1.png";
|
||||
import pdfLogo from "../../../assests/pdf3.png";
|
||||
import axios from "axios";
|
||||
import * as ContextMenu from "@radix-ui/react-context-menu";
|
||||
import { saveAs } from "file-saver";
|
||||
import { getHostUrl } from "../../../utils/Utils";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Table from "react-bootstrap/Table";
|
||||
import * as HoverCard from "@radix-ui/react-hover-card";
|
||||
|
||||
function PdfFileComponent({
|
||||
pdfData,
|
||||
setFolderName,
|
||||
setDocId,
|
||||
setIsLoading,
|
||||
setPdfData,
|
||||
isList,
|
||||
}) {
|
||||
const [rename, setRename] = useState("");
|
||||
const [renameValue, setRenameValue] = useState("");
|
||||
const inputRef = useRef(null);
|
||||
|
||||
const navigate = useNavigate();
|
||||
|
||||
//to focus input box on press rename to change doc name
|
||||
useEffect(() => {
|
||||
if (rename && inputRef.current) {
|
||||
// console.log("ref", inputRef.current)
|
||||
setTimeout(() => {
|
||||
inputRef.current.focus();
|
||||
}, 10);
|
||||
}
|
||||
}, [rename]);
|
||||
|
||||
//function to handle folder component
|
||||
const handleOnclikFolder = (data) => {
|
||||
const folderData = {
|
||||
name: data.Name,
|
||||
objectId: data.objectId,
|
||||
};
|
||||
setFolderName((prev) => [...prev, folderData]);
|
||||
const loadObj = {
|
||||
isLoad: true,
|
||||
message: "This might take some time",
|
||||
};
|
||||
|
||||
setIsLoading(loadObj);
|
||||
setDocId(data.objectId);
|
||||
};
|
||||
//function for change doc name and update doc name in _document class
|
||||
const handledRenameDoc = async (data) => {
|
||||
setRename("");
|
||||
const trimmedValue = renameValue.trim();
|
||||
|
||||
if (trimmedValue.length > 0) {
|
||||
const updateName = {
|
||||
Name: renameValue,
|
||||
};
|
||||
const docId = data.objectId;
|
||||
|
||||
const docData = pdfData;
|
||||
|
||||
const updatedData = docData.map((item) => {
|
||||
if (item.objectId === docId) {
|
||||
// If the item's ID matches the target ID, update the name
|
||||
return { ...item, Name: renameValue };
|
||||
}
|
||||
// If the item's ID doesn't match, keep it unchanged
|
||||
return item;
|
||||
});
|
||||
|
||||
setPdfData(updatedData);
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document/${docId}`,
|
||||
updateName,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken"),
|
||||
},
|
||||
}
|
||||
)
|
||||
.then((result) => {
|
||||
// const res = result.data;
|
||||
// console.log("res", res);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("error updating field is decline ", err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//function for navigate user to microapp-signature component
|
||||
const checkPdfStatus = async (data) => {
|
||||
|
||||
const hostUrl = getHostUrl();
|
||||
const expireDate = data.ExpiryDate.iso;
|
||||
const expireUpdateDate = new Date(expireDate).getTime();
|
||||
const currDate = new Date().getTime();
|
||||
const signerExist = data.Signers && data.Signers;
|
||||
const signUrl = data.SignedUrl && data.SignedUrl;
|
||||
const isDecline = data.IsDeclined && data.IsDeclined;
|
||||
const isPlaceholder = data.Placeholders && data.Placeholders;
|
||||
//checking and navigate to signyouself page
|
||||
const checkPlaceHolder = data.Placeholders;
|
||||
//checking if document has completed
|
||||
if (data.IsCompleted && signerExist) {
|
||||
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
|
||||
|
||||
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
|
||||
} else if (data.IsCompleted && !signerExist) {
|
||||
navigate(
|
||||
`${hostUrl}signaturePdf/${data.objectId}`
|
||||
);
|
||||
// window.location.hash = `/recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`;
|
||||
}
|
||||
//checking if document has declined by someone
|
||||
else if (isDecline) {
|
||||
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
|
||||
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
|
||||
} else if (currDate > expireUpdateDate && signerExist && !isPlaceholder) {
|
||||
// window.location.hash = `/placeHolderSign/${data.objectId}`;
|
||||
navigate(`${hostUrl}placeHolderSign/${data.objectId}`);
|
||||
} else if (
|
||||
currDate > expireUpdateDate &&
|
||||
!signerExist &&
|
||||
!isPlaceholder &&
|
||||
!signUrl
|
||||
) {
|
||||
navigate(`${hostUrl}signaturePdf/${data.objectId}`);
|
||||
// window.location.hash = `/signaturePdf/${data.objectId}`;
|
||||
}
|
||||
//checking if document has expired
|
||||
else if (currDate > expireUpdateDate) {
|
||||
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
|
||||
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
|
||||
} //checking if document is draft signers type and signers placeholder does not placed yet
|
||||
else if (!signUrl && signerExist) {
|
||||
// window.location.hash = `/placeHolderSign/${data.objectId}`;
|
||||
navigate(`${hostUrl}placeHolderSign/${data.objectId}`);
|
||||
}
|
||||
//checking if document is request type and signers placeholder exist and does not completed yet
|
||||
//then user can check progress of document and sign also
|
||||
else if (
|
||||
checkPlaceHolder &&
|
||||
checkPlaceHolder.length > 0 &&
|
||||
!data.IsCompleted
|
||||
) {
|
||||
navigate(`${hostUrl}pdfRequestFiles/${data.objectId}`);
|
||||
// window.location.hash = `/pdfRequestFiles/${data.objectId}`;
|
||||
}
|
||||
//checking document is draft and signyourself type then user can sign document
|
||||
else {
|
||||
navigate(`${hostUrl}signaturePdf/${data.objectId}`);
|
||||
// navigate(`/signaturePdf/${data.objectId}`);
|
||||
// window.location.hash = `/signaturePdf/${data.objectId}`;
|
||||
}
|
||||
};
|
||||
|
||||
//component to handle type of document and render according to type
|
||||
const handleFolderData = (data, ind, listType) => {
|
||||
// console.log("data", data);
|
||||
let createddate,
|
||||
status,
|
||||
isDecline,
|
||||
signerExist,
|
||||
isExpire,
|
||||
isComplete,
|
||||
signUrl,
|
||||
isPlaceholder;
|
||||
if (data.Type !== "Folder") {
|
||||
const expireDate = data.ExpiryDate && data.ExpiryDate.iso;
|
||||
const createdDate = data.createdAt && data.createdAt;
|
||||
createddate = new Date(createdDate).toLocaleDateString();
|
||||
isComplete = data.IsCompleted && data.IsCompleted ? true : false;
|
||||
isDecline = data.IsDeclined && data.IsDeclined;
|
||||
isPlaceholder = data.Placeholders && data.Placeholders;
|
||||
signerExist = data.Signers && data.Signers;
|
||||
signUrl = data.SignedUrl && data.SignedUrl;
|
||||
const expireUpdateDate = new Date(expireDate).getTime();
|
||||
const currDate = new Date().getTime();
|
||||
|
||||
if (currDate > expireUpdateDate) {
|
||||
isExpire = true;
|
||||
} else {
|
||||
isExpire = false;
|
||||
}
|
||||
if (isComplete) {
|
||||
status = "Completed";
|
||||
} else if (isDecline) {
|
||||
status = "Declined";
|
||||
} else if (isExpire && !isPlaceholder && signerExist) {
|
||||
// status = "Expired";
|
||||
status = "Draft";
|
||||
} else if (isExpire && !isPlaceholder && !signerExist && !signUrl) {
|
||||
// status = "Expired";
|
||||
status = "Draft";
|
||||
} else if (isExpire) {
|
||||
status = "Expired";
|
||||
} else if (!signUrl) {
|
||||
status = "Draft";
|
||||
} else {
|
||||
status = "InComplete";
|
||||
}
|
||||
}
|
||||
|
||||
const handleDraftDoc = (data) => {
|
||||
window.location.hash = `/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9MZWdhR2VuaWUtTWljcm9hcHBWMi9yZW1vdGVFbnRyeS5qcw==&moduleToLoad=AppRoutes&remoteName=legageniemicroapp/legagenie?${data.objectId}`;
|
||||
};
|
||||
|
||||
const handleMenuItemClick = (selectType, data) => {
|
||||
// console.log("data",data)
|
||||
if (selectType === "Download") {
|
||||
// console.log("download")
|
||||
const pdfName = data && data.Name;
|
||||
const pdfUrl = data && data.SignedUrl ? data.SignedUrl : data.URL;
|
||||
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
||||
} else if (selectType === "Rename") {
|
||||
// console.log("rename")
|
||||
setRenameValue(data.Name);
|
||||
setRename(data.objectId);
|
||||
}
|
||||
};
|
||||
|
||||
const sanitizeFileName = (pdfName) => {
|
||||
// Replace spaces with underscore
|
||||
return pdfName.replace(/ /g, '_');
|
||||
}
|
||||
|
||||
const handleEnterPress = (e, data) => {
|
||||
if (e.key === "Enter") {
|
||||
handledRenameDoc(data);
|
||||
}
|
||||
};
|
||||
|
||||
return listType === "table" ? (
|
||||
data.Type === "Folder" ? (
|
||||
<tr onClick={() => handleOnclikFolder(data)}>
|
||||
<td>
|
||||
<i
|
||||
className="fa fa-folder"
|
||||
aria-hidden="true"
|
||||
style={{ color: "#f0ad26", marginRight: "8px", fontSize: "26px" }}
|
||||
></i>
|
||||
|
||||
<span style={{ fontSize: "12px", fontWeight: "500" }}>
|
||||
{data.Name}
|
||||
</span>
|
||||
</td>
|
||||
<td>_</td>
|
||||
<td>Folder</td>
|
||||
<td>_</td>
|
||||
<td>_</td>
|
||||
</tr>
|
||||
) : data.Type === "AIDoc" ? (
|
||||
<tr onClick={() => handleDraftDoc(data)}>
|
||||
<td>
|
||||
<i
|
||||
className="fa fa-file-text"
|
||||
style={{ color: "#0ea3ed", marginRight: "8px", fontSize: "26px" }}
|
||||
></i>
|
||||
|
||||
<span style={{ fontSize: "12px", fontWeight: "500" }}>
|
||||
{data.Name}
|
||||
</span>
|
||||
</td>
|
||||
<td>{createddate}</td>
|
||||
<td>LegaGenie Draft</td>
|
||||
<td>_</td>
|
||||
<td>_</td>
|
||||
</tr>
|
||||
) : (
|
||||
<tr onClick={() => checkPdfStatus(data)}>
|
||||
<td>
|
||||
<i
|
||||
className="fa fa-file-pdf"
|
||||
style={{ color: "#ed4d0e", marginRight: "8px", fontSize: "26px" }}
|
||||
></i>
|
||||
|
||||
<span style={{ fontSize: "12px", fontWeight: "500" }}>
|
||||
{data.Name}
|
||||
</span>
|
||||
</td>
|
||||
<td>{createddate}</td>
|
||||
<td>Pdf</td>
|
||||
<td>{status}</td>
|
||||
<td>
|
||||
<i
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleMenuItemClick("Download", data);
|
||||
}}
|
||||
className="fa fa-download"
|
||||
aria-hidden="true"
|
||||
style={{ color: "#ed280e", marginRight: "8px" }}
|
||||
></i>
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
) : listType === "list" && data.Type === "Folder" ? (
|
||||
<div key={ind} className="folderBox">
|
||||
<ContextMenu.Root>
|
||||
<ContextMenu.Trigger className="ContextMenuTrigger">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
onClick={() => handleOnclikFolder(data)}
|
||||
src={folder}
|
||||
width={100}
|
||||
height={103}
|
||||
/>
|
||||
{rename === data.objectId ? (
|
||||
<input
|
||||
onFocus={() => {
|
||||
inputRef.current.setSelectionRange(0, 0);
|
||||
const input = inputRef.current;
|
||||
if (input) {
|
||||
input.select();
|
||||
}
|
||||
}}
|
||||
autoFocus={true}
|
||||
type="text"
|
||||
// onFocus={()=>console.log("focus")}
|
||||
onBlur={() => handledRenameDoc(data)}
|
||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
||||
ref={inputRef}
|
||||
defaultValue={renameValue}
|
||||
// value={renameValue}
|
||||
onChange={(e) => setRenameValue(e.target.value)}
|
||||
style={{
|
||||
width: "100px",
|
||||
border: "1.5px solid black",
|
||||
borderRadius: "2px",
|
||||
fontSize: "10px",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className="foldName">{data.Name}</span>
|
||||
)}
|
||||
</div>
|
||||
</ContextMenu.Trigger>
|
||||
|
||||
<ContextMenu.Portal>
|
||||
<ContextMenu.Content
|
||||
className="ContextMenuContent"
|
||||
sideOffset={5}
|
||||
align="end"
|
||||
>
|
||||
{/* <ContextMenu.Item
|
||||
onClick={() => handleMenuItemClick("Download", data)}
|
||||
onSelect={(e) => console.log("event", e)}
|
||||
className="ContextMenuItem"
|
||||
>
|
||||
Download
|
||||
</ContextMenu.Item> */}
|
||||
|
||||
<ContextMenu.Item
|
||||
onClick={() => handleMenuItemClick("Rename", data)}
|
||||
className="ContextMenuItem"
|
||||
>
|
||||
Rename
|
||||
</ContextMenu.Item>
|
||||
</ContextMenu.Content>
|
||||
</ContextMenu.Portal>
|
||||
</ContextMenu.Root>
|
||||
</div>
|
||||
) : data.Type === "AIDoc" ? (
|
||||
<div key={ind} className="folderBox">
|
||||
<ContextMenu.Root>
|
||||
<ContextMenu.Trigger className="ContextMenuTrigger">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
cursor: "pointer",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
onClick={() => handleDraftDoc(data)}
|
||||
src={draftDoc}
|
||||
width={100}
|
||||
height={103}
|
||||
/>
|
||||
{rename === data.objectId ? (
|
||||
<input
|
||||
onFocus={() => {
|
||||
inputRef.current.setSelectionRange(0, 0);
|
||||
const input = inputRef.current;
|
||||
if (input) {
|
||||
input.select();
|
||||
}
|
||||
}}
|
||||
autoFocus={true}
|
||||
type="text"
|
||||
// onFocus={()=>console.log("focus")}
|
||||
onBlur={() => handledRenameDoc(data)}
|
||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
||||
ref={inputRef}
|
||||
defaultValue={renameValue}
|
||||
// value={renameValue}
|
||||
onChange={(e) => setRenameValue(e.target.value)}
|
||||
style={{
|
||||
width: "100px",
|
||||
border: "1.5px solid black",
|
||||
borderRadius: "2px",
|
||||
fontSize: "10px",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className="foldName">{data.Name}</span>
|
||||
)}
|
||||
</div>
|
||||
</ContextMenu.Trigger>
|
||||
|
||||
<ContextMenu.Portal>
|
||||
<ContextMenu.Content
|
||||
className="ContextMenuContent"
|
||||
sideOffset={5}
|
||||
align="end"
|
||||
>
|
||||
{/* <ContextMenu.Item
|
||||
onClick={() => handleMenuItemClick("Download", data)}
|
||||
onSelect={(e) => console.log("event", e)}
|
||||
className="ContextMenuItem"
|
||||
>
|
||||
Download
|
||||
</ContextMenu.Item> */}
|
||||
|
||||
<ContextMenu.Item
|
||||
onClick={() => handleMenuItemClick("Rename", data)}
|
||||
className="ContextMenuItem"
|
||||
>
|
||||
Rename
|
||||
</ContextMenu.Item>
|
||||
</ContextMenu.Content>
|
||||
</ContextMenu.Portal>
|
||||
</ContextMenu.Root>
|
||||
</div>
|
||||
) : (
|
||||
<HoverCard.Root>
|
||||
<HoverCard.Trigger asChild>
|
||||
<div>
|
||||
<ContextMenu.Root>
|
||||
<div className="icon-container">
|
||||
<ContextMenu.Trigger className="ContextMenuTrigger">
|
||||
<img
|
||||
alt="PDF"
|
||||
className="pdf-icon"
|
||||
src={pdfLogo}
|
||||
onClick={() => checkPdfStatus(data)}
|
||||
/>
|
||||
{rename === data.objectId ? (
|
||||
<input
|
||||
autoFocus={true}
|
||||
type="text"
|
||||
onFocus={() => {
|
||||
inputRef.current.setSelectionRange(0, 0);
|
||||
const input = inputRef.current;
|
||||
if (input) {
|
||||
input.select();
|
||||
}
|
||||
}}
|
||||
onBlur={() => handledRenameDoc(data)}
|
||||
onKeyDown={(e) => handleEnterPress(e, data)}
|
||||
ref={inputRef}
|
||||
defaultValue={renameValue}
|
||||
// value={renameValue}
|
||||
onChange={(e) => setRenameValue(e.target.value)}
|
||||
style={{
|
||||
width: "100px",
|
||||
border: "1.5px solid black",
|
||||
borderRadius: "2px",
|
||||
fontSize: "10px",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<span className="fileName">{data.Name}</span>
|
||||
)}
|
||||
</ContextMenu.Trigger>
|
||||
{status === "Completed" ? (
|
||||
<div className="status-badge completed">
|
||||
<i className="fas fa-check-circle"></i>
|
||||
</div>
|
||||
) : status === "Declined" ? (
|
||||
<div className="status-badge declined">
|
||||
<i className="fa fa-thumbs-down"></i>
|
||||
</div>
|
||||
) : status === "Expired" ? (
|
||||
<div className="status-badge expired">
|
||||
<i className="fa fa-hourglass-end"></i>
|
||||
</div>
|
||||
) : status === "Draft" ? (
|
||||
<div className="status-badge draft">
|
||||
<i className="fa fa-file"></i>
|
||||
</div>
|
||||
) : (
|
||||
status === "InComplete" && (
|
||||
<div className="status-badge in-progress">
|
||||
<i className="fa fa-paper-plane"></i>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
|
||||
<ContextMenu.Portal>
|
||||
<ContextMenu.Content
|
||||
className="ContextMenuContent"
|
||||
sideOffset={5}
|
||||
align="end"
|
||||
>
|
||||
<ContextMenu.Item
|
||||
onClick={() => handleMenuItemClick("Download", data)}
|
||||
onSelect={(e) => console.log("event", e)}
|
||||
className="ContextMenuItem"
|
||||
>
|
||||
Download
|
||||
</ContextMenu.Item>
|
||||
|
||||
<ContextMenu.Item
|
||||
onClick={() => handleMenuItemClick("Rename", data)}
|
||||
className="ContextMenuItem"
|
||||
>
|
||||
Rename
|
||||
</ContextMenu.Item>
|
||||
</ContextMenu.Content>
|
||||
</ContextMenu.Portal>
|
||||
</ContextMenu.Root>
|
||||
</div>
|
||||
</HoverCard.Trigger>
|
||||
<HoverCard.Portal>
|
||||
<HoverCard.Content className="HoverCardContent" sideOffset={5}>
|
||||
<strong style={{ fontSize: "13px" }}>Title: </strong>
|
||||
<span className="statusSpan" style={{ marginBottom: "0px" }}>
|
||||
{" "}
|
||||
{data.Name}
|
||||
</span>
|
||||
<br />
|
||||
<strong style={{ fontSize: "13px" }}>Status: </strong>
|
||||
<span className="statusSpan"> {status}</span>
|
||||
<br />
|
||||
<strong style={{ fontSize: "13px" }}>Created Date: </strong>
|
||||
<span className="statusSpan">{createddate}</span>
|
||||
<br />
|
||||
{signerExist && (
|
||||
<>
|
||||
<strong style={{ fontSize: "13px" }}>Signers: </strong>
|
||||
{signerExist.map((data, key) => {
|
||||
return (
|
||||
<React.Fragment key={key}>
|
||||
<span className="statusSpan">{data.Name}, </span>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
<HoverCard.Arrow className="HoverCardArrow" />
|
||||
</HoverCard.Content>
|
||||
</HoverCard.Portal>
|
||||
</HoverCard.Root>
|
||||
);
|
||||
};
|
||||
//component to handle type of document and render according to type
|
||||
|
||||
return isList ? (
|
||||
<div className="container" style={{overflowX:"auto"}}>
|
||||
<Table striped bordered hover >
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Created Date</th>
|
||||
<th>Type</th>
|
||||
<th>Status</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{pdfData.map((data, ind) => {
|
||||
return (
|
||||
<React.Fragment key={ind}>
|
||||
{handleFolderData(data, ind, "table")}
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</Table>
|
||||
</div>
|
||||
) : (
|
||||
<div className="pdfContainer">
|
||||
{pdfData.map((data, ind) => {
|
||||
return (
|
||||
<div className="box" key={ind}>
|
||||
{handleFolderData(data, ind, "list")}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PdfFileComponent;
|
||||
@@ -1,534 +0,0 @@
|
||||
@import '@radix-ui/colors/black-alpha.css';
|
||||
@import '@radix-ui/colors/mauve.css';
|
||||
@import '@radix-ui/colors/violet.css';
|
||||
|
||||
|
||||
|
||||
.ContextMenuContent,
|
||||
.ContextMenuSubContent {
|
||||
min-width: 150px;
|
||||
background-color: white;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
padding: 5px;
|
||||
box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2);
|
||||
}
|
||||
|
||||
.ContextMenuItem,
|
||||
.ContextMenuCheckboxItem,
|
||||
.ContextMenuRadioItem,
|
||||
.ContextMenuSubTrigger {
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
color: var(--violet-11);
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 25px;
|
||||
padding: 0 5px;
|
||||
position: relative;
|
||||
padding-left: 25px;
|
||||
user-select: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.ContextMenuSubTrigger[data-state='open'] {
|
||||
background-color: gray;
|
||||
color: var(--violet-11);
|
||||
}
|
||||
|
||||
.ContextMenuItem[data-disabled],
|
||||
.ContextMenuCheckboxItem[data-disabled],
|
||||
.ContextMenuRadioItem[data-disabled],
|
||||
.ContextMenuSubTrigger[data-disabled] {
|
||||
color: var(--mauve-8);
|
||||
pointer-events: 'none';
|
||||
}
|
||||
|
||||
.ContextMenuItem[data-highlighted],
|
||||
.ContextMenuCheckboxItem[data-highlighted],
|
||||
.ContextMenuRadioItem[data-highlighted],
|
||||
.ContextMenuSubTrigger[data-highlighted] {
|
||||
background-color: #dad9db;
|
||||
color: var(--violet-11);
|
||||
}
|
||||
|
||||
.ContextMenuLabel {
|
||||
padding-left: 25px;
|
||||
font-size: 12px;
|
||||
line-height: 25px;
|
||||
color: var(--mauve-11);
|
||||
}
|
||||
|
||||
|
||||
.ContextMenuItemIndicator {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 25px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.RightSlot {
|
||||
margin-left: auto;
|
||||
padding-left: 20px;
|
||||
color: var(--mauve-11);
|
||||
}
|
||||
|
||||
[data-highlighted]>.RightSlot {
|
||||
color: white;
|
||||
}
|
||||
|
||||
[data-disabled] .RightSlot {
|
||||
color: var(--mauve-8);
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
min-width: 10rem;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
display: block;
|
||||
width: 100%;
|
||||
padding: 0.3rem 1.2rem;
|
||||
clear: both;
|
||||
font-weight: 400;
|
||||
color: #393a39;
|
||||
text-align: inherit;
|
||||
white-space: nowrap;
|
||||
background-color: transparent;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.dropdown-item:hover {
|
||||
background-color: #dad9db;
|
||||
color: var(--violet-11);
|
||||
}
|
||||
|
||||
.itemColor {
|
||||
font-size: 13px !important;
|
||||
}
|
||||
|
||||
.folderComponent {
|
||||
margin: 30px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.folderComponent::-webkit-scrollbar {
|
||||
display: none;
|
||||
/* for Chrome, Safari, and Opera */
|
||||
}
|
||||
|
||||
.modal {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.folderBox {
|
||||
/* box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
|
||||
margin: 10px ;
|
||||
padding: 5px 0px 5px 40px; */
|
||||
/* overflow: scroll;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
width: 200px; */
|
||||
margin: 10px;
|
||||
/* box-shadow: rgba(0, 0, 0, 0.15) 1.95px 1.95px 2.6px; */
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
.folderContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
/* .folderBox:hover{
|
||||
box-shadow: rgba(0, 0, 0, 0.16) 0px 3px 6px, rgba(0, 0, 0, 0.23) 0px 3px 6px;
|
||||
font-weight: bold;
|
||||
} */
|
||||
.pdfName {
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.viewbotton {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 8px 20px;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.viewbotton:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.folderRender {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 20px;
|
||||
display: inline-block;
|
||||
|
||||
}
|
||||
|
||||
.pdfContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 20px;
|
||||
align-items: center;
|
||||
|
||||
justify-content: space-around
|
||||
}
|
||||
|
||||
.pdfContainer .box:last-child {
|
||||
margin-left: 0;
|
||||
/* Override the margin on the last box */
|
||||
margin-right: auto;
|
||||
/* Align it to the start */
|
||||
}
|
||||
|
||||
.icon-container {
|
||||
position: relative;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
margin: 10px;
|
||||
display: inline-block;
|
||||
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
.hrStyle {
|
||||
margin-top: 0rem !important;
|
||||
margin-bottom: 0rem !important;
|
||||
border: 0;
|
||||
border-top: 1px solid rgba(0, 0, 0, .1);
|
||||
}
|
||||
|
||||
.pdf-icon {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background-color: #fff;
|
||||
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
|
||||
}
|
||||
|
||||
.status-badge i {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
/* Status-specific colors */
|
||||
.completed {
|
||||
background-color: #4CAF50;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.in-progress {
|
||||
background-color: #FFC107;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.declined {
|
||||
background-color: #F44336;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.expired {
|
||||
background-color: #9E9E9E;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.draft {
|
||||
background-color: #079cdc;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.add {
|
||||
background-color: #05bbdb;
|
||||
color: #fff;
|
||||
padding: 8px 15px;
|
||||
text-align: center;
|
||||
display: flex;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.sort {
|
||||
padding: 8px 15px;
|
||||
margin: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
|
||||
}
|
||||
|
||||
.sort:hover {
|
||||
box-shadow: 0 2px 4px rgba(168, 204, 206, 0.1);
|
||||
background-color: var(--mauve-3);
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
/* Hover effect */
|
||||
.info-box {
|
||||
position: absolute;
|
||||
|
||||
bottom: 100%;
|
||||
left: 0;
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
padding: 5px;
|
||||
width: 180px;
|
||||
display: none;
|
||||
z-index: 10;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
text-align: center;
|
||||
|
||||
}
|
||||
|
||||
.icon-container:hover .info-box {
|
||||
display: block;
|
||||
|
||||
}
|
||||
|
||||
.folderRender:hover .info-box {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.info-box:hover {
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.addFolderInput {
|
||||
padding: 10px;
|
||||
|
||||
border-radius: 4px;
|
||||
/* width: 440px; */
|
||||
font-size: 15px;
|
||||
|
||||
border: 0.5px solid rgb(198, 195, 195);
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
background-color: #fff;
|
||||
border: 1px solid black;
|
||||
font-weight: 600;
|
||||
opacity: 1 !important;
|
||||
color: rgb(0, 0, 0);
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.fileName {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 11px;
|
||||
text-align: center;
|
||||
font-weight: 480;
|
||||
}
|
||||
|
||||
.foldName {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 11px;
|
||||
text-align: center;
|
||||
font-weight: 480;
|
||||
}
|
||||
|
||||
.statusSpan {
|
||||
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
|
||||
a {
|
||||
all: unset;
|
||||
}
|
||||
|
||||
.HoverCardContent {
|
||||
border-radius: 6px;
|
||||
padding: 5px 10px;
|
||||
width: 170px;
|
||||
background-color: white;
|
||||
box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px, hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
|
||||
animation-duration: 400ms;
|
||||
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
will-change: transform, opacity;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.HoverCardContent[data-side='top'] {
|
||||
animation-name: slideDownAndFade;
|
||||
}
|
||||
|
||||
.HoverCardContent[data-side='right'] {
|
||||
animation-name: slideLeftAndFade;
|
||||
}
|
||||
|
||||
.HoverCardContent[data-side='bottom'] {
|
||||
animation-name: slideUpAndFade;
|
||||
}
|
||||
|
||||
.HoverCardContent[data-side='left'] {
|
||||
animation-name: slideRightAndFade;
|
||||
}
|
||||
|
||||
.HoverCardArrow {
|
||||
fill: white;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@keyframes slideUpAndFade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(2px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideRightAndFade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(-2px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideDownAndFade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideLeftAndFade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
.dropMenuBD {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.dropMenuSS {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.folderPath {
|
||||
overflow-x: auto;
|
||||
white-space: nowrap;
|
||||
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.folderPath::-webkit-scrollbar {
|
||||
display: none;
|
||||
/* for Chrome, Safari, and Opera */
|
||||
}
|
||||
|
||||
@media screen and (max-width:766px) {
|
||||
.itemColor {
|
||||
font-size: 10px !important;
|
||||
}
|
||||
|
||||
}
|
||||
@media (min-width: 310px) and (max-width:550px) {
|
||||
|
||||
.pdfContainer {
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.sort {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.folderComponent {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width:309px) {
|
||||
|
||||
.pdfContainer {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.sort {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.folderComponent {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
@@ -1,750 +0,0 @@
|
||||
import React, { useEffect, useState, useRef } from "react";
|
||||
import axios from "axios";
|
||||
import "./LegaDrive.css";
|
||||
import loader from "../../assests/loader2.gif";
|
||||
import PdfFileComponent from "./FolderDrive/legaDriveComponent";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import ModalHeader from "react-bootstrap/esm/ModalHeader";
|
||||
import { themeColor, iconColor } from "../../utils/ThemeColor/backColor";
|
||||
import { getDrive } from "../../utils/Utils";
|
||||
import AlertComponent from "../component/alertComponent";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
function PdfFile() {
|
||||
const navigate = useNavigate();
|
||||
const scrollRef = useRef(null);
|
||||
const [isList, setIsList] = useState(false);
|
||||
const [selectedSort, setSelectedSort] = useState("Date");
|
||||
const [sortingOrder, setSortingOrder] = useState("Decending");
|
||||
const [pdfData, setPdfData] = useState([]);
|
||||
const [isFolder, setIsFolder] = useState(false);
|
||||
const [newFolderName, setNewFolderName] = useState();
|
||||
const [error, setError] = useState();
|
||||
const [folderLoader, setIsFolderLoader] = useState(false);
|
||||
const [isShowSort, setIsShowSort] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
});
|
||||
const [docId, setDocId] = useState();
|
||||
const [handleError, setHandleError] = useState();
|
||||
const [folderName, setFolderName] = useState([]);
|
||||
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
||||
const [isNewFol, setIsNewFol] = useState(false);
|
||||
const currentUser =
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
) &&
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
);
|
||||
const jsonCurrentUser = JSON.parse(currentUser);
|
||||
|
||||
useEffect(() => {
|
||||
if (docId) {
|
||||
getPdfFolderDocumentList();
|
||||
} else {
|
||||
getPdfDocumentList();
|
||||
}
|
||||
}, [docId]);
|
||||
|
||||
//function for get all pdf document list
|
||||
const getPdfDocumentList = async () => {
|
||||
const load = {
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
};
|
||||
setIsLoading(load);
|
||||
const driveDetails = await getDrive();
|
||||
if (driveDetails) {
|
||||
if (driveDetails.length > 0) {
|
||||
setPdfData(driveDetails);
|
||||
}
|
||||
const data = [
|
||||
{
|
||||
name: "OpenSignDrive™",
|
||||
objectId: ""
|
||||
}
|
||||
];
|
||||
setFolderName(data);
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
} else if (driveDetails === "Error: Something went wrong!") {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
};
|
||||
//function for get parent folder document list
|
||||
const getPdfFolderDocumentList = async () => {
|
||||
const load = {
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
};
|
||||
setIsLoading(load);
|
||||
const driveDetails = await getDrive(docId);
|
||||
if (driveDetails) {
|
||||
if (driveDetails.length > 0) {
|
||||
setPdfData(driveDetails);
|
||||
} else {
|
||||
setPdfData([]);
|
||||
}
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
} else if (driveDetails === "Error: Something went wrong!") {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
};
|
||||
|
||||
//function for get all pdf document list
|
||||
const getParentFolder = async () => {
|
||||
setIsFolder(true);
|
||||
};
|
||||
//function for handle folder name path
|
||||
const handleRoute = (data) => {
|
||||
let loadObj = {
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
};
|
||||
if (data.name === "LegaDrive™") {
|
||||
setIsLoading(loadObj);
|
||||
if (docId) {
|
||||
setDocId();
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
}, 1000);
|
||||
}
|
||||
} else if (data.name === folderName[folderName.length - 1].name) {
|
||||
setIsLoading(loadObj);
|
||||
setTimeout(() => {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
}, 1000);
|
||||
} else {
|
||||
const findIndex = folderName.findIndex(
|
||||
(fold) => fold.objectId === data.objectId
|
||||
);
|
||||
const newFolder = folderName.slice(0, findIndex + 1);
|
||||
|
||||
setFolderName(newFolder);
|
||||
const getLastId = newFolder[newFolder.length - 1];
|
||||
|
||||
setDocId(getLastId.objectId);
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
};
|
||||
|
||||
//function for add new folder name
|
||||
const handleFolderName = (e) => {
|
||||
setError();
|
||||
const value = e.target.value;
|
||||
setNewFolderName(value);
|
||||
};
|
||||
//function for add folder
|
||||
const handleAddFolder = async () => {
|
||||
if (newFolderName) {
|
||||
setIsFolderLoader(true);
|
||||
|
||||
const getParentObjId = folderName[folderName.length - 1];
|
||||
const parentId = getParentObjId && getParentObjId.objectId;
|
||||
let data;
|
||||
if (parentId) {
|
||||
data = {
|
||||
Name: newFolderName,
|
||||
Type: "Folder",
|
||||
Folder: {
|
||||
__type: "Pointer",
|
||||
className: `${localStorage.getItem("_appName")}_Document`,
|
||||
objectId: parentId
|
||||
},
|
||||
CreatedBy: {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: jsonCurrentUser.objectId
|
||||
}
|
||||
};
|
||||
} else {
|
||||
data = {
|
||||
Name: newFolderName,
|
||||
Type: "Folder",
|
||||
CreatedBy: {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: jsonCurrentUser.objectId
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
await axios
|
||||
.post(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
.then((Listdata) => {
|
||||
// console.log("Listdata ", Listdata);
|
||||
const json = Listdata.data;
|
||||
// console.log("json ", json);
|
||||
if (json) {
|
||||
setNewFolderName();
|
||||
|
||||
setIsFolderLoader(false);
|
||||
setIsFolder(false);
|
||||
if (docId) {
|
||||
getPdfFolderDocumentList();
|
||||
} else {
|
||||
getPdfDocumentList();
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
});
|
||||
} else {
|
||||
setError("Please fill out this field");
|
||||
}
|
||||
};
|
||||
|
||||
const sortingApp = (appInfo, type, order) => {
|
||||
if (type === "Name") {
|
||||
if (order === "Accending") {
|
||||
return appInfo.sort((a, b) => (a.Name > b.Name ? 1 : -1));
|
||||
} else if (order === "Decending") {
|
||||
return appInfo.sort((a, b) => (a.Name > b.Name ? -1 : 1));
|
||||
}
|
||||
} else if (type === "Date") {
|
||||
if (order === "Accending") {
|
||||
return appInfo.sort((a, b) => (a.createdAt > b.createdAt ? 1 : -1));
|
||||
} else if (order === "Decending") {
|
||||
return appInfo.sort((a, b) => (a.createdAt > b.createdAt ? -1 : 1));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const sortApps = () => {
|
||||
const selectedSortType = selectedSort;
|
||||
const sortOrder = sortingOrder;
|
||||
|
||||
let sortingData = pdfData;
|
||||
if (selectedSortType === "Name") {
|
||||
sortingApp(sortingData, "Name", sortOrder);
|
||||
} else if (selectedSortType === "Date") {
|
||||
sortingApp(sortingData, "Date", sortOrder);
|
||||
}
|
||||
|
||||
setPdfData(sortingData);
|
||||
};
|
||||
|
||||
//function for handle auto scroll on folder path
|
||||
const handleMouseEnter = (e) => {
|
||||
let side = "";
|
||||
const container = scrollRef.current;
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const cursorX = e.clientX;
|
||||
const containerX = containerRect.left;
|
||||
const containerWidth = containerRect.width;
|
||||
|
||||
// Define a threshold (e.g., 10 pixels) for the start and end points
|
||||
const threshold = 10;
|
||||
|
||||
if (cursorX - containerX <= threshold) {
|
||||
side = "start";
|
||||
} else if (containerX + containerWidth - cursorX <= threshold) {
|
||||
side = "end";
|
||||
} else {
|
||||
side = "";
|
||||
}
|
||||
|
||||
const scrollSpeed = 10;
|
||||
let scrollAmount = 0;
|
||||
|
||||
const scroll = () => {
|
||||
if (side === "start" && container.scrollLeft > 0) {
|
||||
container.scrollLeft -= scrollAmount;
|
||||
requestAnimationFrame(scroll);
|
||||
} else if (
|
||||
side === "end" &&
|
||||
container.scrollLeft < container.scrollWidth - container.clientWidth
|
||||
) {
|
||||
container.scrollLeft += scrollAmount;
|
||||
requestAnimationFrame(scroll);
|
||||
}
|
||||
};
|
||||
|
||||
container.addEventListener("mousemove", (e) => {
|
||||
const rect = container.getBoundingClientRect();
|
||||
const x = e.clientX - rect.left;
|
||||
const containerWidth = rect.width;
|
||||
|
||||
// Calculate the scroll amount based on the cursor's position
|
||||
scrollAmount = (x / containerWidth) * scrollSpeed;
|
||||
});
|
||||
|
||||
scroll();
|
||||
};
|
||||
|
||||
//handle to close drop down menu onclick screen
|
||||
useEffect(() => {
|
||||
const closeMenuOnOutsideClick = (e) => {
|
||||
if (isShowSort && !e.target.closest("#menu-container")) {
|
||||
setIsShowSort(false);
|
||||
} else if (isNewFol && !e.target.closest("#folder-menu")) {
|
||||
setIsNewFol(false);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("click", closeMenuOnOutsideClick);
|
||||
|
||||
return () => {
|
||||
// Cleanup the event listener when the component unmounts
|
||||
document.removeEventListener("click", closeMenuOnOutsideClick);
|
||||
};
|
||||
}, [isShowSort]);
|
||||
|
||||
return (
|
||||
<div className="folderComponent ">
|
||||
<div>
|
||||
<AlertComponent
|
||||
isShow={isAlert.isShow}
|
||||
alertMessage={isAlert.alertMessage}
|
||||
setIsAlert={setIsAlert}
|
||||
/>
|
||||
<Modal show={isFolder}>
|
||||
<ModalHeader style={{ background: themeColor() }}>
|
||||
<span style={{ color: "white" }}>Add New Folder</span>
|
||||
{!folderLoader && (
|
||||
<span
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={() => {
|
||||
setNewFolderName("");
|
||||
setIsFolder(false);
|
||||
}}
|
||||
>
|
||||
X
|
||||
</span>
|
||||
)}
|
||||
</ModalHeader>
|
||||
|
||||
<Modal.Body>
|
||||
{folderLoader ? (
|
||||
<div
|
||||
style={{
|
||||
height: "200px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="loader img"
|
||||
src={loader}
|
||||
style={{ width: "50px", height: "50px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "13px", color: "gray" }}>
|
||||
Loading...
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<form style={{ display: "flex", flexDirection: "column" }}>
|
||||
<label
|
||||
style={{
|
||||
margin: "10px 0px 10px 0px",
|
||||
fontSize: "15px",
|
||||
fontWeight: "400"
|
||||
}}
|
||||
>
|
||||
Name*
|
||||
</label>
|
||||
|
||||
<input
|
||||
required
|
||||
className="form-control"
|
||||
type="text"
|
||||
value={newFolderName}
|
||||
onChange={(e) => handleFolderName(e)}
|
||||
// className="addFolderInput"
|
||||
/>
|
||||
<span style={{ color: "red", fontSize: "12px" }}>{error}</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
margin: "20px 10px 10px 10px ",
|
||||
display: "flex",
|
||||
alignItems: "flex-end",
|
||||
justifyContent: "flex-end",
|
||||
alignContent: "flex-end"
|
||||
}}
|
||||
>
|
||||
<button
|
||||
type="submit"
|
||||
style={{
|
||||
borderRadius: "0px",
|
||||
border: "1.5px solid #e3e2e1",
|
||||
fontWeight: "600",
|
||||
color: "black"
|
||||
}}
|
||||
className="finishBtn"
|
||||
onClick={() => setIsFolder(false)}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={() => handleAddFolder()}
|
||||
style={{
|
||||
background: themeColor()
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
|
||||
{isLoading.isLoad ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
width: "100%",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="loader img"
|
||||
src={loader}
|
||||
style={{ width: "80px", height: "80px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "13px", color: "gray" }}>
|
||||
{isLoading.message}
|
||||
</span>
|
||||
</div>
|
||||
) : handleError ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: "20px", color: "gray" }}>
|
||||
{handleError}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div className="folderContainer">
|
||||
<div
|
||||
onMouseEnter={(e) => handleMouseEnter(e)}
|
||||
ref={scrollRef}
|
||||
style={{
|
||||
width: "100%"
|
||||
}}
|
||||
className="folderPath"
|
||||
>
|
||||
{folderName.map((data, id) => {
|
||||
return (
|
||||
<span
|
||||
key={id}
|
||||
onClick={() => handleRoute(data)}
|
||||
style={{
|
||||
color: "#a64b4e",
|
||||
fontWeight: "400",
|
||||
cursor: "pointer"
|
||||
}}
|
||||
>
|
||||
{data.name}
|
||||
<span
|
||||
style={{
|
||||
color: "#a64b4e",
|
||||
fontWeight: "200",
|
||||
cursor: "pointer",
|
||||
margin: "0 4px"
|
||||
}}
|
||||
>
|
||||
>
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="dropMenuBD">
|
||||
<div
|
||||
id="folder-menu"
|
||||
className={
|
||||
isNewFol ? "dropdown show dropDownStyle" : "dropdown"
|
||||
}
|
||||
onClick={() => setIsNewFol(!isNewFol)}
|
||||
>
|
||||
<div className="sort">
|
||||
<i
|
||||
className="fa fa-plus-square"
|
||||
aria-hidden="true"
|
||||
style={{ fontSize: "25px", color: `${iconColor()}` }}
|
||||
></i>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
isNewFol ? "dropdown-menu show" : "dropdown-menu"
|
||||
}
|
||||
aria-labelledby="dropdownMenuButton"
|
||||
aria-expanded={isNewFol ? "true" : "false"}
|
||||
>
|
||||
{" "}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<span
|
||||
className="dropdown-item itemColor"
|
||||
onClick={() => getParentFolder()}
|
||||
>
|
||||
<i
|
||||
style={{ marginRight: "5px" }}
|
||||
className="fa fa-plus"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Create folder
|
||||
</span>
|
||||
<span
|
||||
className="dropdown-item itemColor"
|
||||
onClick={() => navigate("/form/sHAnZphf69")}
|
||||
>
|
||||
<i
|
||||
style={{ marginRight: "5px" }}
|
||||
className="fas fa-pen-nib"
|
||||
></i>
|
||||
Sign Yourself
|
||||
</span>
|
||||
<span
|
||||
className="dropdown-item itemColor"
|
||||
onClick={() => navigate("/form/8mZzFxbG1z")}
|
||||
>
|
||||
{" "}
|
||||
<i
|
||||
style={{ marginRight: "5px" }}
|
||||
className="fa fa-file-signature"
|
||||
></i>
|
||||
Request Signatures{" "}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
id="menu-container"
|
||||
className={isShowSort ? "dropdown show" : "dropdown"}
|
||||
onClick={() => setIsShowSort(!isShowSort)}
|
||||
>
|
||||
<div className=" sort " data-toggle="dropdown">
|
||||
<i
|
||||
className="fa fa-sort-amount-asc"
|
||||
aria-hidden="true"
|
||||
style={{
|
||||
marginRight: "5px",
|
||||
fontSize: "14px",
|
||||
color: `${iconColor()}`
|
||||
}}
|
||||
></i>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "15px",
|
||||
color: `${iconColor()}`
|
||||
}}
|
||||
>
|
||||
{selectedSort}
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
isShowSort ? "dropdown-menu show" : "dropdown-menu"
|
||||
}
|
||||
aria-labelledby="dropdownMenuButton"
|
||||
aria-expanded={isShowSort ? "true" : "false"}
|
||||
>
|
||||
<span
|
||||
onClick={() => {
|
||||
setSelectedSort("Name");
|
||||
sortApps();
|
||||
}}
|
||||
className="dropdown-item itemColor"
|
||||
>
|
||||
{selectedSort !== "Name" ? (
|
||||
<i
|
||||
className="fa fa-arrow-up"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
) : (
|
||||
<i
|
||||
className="fa fa-check"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
)}
|
||||
Name
|
||||
</span>
|
||||
<span
|
||||
onClick={() => {
|
||||
setSelectedSort("Date");
|
||||
sortApps();
|
||||
}}
|
||||
className="dropdown-item itemColor"
|
||||
>
|
||||
{selectedSort !== "Date" ? (
|
||||
<i
|
||||
className="fa fa-arrow-up"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
) : (
|
||||
<i
|
||||
className="fa fa-check"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
)}
|
||||
Date
|
||||
</span>
|
||||
<hr className="hrStyle" />
|
||||
<span
|
||||
onClick={() => {
|
||||
setSortingOrder("Accending");
|
||||
sortApps();
|
||||
}}
|
||||
className="dropdown-item itemColor"
|
||||
>
|
||||
{sortingOrder !== "Accending" ? (
|
||||
<i
|
||||
className="fa fa-arrow-up"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
) : (
|
||||
<i
|
||||
className="fa fa-check"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
)}
|
||||
Accending
|
||||
</span>
|
||||
<span
|
||||
onClick={() => {
|
||||
setSortingOrder("Decending");
|
||||
sortApps();
|
||||
}}
|
||||
className="dropdown-item itemColor"
|
||||
>
|
||||
{sortingOrder !== "Decending" ? (
|
||||
<i
|
||||
className="fa fa-arrow-up"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
) : (
|
||||
<i
|
||||
className="fa fa-check"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "5px" }}
|
||||
></i>
|
||||
)}
|
||||
Decending
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
{isList ? (
|
||||
<div className="sort" onClick={() => setIsList(!isList)}>
|
||||
<i
|
||||
onClick={() => setIsList(!isList)}
|
||||
className="fa fa-th-large"
|
||||
style={{ fontSize: "24px", color: `${iconColor()}` }}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</div>
|
||||
) : (
|
||||
<div className="sort" onClick={() => setIsList(!isList)}>
|
||||
<i
|
||||
className="fa fa-list"
|
||||
aria-hidden="true"
|
||||
style={{ fontSize: "23px", color: `${iconColor()}` }}
|
||||
></i>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{pdfData && pdfData.length === 0 ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "50vh",
|
||||
width: "100%"
|
||||
}}
|
||||
>
|
||||
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
|
||||
</div>
|
||||
) : (
|
||||
<PdfFileComponent
|
||||
pdfData={pdfData}
|
||||
setFolderName={setFolderName}
|
||||
setIsLoading={setIsLoading}
|
||||
setDocId={setDocId}
|
||||
getPdfFolderDocumentList={getPdfFolderDocumentList}
|
||||
getPdfDocumentList={getPdfDocumentList}
|
||||
isDocId={docId}
|
||||
setPdfData={setPdfData}
|
||||
isList={isList}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PdfFile;
|
||||
@@ -1,700 +0,0 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import SignatureCanvas from "react-signature-canvas";
|
||||
import redPen from "../assests/redPen.png";
|
||||
import bluePen from "../assests/bluePen.png";
|
||||
import blackPen from "../assests/blackPen.png";
|
||||
import "../css/custom.css";
|
||||
import "../css/signature.css";
|
||||
import axios from "axios";
|
||||
import { toDataUrl } from "../utils/toDataUrl";
|
||||
|
||||
|
||||
const ManageSign = () => {
|
||||
let appName;
|
||||
const [penColor, setPenColor] = useState("blue");
|
||||
const [initialPen, setInitialPen] = useState("blue");
|
||||
const [image, setImage] = useState();
|
||||
const [signName, setSignName] = useState("");
|
||||
const [signature, setSignature] = useState("");
|
||||
const [warning, setWarning] = useState(false);
|
||||
const [nameWarning, setNameWarning] = useState(false);
|
||||
const [isvalue, setIsValue] = useState(false);
|
||||
const allColor = [bluePen, redPen, blackPen];
|
||||
const [isLoader, setIsLoader] = useState(true);
|
||||
const [isSuccess, setIsSuccess] = useState(false);
|
||||
const [Initials, setInitials] = useState("");
|
||||
const [isInitials, setIsInitials] = useState(false);
|
||||
const [id, setId] = useState("");
|
||||
const canvasRef = useRef(null);
|
||||
const imageRef = useRef(null);
|
||||
const initailsRef = useRef(null);
|
||||
useEffect(() => {
|
||||
getLocalStorageValue();
|
||||
}, []);
|
||||
|
||||
//function for get localstorage value first and than call another function.
|
||||
const getLocalStorageValue = () => {
|
||||
let User = JSON.parse(
|
||||
localStorage.getItem(
|
||||
"Parse/" + localStorage.getItem("parseAppId") + "/currentUser"
|
||||
)
|
||||
);
|
||||
appName =
|
||||
localStorage.getItem("_appName") && localStorage.getItem("_appName");
|
||||
if (User) {
|
||||
fetchUserSign(User);
|
||||
}
|
||||
};
|
||||
|
||||
const fetchUserSign = async (User) => {
|
||||
const userId = {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: User.objectId,
|
||||
};
|
||||
const strObj = JSON.stringify(userId);
|
||||
const url =
|
||||
localStorage.getItem("baseUrl") +
|
||||
`classes/${appName}_Signature?where={"UserId":${strObj}}&limit=1`;
|
||||
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
// "X-Parse-Session-Token": localStorage.getItem("accesstoken"),
|
||||
};
|
||||
const res = await axios
|
||||
.get(url, { headers: headers })
|
||||
.then((res) => {
|
||||
if (res.data.results.length > 0) {
|
||||
setId(res.data.results[0].objectId);
|
||||
setSignName(res.data.results[0].SignatureName);
|
||||
setImage(res.data.results[0].ImageURL);
|
||||
if (res.data.results[0] && res.data.results[0].Initials) {
|
||||
setInitials(res.data.results[0].Initials);
|
||||
setIsInitials(true);
|
||||
}
|
||||
}
|
||||
setIsLoader(false);
|
||||
return res;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
alert(`${error.message}`);
|
||||
});
|
||||
return res;
|
||||
};
|
||||
const handleSignatureChange = () => {
|
||||
if (imageRef.current) {
|
||||
imageRef.current.value = "";
|
||||
}
|
||||
setImage("");
|
||||
setSignature(canvasRef.current.toDataURL());
|
||||
setIsValue(true);
|
||||
};
|
||||
const handleClear = () => {
|
||||
if (canvasRef.current) {
|
||||
canvasRef.current.clear();
|
||||
}
|
||||
if (imageRef.current) {
|
||||
imageRef.current.value = "";
|
||||
}
|
||||
setImage("");
|
||||
setSignature("");
|
||||
setIsValue(false);
|
||||
};
|
||||
|
||||
const handleClearInitials = () => {
|
||||
if (initailsRef.current) {
|
||||
initailsRef.current.clear();
|
||||
}
|
||||
setInitials("");
|
||||
setIsValue(true);
|
||||
setIsInitials(false);
|
||||
};
|
||||
|
||||
// const handleReset = () => {
|
||||
// if (canvasRef.current) {
|
||||
// canvasRef.current.clear();
|
||||
// }
|
||||
// if (imageRef.current) {
|
||||
// imageRef.current.value = "";
|
||||
// }
|
||||
// setImage("");
|
||||
// setSignature("");
|
||||
// setIsValue(false);
|
||||
// setSignName("");
|
||||
// };
|
||||
const onImageChange = async (event) => {
|
||||
if (canvasRef.current) {
|
||||
canvasRef.current.clear();
|
||||
}
|
||||
setSignature("");
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
const file = event.target.files[0];
|
||||
const base64Img = await toDataUrl(file);
|
||||
setImage(base64Img);
|
||||
setIsValue(true);
|
||||
}
|
||||
};
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
const isUrl = image.includes("https");
|
||||
|
||||
if (!signName) {
|
||||
setNameWarning(true);
|
||||
|
||||
} else if (!isvalue) {
|
||||
setWarning(true);
|
||||
setTimeout(() => setWarning(false), 1000);
|
||||
} else {
|
||||
setIsLoader(true);
|
||||
const replaceSpace = signName.replace(/ /g, "_");
|
||||
let file;
|
||||
if (signature) {
|
||||
file = base64StringtoFile(signature, `${replaceSpace}.png`);
|
||||
} else {
|
||||
if (!isUrl) {
|
||||
file = base64StringtoFile(image, `${replaceSpace}.png`);
|
||||
}
|
||||
}
|
||||
console.log("isUrl ", isUrl);
|
||||
let imgUrl;
|
||||
if (!isUrl) {
|
||||
imgUrl = await uploadFile(file);
|
||||
} else {
|
||||
imgUrl = { data: { imageUrl: image } };
|
||||
}
|
||||
let initialsUrl = "";
|
||||
if (Initials) {
|
||||
const initialsImg = base64StringtoFile(Initials, `${replaceSpace}.png`);
|
||||
initialsUrl = await uploadFile(initialsImg);
|
||||
}
|
||||
if (imgUrl.data && imgUrl.data.imageUrl) {
|
||||
await saveEntry({
|
||||
name: signName,
|
||||
url: imgUrl.data.imageUrl,
|
||||
initialsUrl: initialsUrl,
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
function base64StringtoFile(base64String, filename) {
|
||||
var arr = base64String.split(","),
|
||||
mime = arr[0].match(/:(.*?);/)[1],
|
||||
bstr = atob(arr[1]),
|
||||
n = bstr.length,
|
||||
u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
return new File([u8arr], filename, { type: mime });
|
||||
}
|
||||
|
||||
const uploadFile = async (file) => {
|
||||
let parseBaseUrl = localStorage.getItem("baseUrl");
|
||||
parseBaseUrl = parseBaseUrl.slice(0, -4);
|
||||
const url = parseBaseUrl + `file_upload`;
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
const config = {
|
||||
headers: {
|
||||
"content-type": "multipart/form-data",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
},
|
||||
onUploadProgress: function (progressEvent) {
|
||||
let percentCompleted = Math.round(
|
||||
(progressEvent.loaded * 100) / progressEvent.total
|
||||
);
|
||||
// setpercentage(percentCompleted);
|
||||
},
|
||||
};
|
||||
const response = await axios
|
||||
.post(url, formData, config)
|
||||
.then((res) => {
|
||||
if (res.data.status === "Error") {
|
||||
alert(res.data.message);
|
||||
}
|
||||
return res;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setIsLoader(false);
|
||||
alert(`${error.message}`);
|
||||
});
|
||||
return response;
|
||||
};
|
||||
|
||||
const saveEntry = async (obj) => {
|
||||
if (id) {
|
||||
const User = JSON.parse(
|
||||
localStorage.getItem(
|
||||
"Parse/" + localStorage.getItem("parseAppId") + "/currentUser"
|
||||
)
|
||||
);
|
||||
const url =
|
||||
localStorage.getItem("baseUrl") +
|
||||
`classes/${localStorage.getItem("_appName")}_Signature/${id}`;
|
||||
const body = {
|
||||
Initials: obj.initialsUrl ? obj.initialsUrl.data.imageUrl : "",
|
||||
ImageURL: obj.url,
|
||||
SignatureName: obj.name,
|
||||
UserId: {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: User.objectId,
|
||||
},
|
||||
};
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
// "X-Parse-Session-Token": localStorage.getItem("accesstoken"),
|
||||
};
|
||||
const res = await axios
|
||||
.put(url, body, { headers: headers })
|
||||
.then((res) => {
|
||||
// handleReset();
|
||||
setIsLoader(false);
|
||||
setIsSuccess(true);
|
||||
return res;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setIsLoader(false);
|
||||
alert(`${error.message}`);
|
||||
});
|
||||
return res;
|
||||
} else {
|
||||
const User = JSON.parse(
|
||||
localStorage.getItem(
|
||||
"Parse/" + localStorage.getItem("parseAppId") + "/currentUser"
|
||||
)
|
||||
);
|
||||
const url =
|
||||
localStorage.getItem("baseUrl") +
|
||||
`classes/${localStorage.getItem("_appName")}_Signature`;
|
||||
const body = {
|
||||
Initials: obj.initialsUrl ? obj.initialsUrl.data.imageUrl : "",
|
||||
ImageURL: obj.url,
|
||||
SignatureName: obj.name,
|
||||
UserId: {
|
||||
__type: "Pointer",
|
||||
className: "_User",
|
||||
objectId: User.objectId,
|
||||
},
|
||||
};
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
// "X-Parse-Session-Token": localStorage.getItem("accesstoken"),
|
||||
};
|
||||
const res = await axios
|
||||
.post(url, body, { headers: headers })
|
||||
.then((res) => {
|
||||
// handleReset();
|
||||
setIsLoader(false);
|
||||
setIsSuccess(true);
|
||||
return res;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setIsLoader(false);
|
||||
alert(`${error.message}`);
|
||||
});
|
||||
return res;
|
||||
}
|
||||
};
|
||||
const handleSignatureBtn = () => {
|
||||
if (imageRef.current) {
|
||||
imageRef.current.value = "";
|
||||
}
|
||||
setImage("");
|
||||
};
|
||||
const handleUploadBtn = () => {
|
||||
imageRef.current.click();
|
||||
};
|
||||
const handleInitialsChange = () => {
|
||||
setInitials(initailsRef.current.toDataURL());
|
||||
setIsValue(true);
|
||||
};
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
maxHeight: "500px",
|
||||
overflow: "auto",
|
||||
}}
|
||||
>
|
||||
{isSuccess && (
|
||||
<div
|
||||
className="alert alert-success successBox"
|
||||
role="alert"
|
||||
onAnimationEnd={() => setIsSuccess(false)}
|
||||
>
|
||||
Signature saved successfully!
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div
|
||||
className="mainDiv"
|
||||
style={{
|
||||
width: "100%",
|
||||
paddingRight: "10px",
|
||||
}}
|
||||
>
|
||||
<div style={{ margin: 20 }}>
|
||||
<div
|
||||
style={{
|
||||
fontWeight: "700",
|
||||
fontSize: 15,
|
||||
color: "#000",
|
||||
paddingBottom: 8,
|
||||
}}
|
||||
>
|
||||
Manage Signature
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<label
|
||||
htmlFor="signName"
|
||||
style={{
|
||||
fontSize: 12,
|
||||
position: "relative",
|
||||
paddingBottom: 5,
|
||||
}}
|
||||
>
|
||||
Signer's Name
|
||||
{nameWarning && (
|
||||
<div
|
||||
className="warning nameWarning"
|
||||
style={{ fontSize: 12 }}
|
||||
onAnimationEnd={() => setNameWarning(false)}
|
||||
>
|
||||
<i
|
||||
className="fas fa-exclamation-circle"
|
||||
style={{ color: "#fab005", fontSize: 15 }}
|
||||
></i>{" "}
|
||||
Please fill input field
|
||||
</div>
|
||||
)}
|
||||
</label>
|
||||
<input
|
||||
id="signName"
|
||||
className="signInputManage"
|
||||
value={signName}
|
||||
style={{
|
||||
border: "1px solid #ccc",
|
||||
borderRadius: 4,
|
||||
|
||||
height: 35,
|
||||
padding: "6px 12px",
|
||||
marginBottom: 10,
|
||||
fontSize: 12,
|
||||
}}
|
||||
required
|
||||
onFocus={() => setNameWarning(false)}
|
||||
onChange={(e) => setSignName(e.target.value)}
|
||||
/>
|
||||
|
||||
<label
|
||||
htmlFor="imgoverview"
|
||||
style={{
|
||||
fontSize: 12,
|
||||
paddingBottom: 5,
|
||||
}}
|
||||
>
|
||||
Signature/Image
|
||||
</label>
|
||||
</div>
|
||||
<div className="signBlock">
|
||||
<div>
|
||||
<div style={{ position: "relative" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
width: "50%",
|
||||
paddingLeft: 10,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-around",
|
||||
alignItems: "center",
|
||||
gap: 10,
|
||||
marginBottom: 10,
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<span
|
||||
onClick={() => handleSignatureBtn()}
|
||||
className="signature"
|
||||
>
|
||||
Signature
|
||||
</span>
|
||||
</>
|
||||
|
||||
<span
|
||||
onClick={() => handleUploadBtn()}
|
||||
className="imgupload"
|
||||
>
|
||||
Upload Image
|
||||
</span>
|
||||
<input
|
||||
type="file"
|
||||
onChange={onImageChange}
|
||||
className="filetype"
|
||||
accept="image/*"
|
||||
ref={imageRef}
|
||||
hidden
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ position: "relative" }}>
|
||||
<div>
|
||||
{image ? (
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
|
||||
border: "2px solid #888",
|
||||
marginBottom: 6,
|
||||
}}
|
||||
className="signatureCanvas"
|
||||
>
|
||||
<img
|
||||
alt="preview image"
|
||||
src={image}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<SignatureCanvas
|
||||
ref={canvasRef}
|
||||
penColor={penColor}
|
||||
canvasProps={{
|
||||
width: "456px",
|
||||
height: "180px",
|
||||
className: "signatureCanvas",
|
||||
}}
|
||||
backgroundColor="rgb(255, 255, 255)"
|
||||
onEnd={() =>
|
||||
handleSignatureChange(canvasRef.current.toDataURL())
|
||||
}
|
||||
dotSize={1}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
// width: 460,
|
||||
}}
|
||||
className="penContainer"
|
||||
>
|
||||
<div>
|
||||
{!image && (
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "row" }}
|
||||
>
|
||||
{allColor.map((data, key) => {
|
||||
return (
|
||||
<img
|
||||
alt="black img"
|
||||
style={{
|
||||
border: "none",
|
||||
margin: "5px",
|
||||
borderBottom:
|
||||
key === 0 && penColor === "blue"
|
||||
? "2px solid blue"
|
||||
: key === 1 && penColor === "red"
|
||||
? "2px solid red"
|
||||
: key === 2 && penColor === "black"
|
||||
? "2px solid black"
|
||||
: "2px solid white",
|
||||
}}
|
||||
onClick={() => {
|
||||
if (key === 0) {
|
||||
setPenColor("blue");
|
||||
} else if (key === 1) {
|
||||
setPenColor("red");
|
||||
} else if (key === 2) {
|
||||
setPenColor("black");
|
||||
}
|
||||
}}
|
||||
key={key}
|
||||
src={data}
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
type="button"
|
||||
className="clearbtn"
|
||||
onClick={() => handleClear()}
|
||||
>
|
||||
Clear
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{warning && (
|
||||
<div
|
||||
className="warning signWarning"
|
||||
style={{ fontSize: 12 }}
|
||||
>
|
||||
<i
|
||||
className="fas fa-exclamation-circle"
|
||||
style={{ color: "#fab005", fontSize: 15 }}
|
||||
></i>{" "}
|
||||
Please upload signature/Image
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ position: "relative" }}>
|
||||
<div style={{ margin: "6px 5px 18px" }}>
|
||||
<span
|
||||
// onClick={() => handleSignatureBtn()}
|
||||
className="signature"
|
||||
>
|
||||
Initials
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
{isInitials ? (
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
|
||||
border: "2px solid #888",
|
||||
marginBottom: 6,
|
||||
}}
|
||||
className="signatureCanvas"
|
||||
>
|
||||
<img
|
||||
alt="preview image"
|
||||
src={Initials}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<SignatureCanvas
|
||||
ref={initailsRef}
|
||||
penColor={initialPen}
|
||||
canvasProps={{
|
||||
width: "456px",
|
||||
height: "180px",
|
||||
className: "signatureCanvas",
|
||||
}}
|
||||
backgroundColor="rgb(255, 255, 255)"
|
||||
onEnd={() =>
|
||||
handleInitialsChange(initailsRef.current.toDataURL())
|
||||
}
|
||||
dotSize={1}
|
||||
/>
|
||||
)}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
// width: 460,
|
||||
}}
|
||||
className="penContainer"
|
||||
>
|
||||
<div>
|
||||
{!isInitials && (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
{allColor.map((data, key) => {
|
||||
return (
|
||||
<img
|
||||
alt="pen"
|
||||
style={{
|
||||
border: "none",
|
||||
margin: "5px",
|
||||
borderBottom:
|
||||
key === 0 && initialPen === "blue"
|
||||
? "2px solid blue"
|
||||
: key === 1 && initialPen === "red"
|
||||
? "2px solid red"
|
||||
: key === 2 && initialPen === "black"
|
||||
? "2px solid black"
|
||||
: "2px solid white",
|
||||
}}
|
||||
onClick={() => {
|
||||
if (key === 0) {
|
||||
setInitialPen("blue");
|
||||
} else if (key === 1) {
|
||||
setInitialPen("red");
|
||||
} else if (key === 2) {
|
||||
setInitialPen("black");
|
||||
}
|
||||
}}
|
||||
key={key}
|
||||
src={data}
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
type="button"
|
||||
className="clearbtn"
|
||||
onClick={() => handleClearInitials()}
|
||||
>
|
||||
Clear
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* {!warning && (
|
||||
<div className="warning signWarning" style={{ fontSize: 12 }}>
|
||||
<i
|
||||
className="fas fa-exclamation-circle"
|
||||
style={{ color: "#fab005", fontSize: 15 }}
|
||||
></i>{" "}
|
||||
Please upload signature/Image
|
||||
</div>
|
||||
)} */}
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ paddingTop: 10 }}>
|
||||
<button
|
||||
className="customBtn successBtn"
|
||||
onClick={(e) => handleSubmit(e)}
|
||||
>
|
||||
save
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{isLoader && (
|
||||
<div className="loaderContainer">
|
||||
<div className="loader"></div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManageSign;
|
||||
@@ -1,16 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
const PageNotFound = () => {
|
||||
return (
|
||||
<div className="flex items-center justify-center h-screen w-full bg-white rounded">
|
||||
<div className="text-center">
|
||||
<h1 className="text-[60px] lg:text-[120px] font-semibold text-black">
|
||||
404
|
||||
</h1>
|
||||
<p className="text-[30px] lg:text-[50px] text-black">Page Not Found</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PageNotFound;
|
||||
@@ -1,999 +0,0 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import "../css/./signature.css";
|
||||
import sign from "../assests/sign3.png";
|
||||
import stamp from "../assests/stamp2.png";
|
||||
import { themeColor } from "../utils/ThemeColor/backColor";
|
||||
import axios from "axios";
|
||||
import Loader from "./component/loader";
|
||||
import RenderAllPdfPage from "./component/renderAllPdfPage";
|
||||
import { DndProvider } from "react-dnd";
|
||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||
import { useDrag, useDrop } from "react-dnd";
|
||||
import SignPad from "./component/signPad";
|
||||
import EmailComponent from "./component/emailComponent";
|
||||
import FieldsComponent from "./component/fieldsComponent";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import ModalHeader from "react-bootstrap/esm/ModalHeader";
|
||||
import {
|
||||
convertPNGtoJPEG,
|
||||
contractDocument,
|
||||
getBase64FromIMG,
|
||||
embedDocId,
|
||||
multiSignEmbed,
|
||||
pdfNewWidthFun,
|
||||
addDefaultSignatureImg,
|
||||
onImageSelect
|
||||
} from "../utils/Utils";
|
||||
import { useParams } from "react-router-dom";
|
||||
import Tour from "reactour";
|
||||
import { onSaveImage, onSaveSign } from "../utils/Utils";
|
||||
import Signedby from "./component/signedby";
|
||||
import HandleError from "./component/HandleError";
|
||||
import Nodata from "./component/Nodata";
|
||||
import Header from "./component/header";
|
||||
import RenderPdf from "./component/renderPdf";
|
||||
import { contractUsers, contactBook, urlValidator } from "../utils/Utils";
|
||||
import { modalAlign } from "../utils/Utils";
|
||||
import AlertComponent from "./component/alertComponent";
|
||||
|
||||
//For signYourself inProgress section signer can add sign and complete doc sign.
|
||||
function SignYourSelf() {
|
||||
const [pdfDetails, setPdfDetails] = useState([]);
|
||||
const [isSignPad, setIsSignPad] = useState(false);
|
||||
const [allPages, setAllPages] = useState(null);
|
||||
const [pdfUrl, setPdfUrl] = useState();
|
||||
const [xyPostion, setXyPostion] = useState([]);
|
||||
const [defaultSignImg, setDefaultSignImg] = useState();
|
||||
const numPages = 1;
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
const [image, setImage] = useState(null);
|
||||
const [isImageSelect, setIsImageSelect] = useState(false);
|
||||
const [signature, setSignature] = useState();
|
||||
const [isStamp, setIsStamp] = useState(false);
|
||||
const [isEmail, setIsEmail] = useState(false);
|
||||
const [signBtnPosition, setSignBtnPosition] = useState([]);
|
||||
const [xySignature, setXYSignature] = useState({});
|
||||
const signRef = useRef(null);
|
||||
const dragRef = useRef(null);
|
||||
const [dragKey, setDragKey] = useState();
|
||||
const [signKey, setSignKey] = useState();
|
||||
const [imgWH, setImgWH] = useState({});
|
||||
const [isCeleb, setIsCeleb] = useState(false);
|
||||
const [pdfNewWidth, setPdfNewWidth] = useState();
|
||||
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
|
||||
const [successEmail, setSuccessEmail] = useState(false);
|
||||
const imageRef = useRef(null);
|
||||
const [documentStatus, setDocumentStatus] = useState({ isCompleted: false });
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
});
|
||||
const [handleError, setHandleError] = useState();
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [signTour, setSignTour] = useState(true);
|
||||
const { docId } = useParams();
|
||||
const [checkTourStatus, setCheckTourStatus] = useState(false);
|
||||
const [signerUserId, setSignerUserId] = useState();
|
||||
const [tourStatus, setTourStatus] = useState([]);
|
||||
const [noData, setNoData] = useState(false);
|
||||
const [contractName, setContractName] = useState("");
|
||||
const [containerWH, setContainerWH] = useState({});
|
||||
const [showAlreadySignDoc, setShowAlreadySignDoc] = useState({
|
||||
status: false
|
||||
});
|
||||
const [pdfLoadFail, setPdfLoadFail] = useState({
|
||||
status: false,
|
||||
type: "load"
|
||||
});
|
||||
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
||||
const divRef = useRef(null);
|
||||
const nodeRef = useRef(null);
|
||||
const [{ isOver }, drop] = useDrop({
|
||||
accept: "BOX",
|
||||
drop: (item, monitor) => addPositionOfSignature(item, monitor),
|
||||
collect: (monitor) => ({
|
||||
isOver: !!monitor.isOver()
|
||||
})
|
||||
});
|
||||
const isMobile = window.innerWidth < 767;
|
||||
|
||||
const pdfRef = useRef();
|
||||
|
||||
const [{ isDragSign }, dragSignature] = useDrag({
|
||||
type: "BOX",
|
||||
|
||||
item: {
|
||||
type: "BOX",
|
||||
id: 1,
|
||||
text: "drag me"
|
||||
},
|
||||
collect: (monitor) => ({
|
||||
isDragSign: !!monitor.isDragging()
|
||||
})
|
||||
});
|
||||
|
||||
const [{ isDragStamp }, dragStamp] = useDrag({
|
||||
type: "BOX",
|
||||
|
||||
item: {
|
||||
type: "BOX",
|
||||
id: 2,
|
||||
text: "drag me"
|
||||
},
|
||||
collect: (monitor) => ({
|
||||
isDragStamp: !!monitor.isDragging()
|
||||
})
|
||||
});
|
||||
const [{ isDragSignatureSS }, dragSignatureSS] = useDrag({
|
||||
type: "BOX",
|
||||
|
||||
item: {
|
||||
type: "BOX",
|
||||
id: 3,
|
||||
text: "drag me"
|
||||
},
|
||||
collect: (monitor) => ({
|
||||
isDragSignatureSS: !!monitor.isDragging()
|
||||
})
|
||||
});
|
||||
|
||||
const [{ isDragStampSS }, dragStampSS] = useDrag({
|
||||
type: "BOX",
|
||||
|
||||
item: {
|
||||
type: "BOX",
|
||||
id: 4,
|
||||
text: "drag me"
|
||||
},
|
||||
collect: (monitor) => ({
|
||||
isDragStampSS: !!monitor.isDragging()
|
||||
})
|
||||
});
|
||||
|
||||
const index = xyPostion.findIndex((object) => {
|
||||
return object.pageNumber === pageNumber;
|
||||
});
|
||||
// rowlevel={JSON.parse(localStorage.getItem("rowlevel"))}
|
||||
const rowLevel =
|
||||
localStorage.getItem("rowlevel") &&
|
||||
JSON.parse(localStorage.getItem("rowlevel"));
|
||||
|
||||
const signObjId =
|
||||
rowLevel && rowLevel?.id
|
||||
? rowLevel.id
|
||||
: rowLevel?.objectId && rowLevel.objectId;
|
||||
|
||||
const documentId = docId ? docId : signObjId && signObjId;
|
||||
const senderUser =
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
) &&
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
);
|
||||
const jsonSender = JSON.parse(senderUser);
|
||||
|
||||
useEffect(() => {
|
||||
if (documentId) {
|
||||
getDocumentDetails(true);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (divRef.current) {
|
||||
const pdfWidth = pdfNewWidthFun(divRef);
|
||||
setPdfNewWidth(pdfWidth);
|
||||
setContainerWH({
|
||||
width: divRef.current.offsetWidth,
|
||||
height: divRef.current.offsetHeight
|
||||
});
|
||||
}
|
||||
}, [divRef.current]);
|
||||
|
||||
//function for get document details for perticular signer with signer'object id
|
||||
const getDocumentDetails = async (showComplete) => {
|
||||
//getting document details
|
||||
const documentData = await contractDocument(documentId);
|
||||
|
||||
if (documentData && documentData.length > 0) {
|
||||
setPdfDetails(documentData);
|
||||
const isCompleted =
|
||||
documentData[0].IsCompleted && documentData[0].IsCompleted;
|
||||
if (isCompleted) {
|
||||
const docStatus = {
|
||||
isCompleted: isCompleted
|
||||
};
|
||||
setDocumentStatus(docStatus);
|
||||
setPdfUrl(documentData[0].SignedUrl);
|
||||
const alreadySign = {
|
||||
status: true,
|
||||
mssg: "You have successfully signed the document!"
|
||||
};
|
||||
if (showComplete) {
|
||||
setShowAlreadySignDoc(alreadySign);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(documentData.result && documentData.result.error)
|
||||
) {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
} else {
|
||||
setNoData(true);
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Signature?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${
|
||||
jsonSender.objectId
|
||||
}"}}`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
)
|
||||
.then((Listdata) => {
|
||||
const json = Listdata.data;
|
||||
const res = json.results;
|
||||
|
||||
if (res[0] && res.length > 0) {
|
||||
setDefaultSignImg(res[0].ImageURL);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
});
|
||||
|
||||
const contractUsersRes = await contractUsers(jsonSender.email);
|
||||
|
||||
if (contractUsersRes[0] && contractUsersRes.length > 0) {
|
||||
setContractName("_Users");
|
||||
setSignerUserId(contractUsersRes[0].objectId);
|
||||
const tourstatuss =
|
||||
contractUsersRes[0].TourStatus && contractUsersRes[0].TourStatus;
|
||||
|
||||
if (tourstatuss && tourstatuss.length > 0) {
|
||||
setTourStatus(tourstatuss);
|
||||
const checkTourRecipients = tourstatuss.filter(
|
||||
(data) => data.signyourself
|
||||
);
|
||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||
setCheckTourStatus(checkTourRecipients[0].signyourself);
|
||||
}
|
||||
}
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
} else if (contractUsersRes === "Error: Something went wrong!") {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
} else if (contractUsersRes.length === 0) {
|
||||
const contractContactBook = await contactBook(jsonSender.objectId);
|
||||
if (contractContactBook && contractContactBook.length > 0) {
|
||||
setContractName("_Contactbook");
|
||||
setSignerUserId(contractContactBook[0].objectId);
|
||||
const tourstatuss =
|
||||
contractContactBook[0].TourStatus &&
|
||||
contractContactBook[0].TourStatus;
|
||||
if (tourstatuss && tourstatuss.length > 0) {
|
||||
setTourStatus(tourstatuss);
|
||||
const checkTourRecipients = tourstatuss.filter(
|
||||
(data) => data.signyourself
|
||||
);
|
||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||
setCheckTourStatus(checkTourRecipients[0].signyourself);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setNoData(true);
|
||||
}
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
};
|
||||
|
||||
//function for setting position after drop signature button over pdf
|
||||
const addPositionOfSignature = (item, monitor) => {
|
||||
const key = Math.floor(1000 + Math.random() * 9000);
|
||||
let dropData = [];
|
||||
let filterDropPos = xyPostion.filter(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
if (item === "onclick") {
|
||||
const dropObj = {
|
||||
xPosition: window.innerWidth / 2 - 100,
|
||||
yPosition: window.innerHeight / 2 - 60,
|
||||
isDrag: false,
|
||||
key: key,
|
||||
isStamp: monitor,
|
||||
|
||||
yBottom: window.innerHeight / 2 - 60
|
||||
};
|
||||
|
||||
dropData.push(dropObj);
|
||||
|
||||
if (monitor) {
|
||||
setIsStamp(true);
|
||||
} else {
|
||||
setIsStamp(false);
|
||||
}
|
||||
} else {
|
||||
const offset = monitor.getClientOffset();
|
||||
//adding and updating drop position in array when user drop signature button in div
|
||||
const containerRect = document
|
||||
.getElementById("container")
|
||||
.getBoundingClientRect();
|
||||
|
||||
const x = offset.x - containerRect.left;
|
||||
const y = offset.y - containerRect.top;
|
||||
const ybottom = containerRect.bottom - offset.y;
|
||||
|
||||
const dropObj = {
|
||||
xPosition: signBtnPosition[0] ? x - signBtnPosition[0].xPos : x,
|
||||
yPosition: signBtnPosition[0] ? y - signBtnPosition[0].yPos : y,
|
||||
isDrag: false,
|
||||
key: key,
|
||||
isStamp: isDragStamp || isDragStampSS ? true : false,
|
||||
firstXPos: signBtnPosition[0] && signBtnPosition[0].xPos,
|
||||
firstYPos: signBtnPosition[0] && signBtnPosition[0].yPos,
|
||||
yBottom: ybottom
|
||||
};
|
||||
|
||||
dropData.push(dropObj);
|
||||
|
||||
if (isDragStamp || isDragStampSS) {
|
||||
setIsStamp(true);
|
||||
} else {
|
||||
setIsStamp(false);
|
||||
}
|
||||
}
|
||||
if (filterDropPos.length > 0) {
|
||||
const index = xyPostion.findIndex((object) => {
|
||||
return object.pageNumber === pageNumber;
|
||||
});
|
||||
const updateData = filterDropPos[0].pos;
|
||||
|
||||
// if (updateData.length > dropData.length) {
|
||||
const newSignPos = updateData.concat(dropData);
|
||||
let xyPos = {
|
||||
pageNumber: pageNumber,
|
||||
pos: newSignPos
|
||||
};
|
||||
xyPostion.splice(index, 1, xyPos);
|
||||
setIsSignPad(true);
|
||||
setSignKey(key);
|
||||
// }
|
||||
} else {
|
||||
const xyPos = {
|
||||
pageNumber: pageNumber,
|
||||
pos: dropData
|
||||
};
|
||||
setXyPostion((prev) => [...prev, xyPos]);
|
||||
setIsSignPad(true);
|
||||
setSignKey(key);
|
||||
}
|
||||
|
||||
// setXyPostion((prev) => [...prev, xyPos]);
|
||||
};
|
||||
|
||||
//function for send placeholder's co-ordinate(x,y) position embed signature url or stamp url
|
||||
async function embedImages() {
|
||||
let checkSignUrl = [];
|
||||
|
||||
for (let i = 0; i < xyPostion.length; i++) {
|
||||
const posData = xyPostion[i].pos.filter((pos) => !pos.SignUrl);
|
||||
if (posData && posData.length > 0) {
|
||||
checkSignUrl.push(posData);
|
||||
}
|
||||
}
|
||||
if (xyPostion.length === 0) {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "Please complete your signature!"
|
||||
});
|
||||
return;
|
||||
} else if (xyPostion.length > 0 && checkSignUrl.length > 0) {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "Please complete your signature!"
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
setIsCeleb(true);
|
||||
setTimeout(() => {
|
||||
setIsCeleb(false);
|
||||
}, 3000);
|
||||
const loadObj = {
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
const url = pdfDetails[0] && pdfDetails[0].URL;
|
||||
|
||||
const existingPdfBytes = await fetch(url).then((res) =>
|
||||
res.arrayBuffer()
|
||||
);
|
||||
|
||||
// Load a PDFDocument from the existing PDF bytes
|
||||
const pdfDoc = await PDFDocument.load(existingPdfBytes, {
|
||||
ignoreEncryption: true
|
||||
});
|
||||
|
||||
//checking if signature is only one then send image url in jpeg formate to server
|
||||
if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) {
|
||||
//embed document's object id to all pages in pdf document
|
||||
await embedDocId(pdfDoc, documentId, allPages);
|
||||
const pdfBase64 = await pdfDoc.saveAsBase64({
|
||||
useObjectStreams: false
|
||||
});
|
||||
|
||||
for (let xyData of xyPostion) {
|
||||
const imgUrlList = xyData.pos;
|
||||
const pageNo = xyData.pageNumber;
|
||||
imgUrlList.map(async (data) => {
|
||||
let ImgUrl = data.SignUrl;
|
||||
//cheking signUrl is defau;t signature url of custom url
|
||||
const checkUrl = urlValidator(ImgUrl);
|
||||
//if default signature url then convert it in base 64
|
||||
if (checkUrl) {
|
||||
ImgUrl = await getBase64FromIMG(ImgUrl + "?get");
|
||||
}
|
||||
//function for convert signature png base64 url to jpeg base64
|
||||
convertPNGtoJPEG(ImgUrl)
|
||||
.then((jpegBase64Data) => {
|
||||
const removeBase64Fromjpeg = "data:image/jpeg;base64,";
|
||||
const newImgUrl = jpegBase64Data.replace(
|
||||
removeBase64Fromjpeg,
|
||||
""
|
||||
);
|
||||
//function for call to embed signature in pdf and get digital signature pdf
|
||||
signPdfFun(newImgUrl, documentId, data, pdfBase64, pageNo);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error:", error);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
//else if signature is more than one then embed all sign with the use of pdf-lib
|
||||
else if (xyPostion.length > 0 && xyPostion[0].pos.length > 0) {
|
||||
const flag = true;
|
||||
//embed document's object id to all pages in pdf document
|
||||
await embedDocId(pdfDoc, documentId, allPages);
|
||||
|
||||
//embed multi signature in pdf
|
||||
const pdfBytes = await multiSignEmbed(
|
||||
xyPostion,
|
||||
pdfDoc,
|
||||
pdfOriginalWidth,
|
||||
flag,
|
||||
containerWH
|
||||
);
|
||||
|
||||
//function for call to embed signature in pdf and get digital signature pdf
|
||||
signPdfFun(pdfBytes, documentId);
|
||||
}
|
||||
setIsSignPad(false);
|
||||
setIsEmail(true);
|
||||
setXyPostion([]);
|
||||
setSignBtnPosition([]);
|
||||
}
|
||||
}
|
||||
|
||||
//function for get digital signature
|
||||
const signPdfFun = async (
|
||||
base64Url,
|
||||
documentId,
|
||||
xyPosData,
|
||||
pdfBase64Url,
|
||||
pageNo
|
||||
) => {
|
||||
let singleSign;
|
||||
const newWidth = containerWH.width;
|
||||
const scale = isMobile ? pdfOriginalWidth / newWidth : 1;
|
||||
|
||||
if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) {
|
||||
const height = xyPosData.Height ? xyPosData.Height : 60;
|
||||
const bottomY = xyPosData.isDrag
|
||||
? xyPosData.yBottom * scale - height * scale
|
||||
: xyPosData.firstYPos
|
||||
? xyPosData.yBottom * scale - height * scale + xyPosData.firstYPos
|
||||
: xyPosData.yBottom * scale - height * scale;
|
||||
|
||||
singleSign = {
|
||||
pdfFile: pdfBase64Url,
|
||||
docId: documentId,
|
||||
sign: {
|
||||
Base64: base64Url,
|
||||
Left: isMobile ? xyPosData.xPosition * scale : xyPosData.xPosition,
|
||||
Bottom: bottomY,
|
||||
Width: xyPosData.Width ? xyPosData.Width * scale : 150 * scale,
|
||||
Height: height * scale,
|
||||
Page: pageNo
|
||||
}
|
||||
};
|
||||
} else if (xyPostion.length > 0 && xyPostion[0].pos.length > 0) {
|
||||
singleSign = {
|
||||
pdfFile: base64Url,
|
||||
docId: documentId
|
||||
};
|
||||
}
|
||||
|
||||
await axios
|
||||
.post(`${localStorage.getItem("baseUrl")}functions/signPdf`, singleSign, {
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
}
|
||||
})
|
||||
.then((Listdata) => {
|
||||
const json = Listdata.data;
|
||||
|
||||
setPdfUrl(json.result.data);
|
||||
if (json.result.data) {
|
||||
getDocumentDetails(false);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("axois err ", err);
|
||||
});
|
||||
};
|
||||
|
||||
//function for save x and y position and show signature tab on that position
|
||||
const handleTabDrag = (key, e) => {
|
||||
setDragKey(key);
|
||||
setIsDragging(true);
|
||||
};
|
||||
|
||||
//function for set and update x and y postion after drag and drop signature tab
|
||||
const handleStop = (event, dragElement) => {
|
||||
if (isDragging && dragElement) {
|
||||
event.preventDefault();
|
||||
const containerRect = document
|
||||
.getElementById("container")
|
||||
.getBoundingClientRect();
|
||||
|
||||
const ybottom = containerRect.height - dragElement.y;
|
||||
|
||||
if (dragKey >= 0) {
|
||||
const filterDropPos = xyPostion.filter(
|
||||
(data) => data.pageNumber === pageNumber
|
||||
);
|
||||
|
||||
if (filterDropPos.length > 0) {
|
||||
const getXYdata = xyPostion[index].pos;
|
||||
const getPosData = getXYdata;
|
||||
const addSign = getPosData.map((url, ind) => {
|
||||
if (url.key === dragKey) {
|
||||
return {
|
||||
...url,
|
||||
xPosition: dragElement.x,
|
||||
yPosition: dragElement.y,
|
||||
isDrag: true,
|
||||
yBottom: ybottom
|
||||
};
|
||||
}
|
||||
return url;
|
||||
});
|
||||
|
||||
const newUpdateUrl = xyPostion.map((obj, ind) => {
|
||||
if (ind === index) {
|
||||
return { ...obj, pos: addSign };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
setXyPostion(newUpdateUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
setIsDragging(false);
|
||||
}, 200);
|
||||
};
|
||||
|
||||
//function for get pdf page details
|
||||
const pageDetails = async (pdf) => {
|
||||
const load = {
|
||||
status: true
|
||||
};
|
||||
setPdfLoadFail(load);
|
||||
pdf.getPage(1).then((pdfPage) => {
|
||||
const pageWidth = pdfPage.view[2];
|
||||
|
||||
setPdfOriginalWidth(pageWidth);
|
||||
});
|
||||
};
|
||||
|
||||
//function for change page numver of pdf
|
||||
function changePage(offset) {
|
||||
setSignBtnPosition([]);
|
||||
setPageNumber((prevPageNumber) => prevPageNumber + offset);
|
||||
}
|
||||
|
||||
//function for image upload or update
|
||||
const onImageChange = (event) => {
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
onImageSelect(event, setImgWH, setImage);
|
||||
}
|
||||
};
|
||||
|
||||
//function for upload stamp or image
|
||||
const saveImage = () => {
|
||||
const getImage = onSaveImage(xyPostion, index, signKey, imgWH, image);
|
||||
setXyPostion(getImage);
|
||||
};
|
||||
|
||||
//function for save button to save signature or image url
|
||||
const saveSign = (isDefaultSign) => {
|
||||
const signatureImg = isDefaultSign ? defaultSignImg : signature;
|
||||
const signFlag = true;
|
||||
let imgWH = { width: "", height: "" };
|
||||
setIsSignPad(false);
|
||||
setIsImageSelect(false);
|
||||
setImage();
|
||||
|
||||
if (isDefaultSign) {
|
||||
const img = new Image();
|
||||
img.src = defaultSignImg;
|
||||
if (img.complete) {
|
||||
imgWH = {
|
||||
width: img.width,
|
||||
height: img.height
|
||||
};
|
||||
}
|
||||
}
|
||||
const getUpdatePosition = onSaveSign(
|
||||
xyPostion,
|
||||
index,
|
||||
signKey,
|
||||
signatureImg,
|
||||
imgWH,
|
||||
isDefaultSign,
|
||||
signFlag
|
||||
);
|
||||
|
||||
setXyPostion(getUpdatePosition);
|
||||
};
|
||||
|
||||
//function for capture position on hover signature button
|
||||
const handleDivClick = (e) => {
|
||||
const divRect = e.currentTarget.getBoundingClientRect();
|
||||
const mouseX = e.clientX - divRect.left;
|
||||
const mouseY = e.clientY - divRect.top;
|
||||
|
||||
const xyPosition = {
|
||||
xPos: mouseX,
|
||||
yPos: mouseY
|
||||
};
|
||||
|
||||
setXYSignature(xyPosition);
|
||||
};
|
||||
|
||||
//function for capture position of x and y on hover signature button last position
|
||||
const handleMouseLeave = (e) => {
|
||||
setSignBtnPosition([xySignature]);
|
||||
};
|
||||
|
||||
const handleAllDelete = () => {
|
||||
setXyPostion([]);
|
||||
};
|
||||
|
||||
//function for delete signature block
|
||||
const handleDeleteSign = (key) => {
|
||||
const updateResizeData = [];
|
||||
|
||||
let filterData = xyPostion[index].pos.filter((data) => data.key !== key);
|
||||
|
||||
//delete and update block position
|
||||
if (filterData.length > 0) {
|
||||
updateResizeData.push(filterData);
|
||||
const newUpdatePos = xyPostion.map((obj, ind) => {
|
||||
if (ind === index) {
|
||||
return { ...obj, pos: updateResizeData[0] };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
|
||||
setXyPostion(newUpdatePos);
|
||||
} else {
|
||||
const getRemainPage = xyPostion.filter(
|
||||
(data) => data.pageNumber !== pageNumber
|
||||
);
|
||||
|
||||
if (getRemainPage && getRemainPage.length > 0) {
|
||||
setXyPostion(getRemainPage);
|
||||
} else {
|
||||
setXyPostion([]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//function for add default signature url in local array
|
||||
const addDefaultSignature = () => {
|
||||
const getXyData = addDefaultSignatureImg(xyPostion, defaultSignImg);
|
||||
|
||||
setXyPostion(getXyData);
|
||||
setShowAlreadySignDoc({ status: false });
|
||||
};
|
||||
const tourConfig = [
|
||||
{
|
||||
selector: '[data-tut="reactourFirst"]',
|
||||
content: `Drag the signature or stamp placeholder onto the PDF to choose your desired signing location.`,
|
||||
position: "top",
|
||||
style: { fontSize: "13px" }
|
||||
},
|
||||
{
|
||||
selector: '[data-tut="reactourSecond"]',
|
||||
content: `Drag and drop anywhere in this area. You can resize and move it later.`,
|
||||
position: "top",
|
||||
style: { fontSize: "13px" }
|
||||
}
|
||||
];
|
||||
|
||||
//function for update TourStatus
|
||||
const closeTour = async () => {
|
||||
setSignTour(false);
|
||||
|
||||
let updatedTourStatus = [];
|
||||
if (tourStatus.length > 0) {
|
||||
updatedTourStatus = [...tourStatus];
|
||||
const signyourselfIndex = tourStatus.findIndex(
|
||||
(obj) => obj["signyourself"] === false || obj["signyourself"] === true
|
||||
);
|
||||
if (signyourselfIndex !== -1) {
|
||||
updatedTourStatus[signyourselfIndex] = { signyourself: true };
|
||||
} else {
|
||||
updatedTourStatus.push({ signyourself: true });
|
||||
}
|
||||
} else {
|
||||
updatedTourStatus = [{ signyourself: true }];
|
||||
}
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}${contractName}/${signerUserId}`,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
)
|
||||
.then((Listdata) => {
|
||||
// const json = Listdata.data;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("axois err ", err);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
{isLoading.isLoad ? (
|
||||
<Loader isLoading={isLoading} />
|
||||
) : handleError ? (
|
||||
<HandleError handleError={handleError} />
|
||||
) : noData ? (
|
||||
<Nodata />
|
||||
) : (
|
||||
<div className="signatureContainer" ref={divRef}>
|
||||
{/* this component used for UI interaction and show their functionality */}
|
||||
{pdfLoadFail && !checkTourStatus && (
|
||||
<Tour
|
||||
onRequestClose={closeTour}
|
||||
steps={tourConfig}
|
||||
isOpen={signTour}
|
||||
rounded={5}
|
||||
closeWithMask={false}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* this component used to render all pdf pages in left side */}
|
||||
|
||||
<RenderAllPdfPage
|
||||
pdfUrl={pdfUrl}
|
||||
signPdfUrl={pdfDetails[0] && pdfDetails[0].URL}
|
||||
allPages={allPages}
|
||||
setAllPages={setAllPages}
|
||||
setPageNumber={setPageNumber}
|
||||
setSignBtnPosition={setSignBtnPosition}
|
||||
/>
|
||||
|
||||
{/* pdf render view */}
|
||||
<div
|
||||
style={{
|
||||
marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px",
|
||||
marginRight: !isMobile && pdfOriginalWidth > 500 && "20px"
|
||||
}}
|
||||
>
|
||||
<AlertComponent
|
||||
isShow={isAlert.isShow}
|
||||
alertMessage={isAlert.alertMessage}
|
||||
setIsAlert={setIsAlert}
|
||||
/>
|
||||
{/* this modal is used show this document is already sign */}
|
||||
<Modal
|
||||
show={showAlreadySignDoc.status}
|
||||
onShow={() => modalAlign()}
|
||||
backdropClassName="signature-backdrop"
|
||||
>
|
||||
<ModalHeader style={{ background: themeColor() }}>
|
||||
<span style={{ color: "white" }}> Sign Documents</span>
|
||||
</ModalHeader>
|
||||
|
||||
<Modal.Body>
|
||||
<p>{showAlreadySignDoc.mssg}</p>
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<button
|
||||
style={{
|
||||
borderRadius: "0px",
|
||||
border: "1.5px solid #e3e2e1",
|
||||
fontWeight: "600",
|
||||
color: "black"
|
||||
}}
|
||||
className="btn"
|
||||
onClick={() => setShowAlreadySignDoc({ status: false })}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
{showAlreadySignDoc.sure && (
|
||||
<button
|
||||
onClick={() => addDefaultSignature()}
|
||||
style={{
|
||||
background: themeColor()
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
)}
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
{/* this is modal of signature pad */}
|
||||
<SignPad
|
||||
isSignPad={isSignPad}
|
||||
isStamp={isStamp}
|
||||
setIsImageSelect={setIsImageSelect}
|
||||
setIsSignPad={setIsSignPad}
|
||||
setImage={setImage}
|
||||
isImageSelect={isImageSelect}
|
||||
imageRef={imageRef}
|
||||
onImageChange={onImageChange}
|
||||
setSignature={setSignature}
|
||||
image={image}
|
||||
onSaveImage={saveImage}
|
||||
onSaveSign={saveSign}
|
||||
defaultSign={defaultSignImg}
|
||||
/>
|
||||
{/* render email component to send email after finish signature on document */}
|
||||
<EmailComponent
|
||||
isEmail={isEmail}
|
||||
pdfUrl={pdfUrl}
|
||||
isCeleb={isCeleb}
|
||||
setIsEmail={setIsEmail}
|
||||
pdfName={pdfDetails[0] && pdfDetails[0].Name}
|
||||
setSuccessEmail={setSuccessEmail}
|
||||
sender={jsonSender}
|
||||
setIsAlert={setIsAlert}
|
||||
/>
|
||||
{/* pdf header which contain funish back button */}
|
||||
<Header
|
||||
pageNumber={pageNumber}
|
||||
allPages={allPages}
|
||||
changePage={changePage}
|
||||
pdfUrl={pdfUrl}
|
||||
documentStatus={documentStatus}
|
||||
embedImages={embedImages}
|
||||
pdfDetails={pdfDetails}
|
||||
isShowHeader={true}
|
||||
currentSigner={true}
|
||||
alreadySign={pdfUrl ? true : false}
|
||||
isSignYourself={true}
|
||||
setIsEmail={setIsEmail}
|
||||
/>
|
||||
|
||||
<div data-tut="reactourSecond">
|
||||
{containerWH && (
|
||||
<RenderPdf
|
||||
pageNumber={pageNumber}
|
||||
pdfOriginalWidth={pdfOriginalWidth}
|
||||
pdfNewWidth={pdfNewWidth}
|
||||
drop={drop}
|
||||
successEmail={successEmail}
|
||||
nodeRef={nodeRef}
|
||||
handleTabDrag={handleTabDrag}
|
||||
handleStop={handleStop}
|
||||
isDragging={isDragging}
|
||||
setIsSignPad={setIsSignPad}
|
||||
setIsStamp={setIsStamp}
|
||||
handleDeleteSign={handleDeleteSign}
|
||||
setSignKey={setSignKey}
|
||||
pdfDetails={pdfDetails}
|
||||
setIsDragging={setIsDragging}
|
||||
xyPostion={xyPostion}
|
||||
pdfRef={pdfRef}
|
||||
pdfUrl={pdfUrl}
|
||||
numPages={numPages}
|
||||
pageDetails={pageDetails}
|
||||
setPdfLoadFail={setPdfLoadFail}
|
||||
pdfLoadFail={pdfLoadFail}
|
||||
setXyPostion={setXyPostion}
|
||||
index={index}
|
||||
containerWH={containerWH}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/*if document is not completed then render signature and stamp button in the right side */}
|
||||
{/*else document is completed then render signed by signer name in the right side */}
|
||||
{!documentStatus.isCompleted ? (
|
||||
<div>
|
||||
<FieldsComponent
|
||||
dataTut="reactourFirst"
|
||||
pdfUrl={pdfUrl}
|
||||
sign={sign}
|
||||
stamp={stamp}
|
||||
dragSignature={dragSignature}
|
||||
signRef={signRef}
|
||||
handleDivClick={handleDivClick}
|
||||
handleMouseLeave={handleMouseLeave}
|
||||
isDragSign={isDragSign}
|
||||
themeColor={themeColor}
|
||||
dragStamp={dragStamp}
|
||||
dragRef={dragRef}
|
||||
isDragStamp={isDragStamp}
|
||||
isDragSignatureSS={isDragSignatureSS}
|
||||
dragSignatureSS={dragSignatureSS}
|
||||
dragStampSS={dragStampSS}
|
||||
handleAllDelete={handleAllDelete}
|
||||
xyPostion={xyPostion}
|
||||
isSignYourself={true}
|
||||
addPositionOfSignature={addPositionOfSignature}
|
||||
isMailSend={false}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<Signedby pdfDetails={pdfDetails[0]} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</DndProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignYourSelf;
|
||||
@@ -1,59 +0,0 @@
|
||||
import React from "react";
|
||||
import "../../css/customModal.css";
|
||||
import "../../css/signature.css";
|
||||
|
||||
function CustomModal({
|
||||
show,
|
||||
headMsg,
|
||||
bodyMssg,
|
||||
footerMessage,
|
||||
declineDoc,
|
||||
setIsDecline,
|
||||
containerWH
|
||||
}) {
|
||||
const isMobile = window.innerWidth < 767;
|
||||
return (
|
||||
show && (
|
||||
<div
|
||||
className="parentDiv"
|
||||
style={{
|
||||
width: containerWH && containerWH.width,
|
||||
height: isMobile ? "100%" : containerWH && containerWH.height
|
||||
}}
|
||||
>
|
||||
<div className="childDiv">
|
||||
<div className="modalHeadDiv bg-danger">{headMsg && headMsg}</div>
|
||||
<div className="modalBodyDIv">
|
||||
<p className="pTagBody">{bodyMssg && bodyMssg}</p>
|
||||
</div>
|
||||
{footerMessage && (
|
||||
<div className="modalFooterDiv">
|
||||
<button
|
||||
style={{
|
||||
color: "black"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
onClick={() => setIsDecline({ isDeclined: false })}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
style={{
|
||||
background: "#de4337"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
onClick={() => declineDoc()}
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
export default CustomModal;
|
||||
@@ -1,58 +0,0 @@
|
||||
import React from "react";
|
||||
import stamp from "../../assests/stamp2.png";
|
||||
import sign from "../../assests/sign3.png";
|
||||
import { themeColor } from "../../utils/ThemeColor/backColor";
|
||||
|
||||
function DragElement({ type, id }) {
|
||||
const selectedId = id;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{selectedId === 3 ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="sign img"
|
||||
style={{
|
||||
width: "25px",
|
||||
height: "23px",
|
||||
background: themeColor(),
|
||||
}}
|
||||
src={sign}
|
||||
/>
|
||||
<span style={{ color: themeColor(), fontSize: "12px" }}>
|
||||
Signature
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
userSelect: "none",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="stamp img"
|
||||
style={{
|
||||
width: "25px",
|
||||
height: "23px",
|
||||
background: themeColor(),
|
||||
}}
|
||||
src={stamp}
|
||||
/>
|
||||
<span style={{ color: themeColor(), fontSize: "12px" }}>Stamp</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DragElement;
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
function HandleError({ handleError }) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: "20px", color: "gray" }}>{handleError}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default HandleError;
|
||||
@@ -1,18 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
function Nodata() {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "50vh",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontWeight: "bold" }}>No Data Found!</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Nodata;
|
||||
@@ -1,79 +0,0 @@
|
||||
import React from "react";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import ModalHeader from "react-bootstrap/esm/ModalHeader";
|
||||
import { themeColor } from "../../utils/ThemeColor/backColor";
|
||||
|
||||
function AlertComponent({
|
||||
isShow,
|
||||
alertMessage,
|
||||
setIsAlert,
|
||||
isdefaultSign,
|
||||
addDefaultSignature,
|
||||
headBG
|
||||
}) {
|
||||
return (
|
||||
<Modal show={isShow}>
|
||||
<ModalHeader
|
||||
style={{
|
||||
color: "white",
|
||||
background: headBG ? themeColor() : "#dc3545"
|
||||
}}
|
||||
>
|
||||
<span>Alert</span>
|
||||
</ModalHeader>
|
||||
|
||||
<Modal.Body>
|
||||
<span>{alertMessage}</span>
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
{isdefaultSign ? (
|
||||
<>
|
||||
<button
|
||||
onClick={() => addDefaultSignature()}
|
||||
style={{
|
||||
background: themeColor()
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
>
|
||||
Yes
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsAlert({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
color: "black"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsAlert({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
});
|
||||
}}
|
||||
style={{
|
||||
color: "black"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
>
|
||||
Ok
|
||||
</button>
|
||||
)}
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default AlertComponent;
|
||||
@@ -1,17 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
function BorderResize() {
|
||||
return (
|
||||
<div
|
||||
className="borderResize"
|
||||
style={{
|
||||
right: "-1px",
|
||||
bottom: "-1px",
|
||||
borderRight: "3px solid #188ae2",
|
||||
borderBottom: "3px solid #188ae2"
|
||||
}}
|
||||
></div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BorderResize;
|
||||
@@ -1,81 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
function DefaultSignature({
|
||||
themeColor,
|
||||
defaultSignImg,
|
||||
xyPostion,
|
||||
setIsAlert
|
||||
}) {
|
||||
const confirmToaddDefaultSign = () => {
|
||||
if (xyPostion.length > 0) {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "Are you sure you want to sign at requested locations?"
|
||||
});
|
||||
} else {
|
||||
alert("please select position!");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="signerComponent">
|
||||
<div
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white",
|
||||
padding: "5px",
|
||||
fontFamily: "sans-serif"
|
||||
}}
|
||||
>
|
||||
Signature
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
marginTop: "10px",
|
||||
fontWeight: "600"
|
||||
}}
|
||||
>
|
||||
{defaultSignImg ? (
|
||||
<>
|
||||
<p>Your Signature</p>
|
||||
<div className="defaultSignBox">
|
||||
<img
|
||||
alt="default img"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
src={defaultSignImg}
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white",
|
||||
marginTop: "20px",
|
||||
cursor: "pointer"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn finishnHover"
|
||||
onClick={() => confirmToaddDefaultSign()}
|
||||
>
|
||||
Auto Sign All
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<div style={{ margin: "10px" }}>
|
||||
<span>
|
||||
Click a signature placeholder to start signing the document!
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DefaultSignature;
|
||||
@@ -1,410 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import { saveAs } from "file-saver";
|
||||
import celebration from "../../assests/newCeleb.gif";
|
||||
import close from "../../assests/close.png";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import ModalHeader from "react-bootstrap/esm/ModalHeader";
|
||||
import axios from "axios";
|
||||
import { getBase64FromUrl } from "../../utils/Utils";
|
||||
import { themeColor } from "../../utils/ThemeColor/backColor";
|
||||
import printModule from "print-js";
|
||||
import loader from "../../assests/loader2.gif";
|
||||
|
||||
function EmailComponent({
|
||||
isEmail,
|
||||
pdfUrl,
|
||||
isCeleb,
|
||||
setIsEmail,
|
||||
setSuccessEmail,
|
||||
pdfName,
|
||||
sender,
|
||||
setIsAlert
|
||||
}) {
|
||||
const [emailList, setEmailList] = useState([]);
|
||||
const [emailValue, setEmailValue] = useState();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
//function for send email
|
||||
const sendEmail = async () => {
|
||||
setIsLoading(true);
|
||||
let sendMail;
|
||||
for (let i = 0; i < emailList.length; i++) {
|
||||
try {
|
||||
const imgPng =
|
||||
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png";
|
||||
// "https://qikinnovation.ams3.digitaloceanspaces.com/mailLogo_2023-08-18T12%3A51%3A31.573Z.png";
|
||||
|
||||
let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
sessionToken: localStorage.getItem("accesstoken")
|
||||
};
|
||||
const openSignUrl = "https://www.opensignlabs.com/";
|
||||
const themeBGcolor = themeColor();
|
||||
let params = {
|
||||
pdfName: pdfName,
|
||||
url: pdfUrl,
|
||||
recipient: emailList[i],
|
||||
subject: `${sender.name} has signed the doc - ${pdfName}`,
|
||||
from: sender.email,
|
||||
html:
|
||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body> <div style='background-color:#f5f5f5;padding:20px'> <div style='box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background-color:white;'> <div><img src=" +
|
||||
imgPng +
|
||||
" height='50' style='padding:20px,width:170px,height:40px'/> </div><div style='padding:2px;font-family:system-ui; background-color:" +
|
||||
themeBGcolor +
|
||||
";'> <p style='font-size:20px;font-weight:400;color:white;padding-left:20px',> Document Copy</p></div><div><p style='padding:20px;font-family:system-ui;font-size:14px'>A copy of the document " +
|
||||
pdfName +
|
||||
" Standard is attached to this email. Kindly download the document from the attachment.</p></div> </div><div><p>This is an automated email from OpenSign. For any queries regarding this email, please contact the sender " +
|
||||
sender.email +
|
||||
" directly. If you think this email is inappropriate or spam, you may file a complaint with OpenSign <a href= " +
|
||||
openSignUrl +
|
||||
" target=_blank>here</a> </p></div></div></body></html>"
|
||||
};
|
||||
sendMail = await axios.post(url, params, { headers: headers });
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
setIsLoading(false);
|
||||
setIsEmail(false);
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (sendMail && sendMail.data.result.status === "success") {
|
||||
setSuccessEmail(true);
|
||||
setTimeout(() => {
|
||||
setSuccessEmail(false);
|
||||
setIsEmail(false);
|
||||
setEmailValue("");
|
||||
setEmailList([]);
|
||||
}, 1500);
|
||||
|
||||
setIsLoading(false);
|
||||
} else if (sendMail && sendMail.data.result.status === "error") {
|
||||
setIsLoading(false);
|
||||
setIsEmail(false);
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
setIsEmail(false);
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
//function for remove email
|
||||
const removeChip = (index) => {
|
||||
const updateEmailCount = emailList.filter((data, key) => key !== index);
|
||||
setEmailList(updateEmailCount);
|
||||
};
|
||||
//function for get email value
|
||||
const handleEmailValue = (e) => {
|
||||
const value = e.target.value;
|
||||
setEmailValue(value);
|
||||
};
|
||||
|
||||
//function for save email in array after press enter
|
||||
const handleEnterPress = (e) => {
|
||||
if (e.key === "Enter" && emailValue) {
|
||||
setEmailList((prev) => [...prev, emailValue]);
|
||||
setEmailValue("");
|
||||
} else if (e === "add" && emailValue) {
|
||||
setEmailList((prev) => [...prev, emailValue]);
|
||||
setEmailValue("");
|
||||
}
|
||||
};
|
||||
|
||||
// function for print signed pdf
|
||||
const handleToPrint = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const pdf = await getBase64FromUrl(pdfUrl);
|
||||
const isAndroidDevice = navigator.userAgent.match(/Android/i);
|
||||
const isAppleDevice =
|
||||
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1)) &&
|
||||
!window.MSStream;
|
||||
if (isAndroidDevice || isAppleDevice) {
|
||||
const byteArray = Uint8Array.from(
|
||||
atob(pdf)
|
||||
.split("")
|
||||
.map((char) => char.charCodeAt(0))
|
||||
);
|
||||
const blob = new Blob([byteArray], { type: "application/pdf" });
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
window.open(blobUrl, "_blank");
|
||||
} else {
|
||||
printModule({ printable: pdf, type: "pdf", base64: true });
|
||||
}
|
||||
};
|
||||
|
||||
//handle download signed pdf
|
||||
const handleDownloadPdf = () => {
|
||||
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
||||
};
|
||||
|
||||
const sanitizeFileName = (pdfName) => {
|
||||
// Replace spaces with underscore
|
||||
return pdfName.replace(/ /g, "_");
|
||||
};
|
||||
|
||||
const isAndroid = /Android/i.test(navigator.userAgent);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* isEmail */}
|
||||
<Modal show={isEmail}>
|
||||
{isLoading && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
height: "100%",
|
||||
width: "100%",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
zIndex: "20",
|
||||
backgroundColor: "#e6f2f2",
|
||||
opacity: 0.8
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
src={loader}
|
||||
style={{ width: "70px", height: "70px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "12px", fontWeight: "bold" }}>
|
||||
This might take some time
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<ModalHeader style={{ background: themeColor() }}>
|
||||
<span style={{ color: "white" }}>Successfully signed!</span>
|
||||
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<div></div>
|
||||
{!isAndroid && (
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
className="btn btn-primary btn-sm"
|
||||
>
|
||||
<i
|
||||
className="fa fa-print"
|
||||
style={{
|
||||
fontSize: "15px",
|
||||
marginRight: "3px",
|
||||
color: "white"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Print
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
className="btn btn-danger btn-sm"
|
||||
onClick={() => handleDownloadPdf()}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginLeft: "10px"
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Download
|
||||
</button>
|
||||
</div>
|
||||
</ModalHeader>
|
||||
|
||||
<Modal.Body>
|
||||
{isCeleb && (
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
marginLeft: "50px"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="print img"
|
||||
width={300}
|
||||
height={250}
|
||||
// style={styles.gifCeleb}
|
||||
src={celebration}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<p
|
||||
style={{
|
||||
fontFamily: "system-ui",
|
||||
verticalAlign: "baseline",
|
||||
fontWeight: "500",
|
||||
color: "#403f3e",
|
||||
fontSize: "15px"
|
||||
}}
|
||||
>
|
||||
Recipients added here will get a copy of the signed document.
|
||||
</p>
|
||||
{emailList.length > 0 ? (
|
||||
<>
|
||||
<div className="addEmail">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
|
||||
flexWrap: "wrap"
|
||||
}}
|
||||
>
|
||||
{emailList.map((data, ind) => {
|
||||
return (
|
||||
<div
|
||||
className="emailChip"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
key={ind}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "13px"
|
||||
}}
|
||||
>
|
||||
{data}
|
||||
</span>
|
||||
|
||||
<img
|
||||
alt="print img"
|
||||
onClick={() => removeChip(ind)}
|
||||
src={close}
|
||||
width={10}
|
||||
height={10}
|
||||
style={{ fontWeight: "600", marginLeft: "7px" }}
|
||||
className="emailChipClose"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{emailList.length <= 9 && (
|
||||
<input
|
||||
type="text"
|
||||
value={emailValue}
|
||||
className="addEmailInput"
|
||||
onChange={handleEmailValue}
|
||||
onKeyDown={handleEnterPress}
|
||||
required
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
value={emailValue}
|
||||
className="emailInput"
|
||||
onChange={handleEmailValue}
|
||||
onKeyDown={handleEnterPress}
|
||||
placeholder="Add the email addresses"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<span
|
||||
style={{
|
||||
cursor: emailValue && "pointer"
|
||||
}}
|
||||
onClick={() => {
|
||||
if (emailValue) {
|
||||
handleEnterPress("add");
|
||||
}
|
||||
}}
|
||||
>
|
||||
<i
|
||||
style={{
|
||||
backgroundColor: themeColor(),
|
||||
padding: "2px 10px",
|
||||
marginTop: "10px",
|
||||
color: "white"
|
||||
}}
|
||||
className="fa fa-plus"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
background: "#e3e2e1",
|
||||
marginTop: "30px",
|
||||
padding: "5px",
|
||||
borderRadius: "3px"
|
||||
}}
|
||||
>
|
||||
<span style={{ fontWeight: "700" }}>Note:</span>
|
||||
<span style={{ fontSize: "15px" }}>
|
||||
{" "}
|
||||
You can only send to ten recipients at a time.
|
||||
</span>
|
||||
</div>
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<button
|
||||
style={{
|
||||
color: "black"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
onClick={() => {
|
||||
setIsEmail(false);
|
||||
setEmailValue("");
|
||||
setEmailList([]);
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
disabled={emailList.length === 0 && true}
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
type="button"
|
||||
className={emailList.length === 0 ? "defaultBtn" : "finishBtn"}
|
||||
onClick={() => sendEmail()}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EmailComponent;
|
||||
@@ -1,21 +0,0 @@
|
||||
import React from "react";
|
||||
import "../../css/signature.css";
|
||||
|
||||
function EmailToast({ isShow }) {
|
||||
return (
|
||||
<>
|
||||
{isShow && (
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<div
|
||||
className="alert alert-success successBox"
|
||||
style={{ zIndex: "1051" }}
|
||||
>
|
||||
Email sent successfully!
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default EmailToast;
|
||||
@@ -1,429 +0,0 @@
|
||||
import React from "react";
|
||||
import * as Select from "@radix-ui/react-select";
|
||||
import classnames from "classnames";
|
||||
|
||||
function FieldsComponent({
|
||||
pdfUrl,
|
||||
sign,
|
||||
stamp,
|
||||
dragSignature,
|
||||
signRef,
|
||||
handleDivClick,
|
||||
handleMouseLeave,
|
||||
isDragSign,
|
||||
themeColor,
|
||||
dragStamp,
|
||||
dragRef,
|
||||
isDragStamp,
|
||||
dragSignatureSS,
|
||||
dragStampSS,
|
||||
isDragSignatureSS,
|
||||
isSignYourself,
|
||||
addPositionOfSignature,
|
||||
|
||||
signersdata,
|
||||
isSelectListId,
|
||||
setSignerObjId,
|
||||
setIsSelectId,
|
||||
setContractName,
|
||||
isSigners,
|
||||
dataTut,
|
||||
dataTut2,
|
||||
setIsShowEmail,
|
||||
isMailSend,
|
||||
selectedEmail,
|
||||
setSelectedEmail,
|
||||
}) {
|
||||
const signStyle = pdfUrl ? "disableSign" : "signatureBtn";
|
||||
|
||||
const isMobile = window.innerWidth <767;
|
||||
|
||||
const SelectItem = React.forwardRef(
|
||||
({ children, className, ...props }, forwardedRef) => {
|
||||
return (
|
||||
<Select.Item
|
||||
className={classnames("SelectItem", className)}
|
||||
{...props}
|
||||
ref={forwardedRef}
|
||||
>
|
||||
<Select.ItemText>{children}</Select.ItemText>
|
||||
<Select.ItemIndicator className="SelectItemIndicator"></Select.ItemIndicator>
|
||||
</Select.Item>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const color = [
|
||||
"#93a3db",
|
||||
"#e6c3db",
|
||||
"#c0e3bc",
|
||||
"#bce3db",
|
||||
"#b8ccdb",
|
||||
"#ceb8db",
|
||||
"#ffccff",
|
||||
"#99ffcc",
|
||||
"#cc99ff",
|
||||
"#ffcc99",
|
||||
"#66ccff",
|
||||
"#ffffcc",
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{isMobile && isSignYourself ? (
|
||||
!isMailSend && (
|
||||
<div
|
||||
data-tut={dataTut}
|
||||
id="navbar"
|
||||
className="stickyfooter"
|
||||
style={{ width: window.innerWidth + "px" }}
|
||||
>
|
||||
{isSigners && (
|
||||
<div
|
||||
data-tut={dataTut}
|
||||
style={{
|
||||
background: isSelectListId
|
||||
? color[isSelectListId % color.length]
|
||||
: color[0],
|
||||
padding: "10px 20px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: "18px", fontWeight: "500" }}>
|
||||
Signer :
|
||||
</span>
|
||||
|
||||
<Select.Root
|
||||
onValueChange={(obj) => {
|
||||
const [selectedKey, selectedData] = obj.split("|");
|
||||
const parseData = JSON.parse(selectedData);
|
||||
|
||||
setSignerObjId(parseData.objectId);
|
||||
setIsSelectId(selectedKey);
|
||||
setContractName(parseData.className);
|
||||
setSelectedEmail(true);
|
||||
}}
|
||||
>
|
||||
<Select.Trigger
|
||||
className={selectedEmail ? "selectEmail": "SelectTrigger"}
|
||||
style={{
|
||||
background: isSelectListId
|
||||
? color[isSelectListId % color.length]
|
||||
: color[0],
|
||||
}}
|
||||
aria-label="Food"
|
||||
>
|
||||
<Select.Value
|
||||
|
||||
placeholder="Select signer.." />
|
||||
{!selectedEmail &&
|
||||
<Select.Icon className="SelectIcon">
|
||||
<i
|
||||
style={{
|
||||
marginTop: "5px",
|
||||
marginLeft: "5px",
|
||||
color: "#3b15d1",
|
||||
fontSize: "20px",
|
||||
}}
|
||||
className="fa fa-angle-down"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</Select.Icon>}
|
||||
</Select.Trigger>
|
||||
<Select.Portal>
|
||||
<Select.Content
|
||||
className="SelectContent"
|
||||
style={{ zIndex: "5000" }}
|
||||
>
|
||||
<Select.ScrollUpButton className="SelectScrollButton">
|
||||
<i
|
||||
style={{
|
||||
marginTop: "5px",
|
||||
marginLeft: "5px",
|
||||
color: "#3b15d1",
|
||||
fontSize: "20px",
|
||||
}}
|
||||
className="fa fa-angle-down"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</Select.ScrollUpButton>
|
||||
<Select.Viewport className="SelectViewport">
|
||||
<Select.Group>
|
||||
{signersdata.Signers.map((obj, ind) => {
|
||||
return (
|
||||
<SelectItem
|
||||
selected
|
||||
key={ind}
|
||||
value={`${ind}|${JSON.stringify(obj)}`}
|
||||
// value={(obj)}
|
||||
>
|
||||
{" "}
|
||||
{obj.Email}
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
{/* <SelectItem value="orange">Orange</SelectItem>
|
||||
<SelectItem value="apple">Apple</SelectItem>
|
||||
<SelectItem value="grape"></SelectItem> */}
|
||||
</Select.Group>
|
||||
</Select.Viewport>
|
||||
<Select.ScrollDownButton className="SelectScrollButton">
|
||||
<i
|
||||
style={{
|
||||
marginTop: "5px",
|
||||
marginLeft: "5px",
|
||||
color: "#3b15d1",
|
||||
fontSize: "20px",
|
||||
}}
|
||||
className="fa fa-angle-down"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</Select.ScrollDownButton>
|
||||
</Select.Content>
|
||||
</Select.Portal>
|
||||
</Select.Root>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
data-tut={dataTut2}
|
||||
className="signLayoutContainer2"
|
||||
style={{ backgroundColor: themeColor() }}
|
||||
>
|
||||
<div
|
||||
onClick={() => {
|
||||
if (isSigners) {
|
||||
if (selectedEmail) {
|
||||
addPositionOfSignature("onclick", false);
|
||||
} else {
|
||||
setIsShowEmail(true);
|
||||
}
|
||||
} else {
|
||||
addPositionOfSignature("onclick", false);
|
||||
}
|
||||
}}
|
||||
ref={(element) => {
|
||||
dragSignatureSS(element);
|
||||
if (element) {
|
||||
signRef.current = element;
|
||||
// const height = signRef && signRef.current.offsetHeight;
|
||||
// const width = signRef && signRef.current.offsetWidth;
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
userSelect: "none",
|
||||
opacity: isDragSignatureSS ? 0.5 : 1,
|
||||
backgroundImage: `url(${sign})`,
|
||||
backgroundSize: "70% 70%",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center center",
|
||||
paddingBottom: "2.2rem",
|
||||
}}
|
||||
>
|
||||
{/* <img
|
||||
alt="sign img"
|
||||
style={{
|
||||
width: "30px",
|
||||
height: "30px",
|
||||
background: themeColor(),
|
||||
}}
|
||||
src={sign}
|
||||
/> */}
|
||||
<span
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "12px",
|
||||
position: "relative",
|
||||
top: "2.6rem",
|
||||
}}
|
||||
>
|
||||
Signature
|
||||
</span>
|
||||
</div>
|
||||
<div
|
||||
onClick={() => addPositionOfSignature("onclick", true)}
|
||||
ref={(element) => {
|
||||
dragStampSS(element);
|
||||
dragRef.current = element;
|
||||
}}
|
||||
onMouseMove={handleDivClick}
|
||||
onMouseDown={handleMouseLeave}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
userSelect: "none",
|
||||
backgroundImage: `url(${stamp})`,
|
||||
backgroundSize: "32px 33px",
|
||||
backgroundRepeat: "no-repeat",
|
||||
backgroundPosition: "center center",
|
||||
paddingBottom: "2.2rem",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "12px",
|
||||
position: "relative",
|
||||
top: "2.6rem",
|
||||
}}
|
||||
>
|
||||
Stamp
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<div data-tut={dataTut} className="signerComponent">
|
||||
<div
|
||||
style={{
|
||||
background: themeColor(),
|
||||
|
||||
padding: "5px",
|
||||
}}
|
||||
>
|
||||
<span className="signedStyle">Fields</span>
|
||||
</div>
|
||||
|
||||
<div className="signLayoutContainer1">
|
||||
{pdfUrl ? (
|
||||
<>
|
||||
<button className={signStyle} disabled={true}>
|
||||
<span
|
||||
style={{
|
||||
fontWeight: "400",
|
||||
fontSize: "15px",
|
||||
padding: "3px 20px 0px 20px",
|
||||
color: "#bfbfbf",
|
||||
}}
|
||||
>
|
||||
Signature
|
||||
</span>
|
||||
|
||||
<img
|
||||
alt="sign img"
|
||||
style={{
|
||||
width: "30px",
|
||||
height: "28px",
|
||||
background: "#d3edeb",
|
||||
}}
|
||||
src={sign}
|
||||
/>
|
||||
</button>
|
||||
<button className={signStyle} disabled={true}>
|
||||
<span
|
||||
style={{
|
||||
fontWeight: "400",
|
||||
fontSize: "15px",
|
||||
padding: "3px 0px 0px 35px",
|
||||
color: "#bfbfbf",
|
||||
}}
|
||||
>
|
||||
Stamp
|
||||
</span>
|
||||
|
||||
<img
|
||||
alt="stamp img"
|
||||
style={{
|
||||
width: "25px",
|
||||
height: "28px",
|
||||
background: "#d3edeb",
|
||||
}}
|
||||
src={stamp}
|
||||
/>
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
ref={(element) => {
|
||||
dragSignature(element);
|
||||
if (element) {
|
||||
signRef.current = element;
|
||||
// const height = signRef && signRef.current.offsetHeight;
|
||||
// const width = signRef && signRef.current.offsetWidth;
|
||||
}
|
||||
}}
|
||||
className={signStyle}
|
||||
onMouseMove={handleDivClick}
|
||||
onMouseDown={handleMouseLeave}
|
||||
style={{
|
||||
opacity: isDragSign ? 0.5 : 1,
|
||||
boxShadow:
|
||||
"0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontWeight: "400",
|
||||
fontSize: "15px",
|
||||
padding: "3px 20px 0px 20px",
|
||||
color: "black",
|
||||
}}
|
||||
>
|
||||
Signature
|
||||
</span>
|
||||
<img
|
||||
alt="sign img"
|
||||
style={{
|
||||
width: "30px",
|
||||
height: "28px",
|
||||
background: themeColor(),
|
||||
}}
|
||||
src={sign}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
ref={(element) => {
|
||||
dragStamp(element);
|
||||
dragRef.current = element;
|
||||
if (isDragStamp) {
|
||||
// setIsStamp(true);
|
||||
}
|
||||
}}
|
||||
className={!pdfUrl ? signStyle : "disableSign"}
|
||||
disabled={pdfUrl && true}
|
||||
onMouseMove={handleDivClick}
|
||||
onMouseDown={handleMouseLeave}
|
||||
style={{
|
||||
opacity: isDragStamp ? 0.5 : 1,
|
||||
boxShadow:
|
||||
"0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18)",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontWeight: "400",
|
||||
fontSize: "15px",
|
||||
padding: "3px 0px 0px 35px",
|
||||
color: !pdfUrl ? "black" : "#bfbfbf",
|
||||
}}
|
||||
>
|
||||
Stamp
|
||||
</span>
|
||||
|
||||
<img
|
||||
alt="stamp img"
|
||||
style={{
|
||||
width: "25px",
|
||||
height: "28px",
|
||||
background: themeColor(),
|
||||
}}
|
||||
src={stamp}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default FieldsComponent;
|
||||
@@ -1,771 +0,0 @@
|
||||
import React from "react";
|
||||
import PrevNext from "./prevNext";
|
||||
import { PDFDownloadLink } from "@react-pdf/renderer";
|
||||
import Certificate from "../Certificate/Certificate";
|
||||
import printModule from "print-js";
|
||||
import { getBase64FromUrl } from "../../utils/Utils";
|
||||
import { saveAs } from "file-saver";
|
||||
import "../../css/signature.css";
|
||||
import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { themeColor } from "../../utils/ThemeColor/backColor";
|
||||
|
||||
function Header({
|
||||
isPdfRequestFiles,
|
||||
isPlaceholder,
|
||||
recipient,
|
||||
setIsDecline,
|
||||
pageNumber,
|
||||
isAlreadySign,
|
||||
allPages,
|
||||
changePage,
|
||||
pdfUrl,
|
||||
documentStatus,
|
||||
embedImages,
|
||||
pdfDetails,
|
||||
signerPos,
|
||||
signersdata,
|
||||
isMailSend,
|
||||
alertSendEmail,
|
||||
isCompleted,
|
||||
isShowHeader,
|
||||
decline,
|
||||
currentSigner,
|
||||
dataTut4,
|
||||
alreadySign,
|
||||
isSignYourself,
|
||||
setIsEmail
|
||||
}) {
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const navigate = useNavigate();
|
||||
const isGuestSigner = localStorage.getItem("isGuestSigner");
|
||||
//for go to previous page
|
||||
function previousPage() {
|
||||
changePage(-1);
|
||||
}
|
||||
//for go to next page
|
||||
function nextPage() {
|
||||
changePage(1);
|
||||
}
|
||||
//function for show decline alert
|
||||
const handleDeclinePdfAlert = async () => {
|
||||
const currentDecline = {
|
||||
currnt: "Sure",
|
||||
isDeclined: true
|
||||
};
|
||||
setIsDecline(currentDecline);
|
||||
};
|
||||
|
||||
//function for print digital sign pdf
|
||||
const handleToPrint = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const pdf = await getBase64FromUrl(pdfUrl);
|
||||
const isAndroidDevice = navigator.userAgent.match(/Android/i);
|
||||
const isAppleDevice =
|
||||
(/iPad|iPhone|iPod/.test(navigator.platform) ||
|
||||
(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1)) &&
|
||||
!window.MSStream;
|
||||
if (isAndroidDevice || isAppleDevice) {
|
||||
const byteArray = Uint8Array.from(
|
||||
atob(pdf)
|
||||
.split("")
|
||||
.map((char) => char.charCodeAt(0))
|
||||
);
|
||||
const blob = new Blob([byteArray], { type: "application/pdf" });
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
window.open(blobUrl, "_blank");
|
||||
} else {
|
||||
printModule({ printable: pdf, type: "pdf", base64: true });
|
||||
}
|
||||
};
|
||||
|
||||
//handle download signed pdf
|
||||
const handleDownloadPdf = () => {
|
||||
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
|
||||
saveAs(pdfUrl, `${sanitizeFileName(pdfName)}_signed_by_OpenSign™.pdf`);
|
||||
};
|
||||
|
||||
const sanitizeFileName = (pdfName) => {
|
||||
// Replace spaces with underscore
|
||||
return pdfName.replace(/ /g, "_");
|
||||
};
|
||||
//certificate generate and download component in mobile view
|
||||
const CertificateDropDown = () => {
|
||||
//after generate download certifcate pdf
|
||||
const handleDownload = (pdfBlob, fileName) => {
|
||||
if (pdfBlob) {
|
||||
const url = window.URL.createObjectURL(pdfBlob);
|
||||
// Create a temporary anchor element
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = fileName;
|
||||
// Append the anchor to the body
|
||||
document.body.appendChild(link);
|
||||
// Programmatically click the anchor to trigger the download
|
||||
link.click();
|
||||
// Remove the anchor from the body
|
||||
document.body.removeChild(link);
|
||||
// Release the object URL to free up resources
|
||||
window.URL.revokeObjectURL(url);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<PDFDownloadLink
|
||||
onClick={(e) => e.preventDefault()}
|
||||
style={{ textDecoration: "none", zIndex: "35" }}
|
||||
document={<Certificate pdfData={pdfDetails} />}
|
||||
>
|
||||
{({ blob, url, loading, error }) => (
|
||||
<>
|
||||
{loading ? (
|
||||
<div
|
||||
style={{
|
||||
border: "none",
|
||||
backgroundColor: "#fff"
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className="fa fa-certificate"
|
||||
style={{
|
||||
marginRight: "2px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Certificate
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
border: "none",
|
||||
backgroundColor: "#fff"
|
||||
}}
|
||||
onClick={() =>
|
||||
handleDownload(
|
||||
blob,
|
||||
`completion certificate-${
|
||||
pdfDetails[0] && pdfDetails[0].Name
|
||||
}.pdf`
|
||||
)
|
||||
}
|
||||
>
|
||||
<i
|
||||
className="fa fa-certificate"
|
||||
style={{
|
||||
marginRight: "2px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Certificate
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</PDFDownloadLink>
|
||||
);
|
||||
};
|
||||
const CertificateComponent = () => {
|
||||
return (
|
||||
<PDFDownloadLink
|
||||
style={{ textDecoration: "none" }}
|
||||
document={<Certificate pdfData={pdfDetails} />}
|
||||
fileName={`completion certificate-${
|
||||
pdfDetails[0] && pdfDetails[0].Name
|
||||
}.pdf`}
|
||||
>
|
||||
{({ blob, url, loading, error }) =>
|
||||
loading ? (
|
||||
<button
|
||||
type="button"
|
||||
className="defaultBtn certificateBtn"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className="fa fa-certificate"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Certificate
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="defaultBtn certificateBtn"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className="fa fa-certificate"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Certificate
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</PDFDownloadLink>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<div
|
||||
style={{ padding: !isGuestSigner && "5px 0px 5px 0px" }}
|
||||
className="mobileHead"
|
||||
>
|
||||
{isMobile && isShowHeader ? (
|
||||
<div
|
||||
id="navbar"
|
||||
className={isGuestSigner ? "stickySignerHead" : "stickyHead"}
|
||||
style={{
|
||||
width: isGuestSigner
|
||||
? window.innerWidth
|
||||
: window.innerWidth - 30 + "px"
|
||||
}}
|
||||
>
|
||||
<div className="preBtn2">
|
||||
<div
|
||||
onClick={() => {
|
||||
navigate(-1);
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className="fa fa-arrow-left"
|
||||
aria-hidden="true"
|
||||
style={{ color: themeColor(), cursor: "pointer" }}
|
||||
></i>
|
||||
</div>
|
||||
<div>
|
||||
<i
|
||||
onClick={() => {
|
||||
if (pageNumber > 1) {
|
||||
previousPage();
|
||||
}
|
||||
}}
|
||||
className="fa fa-backward"
|
||||
style={{ color: "gray", cursor: "pointer" }}
|
||||
></i>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
fontWeight: "600",
|
||||
marginLeft: "10px",
|
||||
marginRight: "10px"
|
||||
}}
|
||||
>
|
||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
||||
</span>
|
||||
<i
|
||||
onClick={() => {
|
||||
if (pageNumber < allPages) {
|
||||
nextPage();
|
||||
}
|
||||
}}
|
||||
className="fa fa-forward"
|
||||
style={{ color: "gray", cursor: "pointer" }}
|
||||
></i>
|
||||
</div>
|
||||
{pdfUrl && alreadySign ? (
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<div
|
||||
style={{
|
||||
color: themeColor(),
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px",
|
||||
padding: "0px 3px 0px 5px"
|
||||
}}
|
||||
>
|
||||
<i className="fa fa-ellipsis-v" aria-hidden="true"></i>
|
||||
</div>
|
||||
</DropdownMenu.Trigger>
|
||||
|
||||
<DropdownMenu.Portal>
|
||||
<DropdownMenu.Content
|
||||
className="DropdownMenuContent"
|
||||
sideOffset={5}
|
||||
>
|
||||
<DropdownMenu.Item
|
||||
className="DropdownMenuItem"
|
||||
onClick={() => handleDownloadPdf()}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className="fa fa-arrow-down"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "2px" }}
|
||||
></i>
|
||||
Download
|
||||
</div>
|
||||
</DropdownMenu.Item>
|
||||
{recipient && pdfDetails[0] && pdfDetails.length > 0 ? (
|
||||
<DropdownMenu.Item className="DropdownMenuItem">
|
||||
<CertificateDropDown />
|
||||
</DropdownMenu.Item>
|
||||
) : isPdfRequestFiles &&
|
||||
alreadySign &&
|
||||
isCompleted.isCertificate ? (
|
||||
<DropdownMenu.Item className="DropdownMenuItem">
|
||||
<CertificateDropDown />
|
||||
</DropdownMenu.Item>
|
||||
) : (
|
||||
isSignYourself && (
|
||||
<>
|
||||
<DropdownMenu.Item className="DropdownMenuItem">
|
||||
<CertificateDropDown />
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item
|
||||
className="DropdownMenuItem"
|
||||
onClick={() => setIsEmail(true)}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
<i
|
||||
class="fa fa-envelope"
|
||||
style={{ marginRight: "2px" }}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Mail
|
||||
</div>
|
||||
</DropdownMenu.Item>
|
||||
</>
|
||||
)
|
||||
)}
|
||||
<DropdownMenu.Item
|
||||
className="DropdownMenuItem"
|
||||
onClick={handleToPrint}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row"
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
<i
|
||||
className="fa fa-print"
|
||||
aria-hidden="true"
|
||||
style={{ marginRight: "2px" }}
|
||||
></i>
|
||||
Print
|
||||
</div>
|
||||
</DropdownMenu.Item>
|
||||
</DropdownMenu.Content>
|
||||
</DropdownMenu.Portal>
|
||||
</DropdownMenu.Root>
|
||||
) : (
|
||||
<div style={{ display: "flex", justifyContent: "space-around" }}>
|
||||
{/* current signer is checking user send request and check status of pdf sign than if current
|
||||
user exist than show finish button else no
|
||||
*/}
|
||||
{currentSigner && (
|
||||
<>
|
||||
{decline && (
|
||||
<div
|
||||
onClick={() => {
|
||||
handleDeclinePdfAlert();
|
||||
}}
|
||||
style={{
|
||||
color: "red",
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px",
|
||||
marginRight: "10px"
|
||||
}}
|
||||
>
|
||||
Decline
|
||||
</div>
|
||||
)}
|
||||
{isPlaceholder ? (
|
||||
<div
|
||||
onClick={() => {
|
||||
if (!isMailSend) {
|
||||
alertSendEmail();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
color: isMailSend ? "gray" : themeColor(),
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px"
|
||||
}}
|
||||
data-tut={dataTut4}
|
||||
>
|
||||
Send
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
data-tut="reactourThird"
|
||||
onClick={() => {
|
||||
if (!pdfUrl) {
|
||||
embedImages();
|
||||
} else if (isPdfRequestFiles) {
|
||||
embedImages();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
color: themeColor(),
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px"
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="signatureHeader headerBtn">
|
||||
<PrevNext
|
||||
pageNumber={pageNumber}
|
||||
allPages={allPages}
|
||||
changePage={changePage}
|
||||
/>
|
||||
|
||||
{recipient ? (
|
||||
pdfUrl || isAlreadySign.mssg ? (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
{pdfDetails[0] && pdfDetails.length > 0 && (
|
||||
<CertificateComponent />
|
||||
)}
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
className="defaultBtn printBtn"
|
||||
>
|
||||
<i
|
||||
className="fa fa-print"
|
||||
style={{
|
||||
fontSize: "15px",
|
||||
marginRight: "3px",
|
||||
color: "white"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Print
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
className="defaultBtn downloadBtn"
|
||||
onClick={() => handleDownloadPdf()}
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Download
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<button
|
||||
style={{
|
||||
background: "#de4337"
|
||||
}}
|
||||
className="finishBtn hoverCss"
|
||||
onClick={() => {
|
||||
handleDeclinePdfAlert();
|
||||
}}
|
||||
>
|
||||
Decline
|
||||
</button>
|
||||
|
||||
<button
|
||||
data-tut="reactourThird"
|
||||
style={{
|
||||
background: !pdfUrl ? "#188ae2" : "#d3edeb"
|
||||
}}
|
||||
className="finishBtn sendHover"
|
||||
onClick={() => {
|
||||
if (!pdfUrl) {
|
||||
embedImages();
|
||||
}
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
) : isPlaceholder ? (
|
||||
<>
|
||||
{!isMailSend &&
|
||||
signersdata.Signers &&
|
||||
signersdata.Signers.length !== signerPos.length && (
|
||||
<div>
|
||||
{signerPos.length === 0 ? (
|
||||
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
||||
Add all {signersdata.Signers.length - signerPos.length}{" "}
|
||||
recipients signature
|
||||
</span>
|
||||
) : (
|
||||
<span style={{ fontSize: "13px", color: "#f5405e" }}>
|
||||
Add {signersdata.Signers.length - signerPos.length} more
|
||||
recipients signature
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
navigate(-1);
|
||||
}}
|
||||
type="button"
|
||||
className="defaultBtn backBtn"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
|
||||
<button
|
||||
disabled={isMailSend && true}
|
||||
data-tut="reactourFour"
|
||||
style={{
|
||||
background: isMailSend ? "rgb(203, 203, 203)" : "#188ae2",
|
||||
color: isMailSend && "rgb(77, 75, 75)"
|
||||
}}
|
||||
onClick={() => {
|
||||
alertSendEmail();
|
||||
}}
|
||||
className={isMailSend ? "sendMail" : "sendMail sendHover"}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : isPdfRequestFiles ? (
|
||||
alreadySign ? (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
{isCompleted.isCertificate && <CertificateComponent />}
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
type="button"
|
||||
className="defaultBtn printBtn"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<i
|
||||
className="fa fa-print"
|
||||
style={{
|
||||
fontSize: "15px",
|
||||
marginRight: "3px",
|
||||
color: "white"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Print
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
className="defaultBtn downloadBtn"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
onClick={() => handleDownloadPdf()}
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Download
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
navigate(-1);
|
||||
}}
|
||||
type="button"
|
||||
className="defaultBtn backBtn"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
{currentSigner && (
|
||||
<>
|
||||
<button
|
||||
style={{
|
||||
background: "#de4337"
|
||||
}}
|
||||
className="finishBtn hoverCss"
|
||||
onClick={() => {
|
||||
handleDeclinePdfAlert();
|
||||
}}
|
||||
>
|
||||
Decline
|
||||
</button>
|
||||
<button
|
||||
style={{
|
||||
background: "#188ae2"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn sendHover"
|
||||
onClick={() => {
|
||||
embedImages();
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
) : pdfUrl || (documentStatus && documentStatus.isCompleted) ? (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<CertificateComponent />
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
type="button"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center"
|
||||
}}
|
||||
className="defaultBtn printBtn"
|
||||
>
|
||||
<i
|
||||
className="fa fa-print"
|
||||
style={{
|
||||
fontSize: "15px",
|
||||
marginRight: "3px",
|
||||
color: "white"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Print
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="defaultBtn downloadBtn"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginLeft: "10px"
|
||||
}}
|
||||
onClick={() => handleDownloadPdf()}
|
||||
>
|
||||
<i
|
||||
className="fa fa-download"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Download
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="defaultBtn mailBtn"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
marginLeft: "10px"
|
||||
}}
|
||||
onClick={() => setIsEmail(true)}
|
||||
>
|
||||
<i
|
||||
class="fa fa-envelope"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px"
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Mail
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<button
|
||||
onClick={() => {
|
||||
navigate(-1);
|
||||
}}
|
||||
type="button"
|
||||
className="defaultBtn backBtn"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
|
||||
<button
|
||||
style={{
|
||||
background: "#188ae2"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn sendHover"
|
||||
onClick={() => {
|
||||
if (!pdfUrl) {
|
||||
embedImages();
|
||||
}
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Header;
|
||||
@@ -1,28 +0,0 @@
|
||||
import React from 'react'
|
||||
import loader from "../../assests/loader2.gif";
|
||||
|
||||
|
||||
function Loader({isLoading}) {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
src={loader}
|
||||
style={{ width: "80px", height: "80px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "13px", color: "gray" }}>
|
||||
{isLoading.message}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Loader
|
||||
@@ -1,63 +0,0 @@
|
||||
import React from "react";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import ModalHeader from "react-bootstrap/esm/ModalHeader";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
function ModalComponent({ isShow, type, setIsShowEmail }) {
|
||||
const navigate = useNavigate();
|
||||
return (
|
||||
<Modal show={isShow}>
|
||||
<ModalHeader className="bg-danger" style={{ color: "white" }}>
|
||||
{type === "signersAlert" ? (
|
||||
<span>Select signers</span>
|
||||
) : type === "alreadyPlace" ? (
|
||||
<span>Already Placed!</span>
|
||||
) : (
|
||||
<span>Document Expired!</span>
|
||||
)}
|
||||
</ModalHeader>
|
||||
|
||||
<Modal.Body>
|
||||
{type === "signersAlert" ? (
|
||||
<p>Please select signer for add placeholder!</p>
|
||||
) : type === "alreadyPlace" ? (
|
||||
<p>Already set placeHolder for this document.</p>
|
||||
) : (
|
||||
<p>This Document is no longer available.</p>
|
||||
)}
|
||||
</Modal.Body>
|
||||
<Modal.Footer>
|
||||
{type === "signersAlert" ? (
|
||||
<button
|
||||
onClick={() => {
|
||||
setIsShowEmail(false);
|
||||
}}
|
||||
style={{
|
||||
color: "black"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
>
|
||||
Ok
|
||||
</button>
|
||||
) : (
|
||||
type === "alreadyPlace" && (
|
||||
<button
|
||||
onClick={() => {
|
||||
navigate(-1);
|
||||
}}
|
||||
style={{
|
||||
color: "black"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
>
|
||||
Ok
|
||||
</button>
|
||||
)
|
||||
)}
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ModalComponent;
|
||||
@@ -1,58 +0,0 @@
|
||||
import React from "react";
|
||||
|
||||
function PrevNext({ pageNumber, allPages, changePage }) {
|
||||
//for go to previous page
|
||||
function previousPage() {
|
||||
changePage(-1);
|
||||
}
|
||||
//for go to next page
|
||||
function nextPage() {
|
||||
changePage(1);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="preBtn1">
|
||||
<button
|
||||
style={{
|
||||
padding: "3px 20px ",
|
||||
fontSize: "10px",
|
||||
background: "#d3edeb",
|
||||
fontWeight: "600",
|
||||
|
||||
border: "0px",
|
||||
marginRight: "5px",
|
||||
}}
|
||||
disabled={pageNumber <= 1}
|
||||
onClick={previousPage}
|
||||
>
|
||||
Prev
|
||||
</button>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "13px",
|
||||
fontWeight: "600",
|
||||
}}
|
||||
>
|
||||
{pageNumber || (allPages ? 1 : "--")} of {allPages || "--"}
|
||||
</span>
|
||||
<button
|
||||
style={{
|
||||
padding: "3px 20px ",
|
||||
fontSize: "10px",
|
||||
background: "#d3edeb",
|
||||
fontWeight: "600",
|
||||
marginLeft: "5px",
|
||||
border: "0px",
|
||||
}}
|
||||
disabled={pageNumber >= allPages}
|
||||
onClick={nextPage}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default PrevNext;
|
||||
@@ -1,96 +0,0 @@
|
||||
import React from "react";
|
||||
import RSC from "react-scrollbars-custom";
|
||||
import { Document, Page, pdfjs } from "react-pdf";
|
||||
import { themeColor } from "../../utils/ThemeColor/backColor";
|
||||
|
||||
function RenderAllPdfPage({
|
||||
pdfUrl,
|
||||
signPdfUrl,
|
||||
allPages,
|
||||
setAllPages,
|
||||
setPageNumber,
|
||||
setSignBtnPosition,
|
||||
}) {
|
||||
pdfjs.GlobalWorkerOptions.workerSrc = `//cdnjs.cloudflare.com/ajax/libs/pdf.js/${pdfjs.version}/pdf.worker.js`;
|
||||
|
||||
//set all number of pages after load pdf
|
||||
function onDocumentLoad({ numPages }) {
|
||||
setAllPages(numPages);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="showPages">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
boxShadow: "rgba(17, 12, 46, 0.15) 0px 48px 100px 0px",
|
||||
backgroundColor: "white",
|
||||
height:"100%"
|
||||
|
||||
}}
|
||||
>
|
||||
<div style={{ width: "140px" }}>
|
||||
<div
|
||||
style={{
|
||||
background: themeColor(),
|
||||
// color:"white"
|
||||
}}
|
||||
className="signedStyle"
|
||||
>
|
||||
Pages
|
||||
</div>
|
||||
|
||||
|
||||
<div>
|
||||
<RSC id="RSC-Example" style={{width:"135px",height:window.innerHeight-130+'px'}} >
|
||||
<Document
|
||||
onLoadSuccess={onDocumentLoad}
|
||||
file={pdfUrl ? pdfUrl : signPdfUrl}
|
||||
// file="https://api.printnode.com/static/test/pdf/multipage.pdf"
|
||||
>
|
||||
{Array.from(new Array(allPages), (el, index) => (
|
||||
<div
|
||||
key={index}
|
||||
style={{
|
||||
width: "100px",
|
||||
border: "2px solid #878787",
|
||||
// padding: "5px",
|
||||
margin: "10px",
|
||||
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
contain: "content",
|
||||
}}
|
||||
onClick={() => {
|
||||
setPageNumber(index + 1);
|
||||
if (setSignBtnPosition) {
|
||||
setSignBtnPosition([]);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Page
|
||||
key={`page_${index + 1}`}
|
||||
pageNumber={index + 1}
|
||||
width={100}
|
||||
height={100}
|
||||
scale={1}
|
||||
renderAnnotationLayer={false}
|
||||
renderTextLayer={false}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</Document>
|
||||
</RSC>
|
||||
</div>
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default RenderAllPdfPage;
|
||||
@@ -1,397 +0,0 @@
|
||||
import React from "react";
|
||||
import { useRef, useState } from "react";
|
||||
import SignatureCanvas from "react-signature-canvas";
|
||||
import redPen from "../../assests/redPen.png";
|
||||
import bluePen from "../../assests/bluePen.png";
|
||||
import blackPen from "../../assests/blackPen.png";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import { themeColor } from "../../utils/ThemeColor/backColor";
|
||||
import { useEffect } from "react";
|
||||
|
||||
function SignPad({
|
||||
isSignPad,
|
||||
isStamp,
|
||||
setIsImageSelect,
|
||||
onSaveSign,
|
||||
setIsSignPad,
|
||||
setImage,
|
||||
isImageSelect,
|
||||
imageRef,
|
||||
onImageChange,
|
||||
onSaveImage,
|
||||
image,
|
||||
defaultSign,
|
||||
setSignature
|
||||
}) {
|
||||
const [penColor, setPenColor] = useState("blue");
|
||||
const allColor = [bluePen, redPen, blackPen];
|
||||
const canvasRef = useRef(null);
|
||||
const [isDefaultSign, setIsDefaultSign] = useState(false);
|
||||
const [isTab, setIsTab] = useState("signature");
|
||||
const [isSignImg, setIsSignImg] = useState("");
|
||||
//function for clear signature
|
||||
const handleClear = () => {
|
||||
if (canvasRef.current) {
|
||||
canvasRef.current.clear();
|
||||
}
|
||||
|
||||
setIsSignImg("");
|
||||
};
|
||||
//function for set signature url
|
||||
const handleSignatureChange = (dataURL) => {
|
||||
// canvasRef.current.backgroundColor = 'rgb(165, 26, 26)'
|
||||
setSignature(canvasRef.current.toDataURL());
|
||||
setIsSignImg(canvasRef.current.toDataURL());
|
||||
};
|
||||
|
||||
//save button component
|
||||
const SaveBtn = () => {
|
||||
return (
|
||||
<div>
|
||||
{!isStamp && !isImageSelect && (
|
||||
<button
|
||||
style={{
|
||||
color: "black"
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn saveBtn"
|
||||
onClick={() => handleClear()}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
if (!image) {
|
||||
if (isDefaultSign) {
|
||||
setIsSignImg("");
|
||||
onSaveSign(isDefaultSign);
|
||||
} else {
|
||||
setIsSignImg("");
|
||||
onSaveSign();
|
||||
}
|
||||
|
||||
setPenColor("blue");
|
||||
} else {
|
||||
setIsSignImg("");
|
||||
onSaveImage();
|
||||
}
|
||||
setIsSignPad(false);
|
||||
|
||||
setIsImageSelect(false);
|
||||
setIsDefaultSign(false);
|
||||
setImage();
|
||||
setIsTab("signature");
|
||||
}}
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
disabled={isSignImg || image || isDefaultSign ? false : true}
|
||||
type="button"
|
||||
className={
|
||||
isSignImg || image ? "finishBtn saveBtn" : "disabledFinish saveBtn"
|
||||
}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// Load the default signature after the component mounts
|
||||
if (canvasRef.current) {
|
||||
canvasRef.current.fromDataURL(isSignImg);
|
||||
}
|
||||
}, [isTab]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/*isSignPad */}
|
||||
<Modal show={isSignPad}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
background: "white",
|
||||
borderBottom: "1.6px solid #ebe6e6",
|
||||
marginTop: "15px"
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-around",
|
||||
alignItems: "end",
|
||||
gap: 10
|
||||
|
||||
// background: themeColor(),
|
||||
}}
|
||||
>
|
||||
{isStamp ? (
|
||||
<span style={{ color: themeColor() }} className="signTab">
|
||||
Upload Image
|
||||
</span>
|
||||
) : (
|
||||
<>
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(false);
|
||||
setIsImageSelect(false);
|
||||
setIsTab("signature");
|
||||
setImage();
|
||||
}}
|
||||
style={{
|
||||
color: isTab === "signature" ? themeColor() : "#515252",
|
||||
marginLeft: "2px"
|
||||
}}
|
||||
className="signTab"
|
||||
>
|
||||
Signature
|
||||
</span>
|
||||
|
||||
<div
|
||||
style={{
|
||||
border:
|
||||
isTab === "signature"
|
||||
? "1.5px solid #108783"
|
||||
: "1.5px solid #ffffff"
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(false);
|
||||
setIsImageSelect(true);
|
||||
setIsTab("uploadImage");
|
||||
}}
|
||||
style={{
|
||||
color: isTab === "uploadImage" ? themeColor() : "#515252"
|
||||
}}
|
||||
className="signTab"
|
||||
>
|
||||
Upload Image
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
border:
|
||||
isTab === "uploadImage"
|
||||
? "1.5px solid #108783"
|
||||
: "1.5px solid #ffffff"
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
|
||||
{defaultSign && (
|
||||
<div>
|
||||
<span
|
||||
onClick={() => {
|
||||
setIsDefaultSign(true);
|
||||
setIsImageSelect(true);
|
||||
setIsTab("mysignature");
|
||||
setImage();
|
||||
}}
|
||||
style={{
|
||||
color:
|
||||
isTab === "mysignature" ? themeColor() : "#515252"
|
||||
}}
|
||||
className="signTab"
|
||||
>
|
||||
My Signature
|
||||
</span>
|
||||
<div
|
||||
style={{
|
||||
border:
|
||||
isTab === "mysignature"
|
||||
? "1.5px solid #108783"
|
||||
: "1.5px solid #ffffff"
|
||||
}}
|
||||
></div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<button
|
||||
style={{
|
||||
border: "0px",
|
||||
background: "none",
|
||||
paddingLeft: "7px",
|
||||
paddingRight: "7px",
|
||||
marginRight: "5px"
|
||||
}}
|
||||
onClick={() => {
|
||||
setPenColor("blue");
|
||||
setIsSignPad(false);
|
||||
|
||||
setIsImageSelect(false);
|
||||
setIsDefaultSign(false);
|
||||
setImage();
|
||||
setIsTab("signature");
|
||||
}}
|
||||
>
|
||||
X
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* signature modal */}
|
||||
<Modal.Body className="modalBody">
|
||||
{isDefaultSign ? (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
border: "1px solid black",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className="signatureCanvas"
|
||||
>
|
||||
<img
|
||||
alt="stamp img"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
src={defaultSign}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
) : isImageSelect || isStamp ? (
|
||||
!image ? (
|
||||
<div
|
||||
style={{
|
||||
border: "1px solid black",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className="signatureCanvas"
|
||||
onClick={() => imageRef.current.click()}
|
||||
>
|
||||
<input
|
||||
type="file"
|
||||
onChange={onImageChange}
|
||||
className="filetype"
|
||||
accept="image/*"
|
||||
ref={imageRef}
|
||||
hidden
|
||||
/>
|
||||
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
|
||||
<div className="uploadImg">Upload</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
border: "1px solid black",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: 6,
|
||||
cursor: "pointer"
|
||||
}}
|
||||
className="signatureCanvas"
|
||||
>
|
||||
<img
|
||||
alt="stamp img"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain"
|
||||
}}
|
||||
ref={imageRef}
|
||||
src={image.src}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
<SignatureCanvas
|
||||
ref={canvasRef}
|
||||
penColor={penColor}
|
||||
canvasProps={{
|
||||
className: "signatureCanvas"
|
||||
}}
|
||||
backgroundColor="rgb(255, 255, 255)"
|
||||
onEnd={() =>
|
||||
handleSignatureChange(canvasRef.current.toDataURL())
|
||||
}
|
||||
dotSize={1}
|
||||
/>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginTop: "4px"
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
{allColor.map((data, key) => {
|
||||
return (
|
||||
<img
|
||||
key={key}
|
||||
alt="pen img"
|
||||
style={{
|
||||
border: "none",
|
||||
margin: "5px",
|
||||
borderBottom:
|
||||
key === 0 && penColor === "blue"
|
||||
? "2px solid blue"
|
||||
: key === 1 && penColor === "red"
|
||||
? "2px solid red"
|
||||
: key === 2 && penColor === "black"
|
||||
? "2px solid black"
|
||||
: "2px solid white"
|
||||
}}
|
||||
onClick={() => {
|
||||
if (key === 0) {
|
||||
setPenColor("blue");
|
||||
} else if (key === 1) {
|
||||
setPenColor("red");
|
||||
} else if (key === 2) {
|
||||
setPenColor("black");
|
||||
}
|
||||
}}
|
||||
src={data}
|
||||
width={20}
|
||||
height={20}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignPad;
|
||||
@@ -1,68 +0,0 @@
|
||||
import React from "react";
|
||||
import { themeColor } from "../../utils/ThemeColor/backColor";
|
||||
import "../../css/signature.css";
|
||||
function Signedby({ pdfDetails }) {
|
||||
const getFirstLetter = (name) => {
|
||||
const firstLetter = name.charAt(0);
|
||||
return firstLetter;
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
<div className="signerComponent">
|
||||
<div
|
||||
style={{
|
||||
background: themeColor(),
|
||||
// color:"white"
|
||||
}}
|
||||
className="signedStyle"
|
||||
>
|
||||
Signed By
|
||||
</div>
|
||||
<div style={{ marginTop: "2px" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
padding: "10px",
|
||||
|
||||
background: "#93a3db",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="signerStyle"
|
||||
style={{
|
||||
background: "#abd1d0",
|
||||
width: 20,
|
||||
height: 20,
|
||||
display: "flex",
|
||||
borderRadius: 30 / 2,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginRight: "20px",
|
||||
marginTop: "5px",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "8px",
|
||||
textAlign: "center",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{getFirstLetter(pdfDetails.ExtUserPtr.Name)}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<span className="userName">{pdfDetails.ExtUserPtr.Name}</span>
|
||||
<span className="useEmail">{pdfDetails.ExtUserPtr.Email}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
);
|
||||
}
|
||||
|
||||
export default Signedby;
|
||||
@@ -1,163 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import check from "../../assests/checkBox.png";
|
||||
import { themeColor } from "../../utils/ThemeColor/backColor";
|
||||
|
||||
function SignerListPlace({
|
||||
signerPos,
|
||||
signersdata,
|
||||
isSelectListId,
|
||||
setSignerObjId,
|
||||
setIsSelectId,
|
||||
setContractName
|
||||
}) {
|
||||
const color = [
|
||||
"#93a3db",
|
||||
"#e6c3db",
|
||||
"#c0e3bc",
|
||||
"#bce3db",
|
||||
"#b8ccdb",
|
||||
"#ceb8db",
|
||||
"#ffccff",
|
||||
"#99ffcc",
|
||||
"#cc99ff",
|
||||
"#ffcc99",
|
||||
"#66ccff",
|
||||
"#ffffcc",
|
||||
];
|
||||
|
||||
const nameColor = [
|
||||
"#304fbf",
|
||||
"#7d5270",
|
||||
"#5f825b",
|
||||
"#578077",
|
||||
"#576e80",
|
||||
"#6d527d",
|
||||
"#cc00cc",
|
||||
"#006666",
|
||||
"#cc00ff",
|
||||
"#ff9900",
|
||||
"#336699",
|
||||
"#cc9900",
|
||||
];
|
||||
const [isHover, setIsHover] = useState();
|
||||
|
||||
//function for onhover signer name change background color
|
||||
const onHoverStyle = (ind) => {
|
||||
const style = {
|
||||
background: color[ind % color.length],
|
||||
padding: "10px",
|
||||
marginTop: "2px",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
borderBottom: "1px solid #e3e1e1",
|
||||
};
|
||||
return style;
|
||||
};
|
||||
//function for onhover signer name remove background color
|
||||
const nonHoverStyle = (ind) => {
|
||||
const style = {
|
||||
// width:"250px",
|
||||
padding: "10px",
|
||||
marginTop: "2px",
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
|
||||
justifyContent: "space-between",
|
||||
};
|
||||
return style;
|
||||
};
|
||||
|
||||
const getFirstLetter = (name) => {
|
||||
const firstLetter = name.charAt(0);
|
||||
return firstLetter;
|
||||
};
|
||||
|
||||
return (
|
||||
<div >
|
||||
<div
|
||||
style={{
|
||||
background: themeColor(),
|
||||
|
||||
padding: "5px",
|
||||
}}
|
||||
>
|
||||
<span className="signedStyle">Reicipents</span>
|
||||
</div>
|
||||
|
||||
<div className="signerList">
|
||||
{signersdata.Signers &&
|
||||
signersdata.Signers.map((obj, ind) => {
|
||||
return (
|
||||
<div
|
||||
data-tut="reactourFirst"
|
||||
onMouseEnter={() => setIsHover(ind)}
|
||||
onMouseLeave={() => setIsHover(null)}
|
||||
key={ind}
|
||||
style={
|
||||
isHover === ind || isSelectListId === ind
|
||||
? onHoverStyle(ind)
|
||||
: nonHoverStyle(ind)
|
||||
}
|
||||
onClick={() => {
|
||||
setSignerObjId(obj.objectId);
|
||||
setIsSelectId(ind);
|
||||
setContractName(obj.className)
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
className="signerStyle"
|
||||
style={{
|
||||
background: nameColor[ind % nameColor.length],
|
||||
width: 20,
|
||||
height: 20,
|
||||
display: "flex",
|
||||
borderRadius: 30 / 2,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
marginRight: "20px",
|
||||
marginTop: "5px",
|
||||
}}
|
||||
>
|
||||
<span
|
||||
style={{
|
||||
fontSize: "8px",
|
||||
textAlign: "center",
|
||||
fontWeight: "bold",
|
||||
}}
|
||||
>
|
||||
{" "}
|
||||
{getFirstLetter(obj.Name)}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<span className="userName">{obj.Name}</span>
|
||||
<span className="useEmail">{obj.Email}</span>
|
||||
</div>
|
||||
</div>
|
||||
{signerPos.map((data, key) => {
|
||||
return (
|
||||
data.signerObjId === obj.objectId && (
|
||||
<div key={key}>
|
||||
<img alt="no img" src={check} width={20} height={20} />
|
||||
</div>
|
||||
)
|
||||
);
|
||||
})}
|
||||
|
||||
<hr />
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignerListPlace;
|
||||
@@ -1,277 +0,0 @@
|
||||
import React, { useState } from "react";
|
||||
import "../css/LoginPage.css";
|
||||
import loader from "../assests/loader2.gif";
|
||||
import axios from "axios";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { themeColor } from "../utils/ThemeColor/backColor";
|
||||
import { useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
function Login() {
|
||||
const { id, userMail, contactBookId, serverUrl } = useParams();
|
||||
let navigate = useNavigate();
|
||||
const [email, setEmail] = useState(userMail);
|
||||
const [OTP, setOTP] = useState("");
|
||||
const [EnterOTP, setEnterOtp] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
handleServerUrl();
|
||||
}, []);
|
||||
|
||||
//function generate serverUrl and parseAppId from url and save it in local storage
|
||||
const handleServerUrl = () => {
|
||||
//split url in array from '&'
|
||||
localStorage.clear();
|
||||
const checkSplit = serverUrl.split("&");
|
||||
const server = checkSplit[0];
|
||||
const parseId = checkSplit[1];
|
||||
const appName = checkSplit[2];
|
||||
|
||||
const newServer = server.replaceAll("%2F", "/");
|
||||
localStorage.setItem("baseUrl", newServer);
|
||||
localStorage.setItem("parseAppId", parseId);
|
||||
localStorage.setItem("_appName", appName);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
const handleChange = (event) => {
|
||||
const { value } = event.target;
|
||||
setOTP(value);
|
||||
};
|
||||
|
||||
//send email OTP function
|
||||
const SendOtp = async (e) => {
|
||||
const serverUrl =
|
||||
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
|
||||
const parseId =
|
||||
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
|
||||
if (serverUrl && localStorage) {
|
||||
setLoading(true);
|
||||
e.preventDefault();
|
||||
setEmail(email);
|
||||
|
||||
try {
|
||||
let url = `${serverUrl}functions/SendOTPMailV1/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId
|
||||
};
|
||||
let body = {
|
||||
email: email.toString()
|
||||
};
|
||||
let Otp = await axios.post(url, body, { headers: headers });
|
||||
|
||||
if (Otp) {
|
||||
setLoading(false);
|
||||
setEnterOtp(true);
|
||||
}
|
||||
} catch (error) {
|
||||
alert("something went wrong!");
|
||||
}
|
||||
} else {
|
||||
alert("something went wrong!");
|
||||
}
|
||||
};
|
||||
|
||||
//verify OTP send on via email
|
||||
const VerifyOTP = async (e) => {
|
||||
e.preventDefault();
|
||||
const serverUrl =
|
||||
localStorage.getItem("baseUrl") && localStorage.getItem("baseUrl");
|
||||
const parseId =
|
||||
localStorage.getItem("parseAppId") && localStorage.getItem("parseAppId");
|
||||
if (OTP) {
|
||||
setLoading(true);
|
||||
try {
|
||||
let url = `${serverUrl}functions/AuthLoginAsMail/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId
|
||||
};
|
||||
let body = {
|
||||
email: email,
|
||||
otp: OTP
|
||||
};
|
||||
let user = await axios.post(url, body, { headers: headers });
|
||||
if (user.data.result === "Invalid Otp") {
|
||||
alert("Invalid Otp");
|
||||
setLoading(false);
|
||||
} else if (user.data.result === "user not found!") {
|
||||
alert("User not found!");
|
||||
setLoading(false);
|
||||
} else {
|
||||
let _user = user.data.result;
|
||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||
localStorage.setItem("username", _user.name);
|
||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||
//save isGuestSigner true in local to handle login flow header in mobile view
|
||||
localStorage.setItem("isGuestSigner", true);
|
||||
setLoading(false);
|
||||
navigate(
|
||||
`/loadmf/signmicroapp/recipientSignPdf/${id}/${contactBookId}`
|
||||
);
|
||||
}
|
||||
} catch (error) {}
|
||||
} else {
|
||||
alert("Please Enter OTP!");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div style={{ padding: "2rem" }}>
|
||||
{isLoading ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
height: "100vh",
|
||||
flexDirection: "column"
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt="no img"
|
||||
src={loader}
|
||||
style={{ width: "80px", height: "80px" }}
|
||||
/>
|
||||
<span style={{ fontSize: "13px", color: "gray" }}>
|
||||
{isLoading.message}
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
margin: "10px",
|
||||
border: "0.5px solid #c5c7c9",
|
||||
padding: "30px",
|
||||
boxShadow: "rgba(99, 99, 99, 0.2) 0px 2px 8px 0px"
|
||||
}}
|
||||
>
|
||||
<div className="main_head">
|
||||
<div className="main-logo">
|
||||
<img
|
||||
alt="sign img"
|
||||
src="https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"
|
||||
width="100%"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!EnterOTP ? (
|
||||
<div className="row">
|
||||
<div className="col-sm-6 KLO">
|
||||
<span className="welcomeText">Welcome Back !</span>
|
||||
<br />
|
||||
<span className="KNLO">
|
||||
Verification code is sent to your email
|
||||
</span>
|
||||
<div className="card card-box" style={{ borderRadius: "0px" }}>
|
||||
<div className="card-body">
|
||||
<input
|
||||
type="email"
|
||||
name="mobile"
|
||||
value={email}
|
||||
disabled
|
||||
className="loginInput"
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div className="btnContainer">
|
||||
{loading ? (
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
disabled
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
className="verifyBtn"
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white",
|
||||
marginLeft: "0px !important"
|
||||
}}
|
||||
onClick={(e) => SendOtp(e)}
|
||||
>
|
||||
Send OTP
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="row">
|
||||
<div className="col-sm-6 KLO">
|
||||
<span className="welcomeText">Welcome Back !</span>
|
||||
<br />
|
||||
<span className="KNLO">You will get a OTP via Email</span>
|
||||
<div className="card card-box">
|
||||
<div className="card-body">
|
||||
<label>Enter Verification Code</label>
|
||||
<input
|
||||
type="number"
|
||||
className="loginInput"
|
||||
name="OTP"
|
||||
value={OTP}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
{loading ? (
|
||||
<button
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
type="button"
|
||||
disabled
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => VerifyOTP(e)}
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white"
|
||||
}}
|
||||
className="verifyBtn"
|
||||
>
|
||||
Verify
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login;
|
||||
@@ -1,921 +0,0 @@
|
||||
import React, { useState, useRef, useEffect } from "react";
|
||||
import { PDFDocument } from "pdf-lib";
|
||||
import "../css/./signature.css";
|
||||
import axios from "axios";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import { DndProvider } from "react-dnd";
|
||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||
import ModalHeader from "react-bootstrap/esm/ModalHeader";
|
||||
import { themeColor } from "../utils/ThemeColor/backColor";
|
||||
import { useParams } from "react-router-dom";
|
||||
import SignPad from "./component/signPad";
|
||||
import RenderAllPdfPage from "./component/renderAllPdfPage";
|
||||
import DefaultSignature from "./component/defaultSignature";
|
||||
import {
|
||||
getBase64FromUrl,
|
||||
getBase64FromIMG,
|
||||
pdfNewWidthFun,
|
||||
convertPNGtoJPEG,
|
||||
contractUsers,
|
||||
contactBook,
|
||||
contractDocument,
|
||||
urlValidator,
|
||||
multiSignEmbed,
|
||||
embedDocId,
|
||||
signPdfFun,
|
||||
addDefaultSignatureImg,
|
||||
onImageSelect
|
||||
} from "../utils/Utils";
|
||||
import Tour from "reactour";
|
||||
import Signedby from "./component/signedby";
|
||||
import { onSaveImage, onSaveSign } from "../utils/Utils";
|
||||
import Loader from "./component/loader";
|
||||
import HandleError from "./component/HandleError";
|
||||
import Nodata from "./component/Nodata";
|
||||
import Header from "./component/header";
|
||||
import RenderPdf from "./component/renderPdf";
|
||||
import CustomModal from "./component/CustomModal";
|
||||
import { modalAlign } from "../utils/Utils";
|
||||
import AlertComponent from "./component/alertComponent";
|
||||
function EmbedPdfImage() {
|
||||
const { id, contactBookId } = useParams();
|
||||
const [isSignPad, setIsSignPad] = useState(false);
|
||||
const [pdfUrl, setPdfUrl] = useState();
|
||||
const [allPages, setAllPages] = useState(null);
|
||||
const numPages = 1;
|
||||
const [pageNumber, setPageNumber] = useState(1);
|
||||
const [image, setImage] = useState(null);
|
||||
const [isImageSelect, setIsImageSelect] = useState(false);
|
||||
const [signature, setSignature] = useState();
|
||||
const [isStamp, setIsStamp] = useState(false);
|
||||
const [signKey, setSignKey] = useState();
|
||||
const [imgWH, setImgWH] = useState({});
|
||||
const [xyPostion, setXyPostion] = useState([]);
|
||||
const [isAlreadySign, setIsAlreadySign] = useState({ status: false });
|
||||
const imageRef = useRef(null);
|
||||
const [signedPdfData, setSignedPdfData] = useState();
|
||||
const [handleError, setHandleError] = useState();
|
||||
const [isLoading, setIsLoading] = useState({
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
});
|
||||
const [defaultSignImg, setDefaultSignImg] = useState();
|
||||
const [userObjectID, setUserObjectID] = useState();
|
||||
const [isDocId, setIsDocId] = useState(false);
|
||||
const [pdfNewWidth, setPdfNewWidth] = useState();
|
||||
const [pdfOriginalWidth, setPdfOriginalWidth] = useState();
|
||||
const [signTour, setSignTour] = useState(true);
|
||||
const [checkTourStatus, setCheckTourStatus] = useState(false);
|
||||
const [signerUserId, setSignerUserId] = useState();
|
||||
const [tourStatus, setTourStatus] = useState([]);
|
||||
const [isExpired, setIsExpired] = useState(false);
|
||||
const [noData, setNoData] = useState(false);
|
||||
const [contractName, setContractName] = useState("");
|
||||
const [isDecline, setIsDecline] = useState({
|
||||
isDeclined: false
|
||||
});
|
||||
const [addDefaultSign, setAddDefaultSign] = useState({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
});
|
||||
const [pdfLoadFail, setPdfLoadFail] = useState({
|
||||
status: false,
|
||||
type: "load"
|
||||
});
|
||||
const [containerWH, setContainerWH] = useState({});
|
||||
const [isAlert, setIsAlert] = useState({ isShow: false, alertMessage: "" });
|
||||
const docId = id && id;
|
||||
const isMobile = window.innerWidth < 767;
|
||||
const index = xyPostion.findIndex((object) => {
|
||||
return object.pageNumber === pageNumber;
|
||||
});
|
||||
const divRef = useRef(null);
|
||||
const senderUser = localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
)
|
||||
? localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
)
|
||||
: `${localStorage.getItem("UserInformation")}` &&
|
||||
`${localStorage.getItem("UserInformation")}`;
|
||||
const jsonSender = JSON.parse(senderUser);
|
||||
|
||||
useEffect(() => {
|
||||
getDocumentDetails();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (divRef.current) {
|
||||
const pdfWidth = pdfNewWidthFun(divRef);
|
||||
setPdfNewWidth(pdfWidth);
|
||||
setContainerWH({
|
||||
width: divRef.current.offsetWidth,
|
||||
height: divRef.current.offsetHeight
|
||||
});
|
||||
}
|
||||
}, [divRef.current]);
|
||||
|
||||
//function for get document details for perticular signer with signer'object id
|
||||
const getDocumentDetails = async () => {
|
||||
let currUserId, userObjectId;
|
||||
//getting contracts_contactBook details
|
||||
const json = await contactBook(contactBookId);
|
||||
if (json && json.length > 0) {
|
||||
setContractName("_Contactbook");
|
||||
|
||||
userObjectId = json[0].UserId.objectId;
|
||||
setUserObjectID(userObjectId);
|
||||
currUserId = json[0].objectId;
|
||||
|
||||
setSignerUserId(currUserId);
|
||||
const tourstatus = json[0].TourStatus && json[0].TourStatus;
|
||||
|
||||
if (tourstatus && tourstatus.length > 0) {
|
||||
setTourStatus(tourstatus);
|
||||
const checkTourRecipients = tourstatus.filter(
|
||||
(data) => data.recipientssign
|
||||
);
|
||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||
setCheckTourStatus(checkTourRecipients[0].recipientssign);
|
||||
}
|
||||
}
|
||||
} else if (json === "Error: Something went wrong!") {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
} else {
|
||||
const json = await contractUsers(jsonSender.email);
|
||||
if (json && json.length > 0) {
|
||||
setContractName("_Users");
|
||||
if (json[0]) {
|
||||
userObjectId = json[0].UserId.objectId;
|
||||
setUserObjectID(userObjectId);
|
||||
currUserId = json[0].objectId;
|
||||
|
||||
setSignerUserId(currUserId);
|
||||
const tourstatus = json[0].TourStatus && json[0].TourStatus;
|
||||
|
||||
if (tourstatus && tourstatus.length > 0) {
|
||||
setTourStatus(tourstatus);
|
||||
const checkTourRecipients = tourstatus.filter(
|
||||
(data) => data.recipientssign
|
||||
);
|
||||
if (checkTourRecipients && checkTourRecipients.length > 0) {
|
||||
setCheckTourStatus(checkTourRecipients[0].recipientssign);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
setNoData(true);
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
} else if (json === "Error: Something went wrong!") {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
} else {
|
||||
setNoData(true);
|
||||
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
}
|
||||
|
||||
//getting document details
|
||||
const documentData = await contractDocument(docId);
|
||||
if (documentData && documentData.length > 0) {
|
||||
const declined = documentData[0].IsDeclined && documentData[0].IsDeclined;
|
||||
const isCompleted =
|
||||
documentData[0].IsCompleted && documentData[0].IsCompleted;
|
||||
const expireDate = documentData[0].ExpiryDate.iso;
|
||||
|
||||
const expireUpdateDate = new Date(expireDate).getTime();
|
||||
const currDate = new Date().getTime();
|
||||
if (isCompleted) {
|
||||
//checking document is completed (signed by all requested signers) than isCompleted true
|
||||
//then show alert with completed message
|
||||
const alreadySign = {
|
||||
status: true,
|
||||
mssg: "This document has been successfully signed!"
|
||||
};
|
||||
setIsAlreadySign(alreadySign);
|
||||
setPdfUrl(documentData[0].SignedUrl);
|
||||
setSignedPdfData(documentData);
|
||||
} else if (declined) {
|
||||
const currentDecline = {
|
||||
currnt: "another",
|
||||
isDeclined: true
|
||||
};
|
||||
setIsDecline(currentDecline);
|
||||
|
||||
setSignedPdfData(documentData);
|
||||
} else if (currDate > expireUpdateDate) {
|
||||
setIsExpired(true);
|
||||
const checkDocIdExist =
|
||||
documentData[0].AuditTrail &&
|
||||
documentData[0].AuditTrail.length > 0 &&
|
||||
documentData[0].AuditTrail.filter(
|
||||
(data) => data.Activity === "Signed"
|
||||
);
|
||||
|
||||
//if signed by someone than go to in if condition
|
||||
// and second signer could not be add documentId
|
||||
//for that setIsDocId true
|
||||
if (checkDocIdExist && checkDocIdExist.length > 0) {
|
||||
setIsDocId(true);
|
||||
const currUser =
|
||||
documentData.Placeholders &&
|
||||
documentData.Placeholders.filter(
|
||||
(data) => data.signerObjId === currUserId
|
||||
);
|
||||
|
||||
setSignedPdfData(documentData);
|
||||
|
||||
setXyPostion(currUser[0].placeHolder);
|
||||
|
||||
const key = currUser[0].placeHolder[0].pos[0].key;
|
||||
setSignKey(key);
|
||||
}
|
||||
//for show current requested signer's placeholder
|
||||
else {
|
||||
const currUser =
|
||||
documentData[0].Placeholders &&
|
||||
documentData[0].Placeholders.filter(
|
||||
(data) => data.signerObjId === currUserId
|
||||
);
|
||||
|
||||
setSignedPdfData(documentData);
|
||||
|
||||
setXyPostion(currUser[0].placeHolder);
|
||||
|
||||
const key = currUser[0].placeHolder[0].pos[0].key;
|
||||
setSignKey(key);
|
||||
}
|
||||
} else {
|
||||
//checking document has signed by someone or not
|
||||
|
||||
const checkDocIdExist =
|
||||
documentData[0].AuditTrail &&
|
||||
documentData[0].AuditTrail.length > 0 &&
|
||||
documentData[0].AuditTrail.filter(
|
||||
(data) => data.Activity === "Signed"
|
||||
);
|
||||
|
||||
//if signed by someone than go to in if condition
|
||||
// and second signer could not be add documentId
|
||||
//for that setIsDocId true
|
||||
|
||||
if (checkDocIdExist && checkDocIdExist.length > 0) {
|
||||
setIsDocId(true);
|
||||
|
||||
//condition for checking document signed by current requested user or not
|
||||
const checkAlreadyBySigner = documentData[0].AuditTrail.filter(
|
||||
(data) =>
|
||||
data.UserPtr.objectId === currUserId && data.Activity === "Signed"
|
||||
);
|
||||
|
||||
// if checkAlreadyBySigner has some data that current user already sign this document
|
||||
// then show alert with message
|
||||
if (checkAlreadyBySigner && checkAlreadyBySigner.length > 0) {
|
||||
const alreadySign = {
|
||||
status: true,
|
||||
mssg: "You have successfully signed the document!"
|
||||
};
|
||||
setIsAlreadySign(alreadySign);
|
||||
setPdfUrl(documentData[0].SignedUrl);
|
||||
setSignedPdfData(documentData);
|
||||
}
|
||||
//else show placeholder of current requested signer
|
||||
else {
|
||||
const currUser =
|
||||
documentData[0].Placeholders &&
|
||||
documentData[0].Placeholders.filter(
|
||||
(data) => data.signerObjId === currUserId
|
||||
);
|
||||
|
||||
setSignedPdfData(documentData);
|
||||
|
||||
setXyPostion(currUser[0].placeHolder);
|
||||
|
||||
const key = currUser[0].placeHolder[0].pos[0].key;
|
||||
setSignKey(key);
|
||||
}
|
||||
}
|
||||
//for show current requested signer's placeholder
|
||||
else {
|
||||
const currUser =
|
||||
documentData[0].Placeholders &&
|
||||
documentData[0].Placeholders.filter(
|
||||
(data) => data.signerObjId === currUserId
|
||||
);
|
||||
|
||||
setSignedPdfData(documentData);
|
||||
|
||||
setXyPostion(currUser[0].placeHolder);
|
||||
|
||||
const key = currUser[0].placeHolder[0].pos[0].key;
|
||||
setSignKey(key);
|
||||
}
|
||||
}
|
||||
} else if (
|
||||
documentData === "Error: Something went wrong!" ||
|
||||
(documentData.result && documentData.result.error)
|
||||
) {
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
} else {
|
||||
setNoData(true);
|
||||
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
}
|
||||
await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Signature?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${userObjectId}"}}`,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
)
|
||||
.then((Listdata) => {
|
||||
const json = Listdata.data;
|
||||
const res = json.results;
|
||||
|
||||
if (res[0] && res.length > 0) {
|
||||
setDefaultSignImg(res[0].ImageURL);
|
||||
}
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("axois err ", err);
|
||||
const loadObj = {
|
||||
isLoad: false
|
||||
};
|
||||
setHandleError("Error: Something went wrong!");
|
||||
setIsLoading(loadObj);
|
||||
});
|
||||
};
|
||||
|
||||
//function for get pdf page details
|
||||
const pageDetails = async (pdf) => {
|
||||
const load = {
|
||||
status: true
|
||||
};
|
||||
setPdfLoadFail(load);
|
||||
pdf.getPage(1).then((pdfPage) => {
|
||||
const pageWidth = pdfPage.view[2];
|
||||
|
||||
setPdfOriginalWidth(pageWidth);
|
||||
});
|
||||
};
|
||||
|
||||
//function for embed signature or image url in pdf
|
||||
async function embedImages() {
|
||||
let checkSignUrl = [];
|
||||
|
||||
for (let i = 0; i < xyPostion.length; i++) {
|
||||
const posData = xyPostion[i].pos.filter((pos) => !pos.SignUrl);
|
||||
|
||||
if (posData && posData.length > 0) {
|
||||
checkSignUrl.push(posData);
|
||||
}
|
||||
}
|
||||
|
||||
if (checkSignUrl && checkSignUrl.length > 0) {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "Please complete your signature!"
|
||||
});
|
||||
} else {
|
||||
const loadObj = {
|
||||
isLoad: true,
|
||||
message: "This might take some time"
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
const url = pdfUrl
|
||||
? pdfUrl
|
||||
: signedPdfData[0] && signedPdfData[0].SignedUrl;
|
||||
const existingPdfBytes = await fetch(url).then((res) =>
|
||||
res.arrayBuffer()
|
||||
);
|
||||
|
||||
// Load a PDFDocument from the existing PDF bytes
|
||||
const pdfDoc = await PDFDocument.load(existingPdfBytes, {
|
||||
ignoreEncryption: true
|
||||
});
|
||||
|
||||
const pngUrl = xyPostion;
|
||||
|
||||
let pdfBase64;
|
||||
//checking if signature is only one then send image url in jpeg formate to server
|
||||
if (xyPostion.length === 1 && xyPostion[0].pos.length === 1) {
|
||||
if (isDocId) {
|
||||
pdfBase64 = await getBase64FromUrl(url);
|
||||
} else {
|
||||
//embed document's object id to all pages in pdf document
|
||||
await embedDocId(pdfDoc, docId, allPages);
|
||||
pdfBase64 = await pdfDoc.saveAsBase64({ useObjectStreams: false });
|
||||
}
|
||||
|
||||
for (let xyData of xyPostion) {
|
||||
const imgUrlList = xyData.pos;
|
||||
const pageNo = xyData.pageNumber;
|
||||
imgUrlList.map(async (data) => {
|
||||
//cheking signUrl is defau;t signature url of custom url
|
||||
let ImgUrl = data.SignUrl;
|
||||
const checkUrl = urlValidator(ImgUrl);
|
||||
|
||||
//if default signature url then convert it in base 64
|
||||
if (checkUrl) {
|
||||
ImgUrl = await getBase64FromIMG(ImgUrl + "?get");
|
||||
}
|
||||
//function for convert signature png base64 url to jpeg base64
|
||||
convertPNGtoJPEG(ImgUrl)
|
||||
.then((jpegBase64Data) => {
|
||||
const removeBase64Fromjpeg = "data:image/jpeg;base64,";
|
||||
const newImgUrl = jpegBase64Data.replace(
|
||||
removeBase64Fromjpeg,
|
||||
""
|
||||
);
|
||||
|
||||
//function for embed signature in pdf and get digital signature pdf
|
||||
signPdfFun(
|
||||
newImgUrl,
|
||||
docId,
|
||||
signerUserId,
|
||||
pdfOriginalWidth,
|
||||
xyPostion,
|
||||
containerWH,
|
||||
setIsAlert,
|
||||
data,
|
||||
pdfBase64,
|
||||
pageNo
|
||||
)
|
||||
.then((res) => {
|
||||
if (res && res.status === "success") {
|
||||
getDocumentDetails();
|
||||
} else {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
//else if signature is more than one then embed all sign with the use of pdf-lib
|
||||
else if (xyPostion.length > 0 && xyPostion[0].pos.length > 0) {
|
||||
const flag = false;
|
||||
//embed document's object id to all pages in pdf document
|
||||
await embedDocId(pdfDoc, docId, allPages);
|
||||
//embed multi signature in pdf
|
||||
const pdfBytes = await multiSignEmbed(
|
||||
pngUrl,
|
||||
pdfDoc,
|
||||
pdfOriginalWidth,
|
||||
flag,
|
||||
containerWH
|
||||
);
|
||||
|
||||
//function for embed signature in pdf and get digital signature pdf
|
||||
try {
|
||||
const res = await signPdfFun(
|
||||
pdfBytes,
|
||||
docId,
|
||||
signerUserId,
|
||||
pdfOriginalWidth,
|
||||
xyPostion,
|
||||
containerWH,
|
||||
setIsAlert
|
||||
);
|
||||
if (res && res.status === "success") {
|
||||
getDocumentDetails();
|
||||
} else {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
}
|
||||
}
|
||||
setIsSignPad(false);
|
||||
setXyPostion([]);
|
||||
}
|
||||
}
|
||||
|
||||
//function for change page
|
||||
function changePage(offset) {
|
||||
setPageNumber((prevPageNumber) => prevPageNumber + offset);
|
||||
}
|
||||
|
||||
//function for image upload or update
|
||||
const onImageChange = (event) => {
|
||||
if (event.target.files && event.target.files[0]) {
|
||||
onImageSelect(event, setImgWH, setImage);
|
||||
}
|
||||
};
|
||||
|
||||
//function for save button to save signature or image url
|
||||
const saveSign = (isDefaultSign) => {
|
||||
const signatureImg = isDefaultSign ? defaultSignImg : signature;
|
||||
const signFlag = true;
|
||||
let imgWH = { width: "", height: "" };
|
||||
setIsSignPad(false);
|
||||
setIsImageSelect(false);
|
||||
setImage();
|
||||
|
||||
if (isDefaultSign) {
|
||||
const img = new Image();
|
||||
img.src = defaultSignImg;
|
||||
if (img.complete) {
|
||||
imgWH = {
|
||||
width: img.width,
|
||||
height: img.height
|
||||
};
|
||||
}
|
||||
}
|
||||
const getUpdatePosition = onSaveSign(
|
||||
xyPostion,
|
||||
index,
|
||||
signKey,
|
||||
signatureImg,
|
||||
imgWH,
|
||||
isDefaultSign,
|
||||
signFlag
|
||||
);
|
||||
|
||||
if (getUpdatePosition) {
|
||||
setXyPostion(getUpdatePosition);
|
||||
}
|
||||
};
|
||||
//function for upload stamp image
|
||||
const saveImage = () => {
|
||||
const getImage = onSaveImage(xyPostion, index, signKey, imgWH, image);
|
||||
setXyPostion(getImage);
|
||||
};
|
||||
|
||||
//function for set decline true on press decline button
|
||||
const declineDoc = async () => {
|
||||
const data = {
|
||||
IsDeclined: true
|
||||
};
|
||||
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document/${docId}`,
|
||||
data,
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
)
|
||||
.then((result) => {
|
||||
const res = result.data;
|
||||
if (res) {
|
||||
const currentDecline = {
|
||||
currnt: "YouDeclined",
|
||||
isDeclined: true
|
||||
};
|
||||
setIsDecline(currentDecline);
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
setIsAlert({
|
||||
isShow: true,
|
||||
alertMessage: "something went wrong"
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const addDefaultSignature = () => {
|
||||
const getXyData = addDefaultSignatureImg(xyPostion, defaultSignImg);
|
||||
|
||||
setXyPostion(getXyData);
|
||||
setAddDefaultSign({
|
||||
isShow: false,
|
||||
alertMessage: ""
|
||||
});
|
||||
};
|
||||
|
||||
//function for update TourStatus
|
||||
const closeTour = async () => {
|
||||
setSignTour(false);
|
||||
|
||||
let updatedTourStatus = [];
|
||||
if (tourStatus.length > 0) {
|
||||
updatedTourStatus = [...tourStatus];
|
||||
const recipientssignIndex = tourStatus.findIndex(
|
||||
(obj) =>
|
||||
obj["recipientssign"] === false || obj["recipientssign"] === true
|
||||
);
|
||||
if (recipientssignIndex !== -1) {
|
||||
updatedTourStatus[recipientssignIndex] = { recipientssign: true };
|
||||
} else {
|
||||
updatedTourStatus.push({ recipientssign: true });
|
||||
}
|
||||
} else {
|
||||
updatedTourStatus = [{ recipientssign: true }];
|
||||
}
|
||||
|
||||
await axios
|
||||
.put(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}${contractName}/${signerUserId}`,
|
||||
{
|
||||
TourStatus: updatedTourStatus
|
||||
},
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||
}
|
||||
}
|
||||
)
|
||||
.then((Listdata) => {
|
||||
// const json = Listdata.data;
|
||||
// const res = json.results;
|
||||
// console.log("res", json);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("axois err ", err);
|
||||
});
|
||||
};
|
||||
|
||||
const tourFunction = () => {
|
||||
const tourConfig = [
|
||||
{
|
||||
selector: '[data-tut="reactourFirst"]',
|
||||
content: `You can click "Auto Sign All" to automatically sign at all the locations meant to be signed by you.Make sure that you review the document properly before you click this button.`,
|
||||
position: "top",
|
||||
style: { fontSize: "13px" }
|
||||
},
|
||||
{
|
||||
selector: '[data-tut="reactourSecond"]',
|
||||
content: `Click any of such placeholders appearing on the document to sign.You will see the options to draw sign or upload an image once you click here.`,
|
||||
position: "top",
|
||||
style: { fontSize: "13px" }
|
||||
},
|
||||
{
|
||||
selector: '[data-tut="reactourThird"]',
|
||||
content: `Click here to finish & download the signed document.You will also receive a copy on your email.`,
|
||||
position: "top",
|
||||
style: { fontSize: "13px" }
|
||||
}
|
||||
];
|
||||
|
||||
let stepsToShow = [];
|
||||
if (!defaultSignImg || isMobile) {
|
||||
stepsToShow = tourConfig.filter(
|
||||
(step) => step.selector !== '[data-tut="reactourFirst"]'
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Tour
|
||||
onRequestClose={closeTour}
|
||||
steps={stepsToShow && stepsToShow.length > 0 ? stepsToShow : tourConfig}
|
||||
isOpen={signTour}
|
||||
closeWithMask={false}
|
||||
rounded={5}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<DndProvider backend={HTML5Backend}>
|
||||
{isLoading.isLoad ? (
|
||||
<Loader isLoading={isLoading} />
|
||||
) : handleError ? (
|
||||
<HandleError handleError={handleError} />
|
||||
) : noData ? (
|
||||
<Nodata />
|
||||
) : (
|
||||
<div className="signatureContainer" ref={divRef}>
|
||||
{/* this modal is used to show decline alert */}
|
||||
<CustomModal
|
||||
containerWH={containerWH}
|
||||
show={isDecline.isDeclined}
|
||||
headMsg="Document Declined Alert!"
|
||||
bodyMssg={
|
||||
isDecline.currnt === "Sure" ? (
|
||||
<p>Are you sure want to decline this document ?</p>
|
||||
) : isDecline.currnt === "YouDeclined" ? (
|
||||
<p>You have declined this document!</p>
|
||||
) : (
|
||||
isDecline.currnt === "another" && (
|
||||
<p>
|
||||
You cannot sign this document as it has been declined by one
|
||||
or more person(s).
|
||||
</p>
|
||||
)
|
||||
)
|
||||
}
|
||||
footerMessage={isDecline.currnt === "Sure"}
|
||||
declineDoc={declineDoc}
|
||||
setIsDecline={setIsDecline}
|
||||
/>
|
||||
<AlertComponent
|
||||
isShow={isAlert.isShow}
|
||||
alertMessage={isAlert.alertMessage}
|
||||
setIsAlert={setIsAlert}
|
||||
/>
|
||||
<AlertComponent
|
||||
isShow={addDefaultSign.isShow}
|
||||
alertMessage={addDefaultSign.alertMessage}
|
||||
setIsAlert={setAddDefaultSign}
|
||||
isdefaultSign={true}
|
||||
addDefaultSignature={addDefaultSignature}
|
||||
headBG={themeColor()}
|
||||
/>
|
||||
|
||||
{/* this modal is used for show expired alert */}
|
||||
<CustomModal
|
||||
containerWH={containerWH}
|
||||
show={isExpired}
|
||||
headMsg="Document Expired!"
|
||||
bodyMssg="This Document is no longer available."
|
||||
/>
|
||||
{/* this component used for UI interaction and show their functionality */}
|
||||
{pdfLoadFail.status &&
|
||||
!isExpired &&
|
||||
!checkTourStatus &&
|
||||
tourFunction()}
|
||||
|
||||
{/* this component used to render all pdf pages in left side */}
|
||||
<RenderAllPdfPage
|
||||
pdfUrl={pdfUrl}
|
||||
signPdfUrl={signedPdfData[0] && signedPdfData[0].URL}
|
||||
allPages={allPages}
|
||||
setAllPages={setAllPages}
|
||||
setPageNumber={setPageNumber}
|
||||
/>
|
||||
{/* <div style={{width:"160px",border:"1px solid red"}}>kebjke</div> */}
|
||||
{/* pdf render view */}
|
||||
<div
|
||||
style={{
|
||||
marginLeft: !isMobile && pdfOriginalWidth > 500 && "20px",
|
||||
marginRight: !isMobile && pdfOriginalWidth > 500 && "20px"
|
||||
}}
|
||||
ref={divRef}
|
||||
>
|
||||
{/* this modal is used show this document is already sign */}
|
||||
<Modal
|
||||
show={isAlreadySign.status}
|
||||
onShow={() => modalAlign()}
|
||||
backdropClassName="signature-backdrop"
|
||||
>
|
||||
<ModalHeader style={{ background: themeColor() }}>
|
||||
<span style={{ color: "white" }}> Sign Documents</span>
|
||||
</ModalHeader>
|
||||
|
||||
<Modal.Body>
|
||||
<p>{isAlreadySign.mssg}</p>
|
||||
</Modal.Body>
|
||||
|
||||
<Modal.Footer>
|
||||
<button
|
||||
style={{
|
||||
borderRadius: "0px",
|
||||
border: "1.5px solid #e3e2e1",
|
||||
fontWeight: "600",
|
||||
color: "black"
|
||||
}}
|
||||
className="btn"
|
||||
onClick={() => setIsAlreadySign({ status: false })}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
{/* this is modal of signature pad */}
|
||||
<SignPad
|
||||
isSignPad={isSignPad}
|
||||
isStamp={isStamp}
|
||||
setIsImageSelect={setIsImageSelect}
|
||||
setIsSignPad={setIsSignPad}
|
||||
setImage={setImage}
|
||||
isImageSelect={isImageSelect}
|
||||
imageRef={imageRef}
|
||||
onImageChange={onImageChange}
|
||||
setSignature={setSignature}
|
||||
image={image}
|
||||
onSaveImage={saveImage}
|
||||
onSaveSign={saveSign}
|
||||
defaultSign={defaultSignImg}
|
||||
/>
|
||||
|
||||
{/* pdf header which contain finish back button */}
|
||||
<Header
|
||||
recipient={true}
|
||||
pdfDetails={signedPdfData}
|
||||
isAlreadySign={isAlreadySign}
|
||||
pageNumber={pageNumber}
|
||||
allPages={allPages}
|
||||
changePage={changePage}
|
||||
pdfUrl={pdfUrl}
|
||||
setIsDecline={setIsDecline}
|
||||
embedImages={embedImages}
|
||||
isShowHeader={true}
|
||||
currentSigner={true}
|
||||
decline={true}
|
||||
alreadySign={pdfUrl ? true : false}
|
||||
/>
|
||||
{containerWH && (
|
||||
<RenderPdf
|
||||
pageNumber={pageNumber}
|
||||
pdfOriginalWidth={pdfOriginalWidth}
|
||||
pdfNewWidth={pdfNewWidth}
|
||||
setIsSignPad={setIsSignPad}
|
||||
setIsStamp={setIsStamp}
|
||||
setSignKey={setSignKey}
|
||||
pdfDetails={signedPdfData}
|
||||
xyPostion={xyPostion}
|
||||
successEmail={false}
|
||||
pdfUrl={pdfUrl}
|
||||
numPages={numPages}
|
||||
pageDetails={pageDetails}
|
||||
recipient={true}
|
||||
isAlreadySign={isAlreadySign}
|
||||
setPdfLoadFail={setPdfLoadFail}
|
||||
pdfLoadFail={pdfLoadFail}
|
||||
setXyPostion={setXyPostion}
|
||||
index={index}
|
||||
containerWH={containerWH}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{!pdfUrl ? (
|
||||
<div data-tut="reactourFirst">
|
||||
{/* this component is used to render default signature of user in the right side of the component */}
|
||||
|
||||
<DefaultSignature
|
||||
themeColor={themeColor}
|
||||
defaultSignImg={defaultSignImg}
|
||||
setDefaultSignImg={setDefaultSignImg}
|
||||
userObjectId={userObjectID}
|
||||
setIsLoading={setIsLoading}
|
||||
xyPostion={xyPostion}
|
||||
setXyPostion={setXyPostion}
|
||||
setShowAlreadySignDoc={setIsAlreadySign}
|
||||
setIsAlert={setAddDefaultSign}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<Signedby pdfDetails={signedPdfData[0]} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</DndProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export default EmbedPdfImage;
|
||||
@@ -1,55 +0,0 @@
|
||||
import React from "react";
|
||||
import { Routes, Route } from "react-router-dom";
|
||||
import SignYourselfPdf from "./Component/SignYourselfPdf";
|
||||
import RecipientSignPdf from "./Component/recipientSignPdf";
|
||||
import PlaceHolderSign from "./Component/placeHolderSign";
|
||||
import ManageSign from "./Component/ManageSign";
|
||||
import Login from "./Component/login";
|
||||
import DraftDocument from "./Component/DraftDocument";
|
||||
import PdfRequestFiles from "./Component/PdfRequestFiles";
|
||||
import LegaDrive from "./Component/LegaDrive/LegaDrive";
|
||||
import PageNotFound from "./Component/PageNotFound";
|
||||
|
||||
// `AppRoutes` is used to define route path of app and
|
||||
// it expose to host app, check moduleFederation.config.js for more
|
||||
function AppRoutes() {
|
||||
return (
|
||||
<div>
|
||||
<Routes>
|
||||
{/* TODO: Check with images and other assets */}
|
||||
<Route index element={<div>Microapp Home page route </div>} />
|
||||
{/* signyouself route with rowlevel data */}
|
||||
<Route path="/signaturePdf" element={<SignYourselfPdf />} />
|
||||
{/* signyouself route with no rowlevel data using docId from url */}
|
||||
<Route path="/signaturePdf/:docId" element={<SignYourselfPdf />} />
|
||||
{/* recipient signature route with no rowlevel data using docId from url */}
|
||||
<Route
|
||||
path="/recipientSignPdf/:id/:contactBookId"
|
||||
element={<RecipientSignPdf />}
|
||||
/>
|
||||
{/* recipient placeholder set route with rowlevel data */}
|
||||
<Route path="/placeHolderSign" element={<PlaceHolderSign />} />{" "}
|
||||
{/* recipient placeholder set route with no rowlevel data using docId from url*/}
|
||||
<Route path="/placeHolderSign/:docId" element={<PlaceHolderSign />} />
|
||||
{/*Add default signature of user route */}
|
||||
<Route path="/managesign" element={<ManageSign />} />
|
||||
{/* login page route */}
|
||||
<Route
|
||||
path="/login/:id/:userMail/:contactBookId/:serverUrl"
|
||||
element={<Login />}
|
||||
/>
|
||||
{/* draft document route to handle and navigate route page accordiing to document status */}
|
||||
<Route path="/draftDocument" element={<DraftDocument />} />
|
||||
{/* for user signature (need your sign route) with row level data */}
|
||||
<Route path="/pdfRequestFiles" element={<PdfRequestFiles />} />
|
||||
{/* for user signature (need your sign route) with no row level data */}
|
||||
<Route path="/pdfRequestFiles/:docId" element={<PdfRequestFiles />} />
|
||||
{/* lega drive route */}
|
||||
<Route path="/legadrive" element={<LegaDrive />} />
|
||||
{/* Page Not Found */}
|
||||
<Route path="*" element={<PageNotFound />} />
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default AppRoutes;
|
||||
|
Before Width: | Height: | Size: 430 B |
|
Before Width: | Height: | Size: 574 B |
|
Before Width: | Height: | Size: 448 B |
|
Before Width: | Height: | Size: 324 B |
|
Before Width: | Height: | Size: 259 B |
|
Before Width: | Height: | Size: 272 B |
|
Before Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 76 KiB |
|
Before Width: | Height: | Size: 4.4 KiB |
|
Before Width: | Height: | Size: 61 KiB |
|
Before Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 234 KiB |
|
Before Width: | Height: | Size: 86 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 208 B |
|
Before Width: | Height: | Size: 569 B |
|
Before Width: | Height: | Size: 804 B |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 561 B |
@@ -1,7 +0,0 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||
|
||||
root.render(<App />);
|
||||
@@ -1,210 +0,0 @@
|
||||
.loginInput{
|
||||
padding: 10px;
|
||||
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
font-size: 0.75rem;
|
||||
border: 1px solid #e2dddd;;
|
||||
background-color: #e0e5f5;
|
||||
color: black;
|
||||
|
||||
padding-left: 1rem!important;
|
||||
padding-right: 1rem!important;
|
||||
padding-top: 0.5rem!important;
|
||||
|
||||
font-family: inherit;
|
||||
font-feature-settings: inherit;
|
||||
font-variation-settings: inherit;
|
||||
font-weight: inherit;
|
||||
overflow: visible;
|
||||
|
||||
}
|
||||
.loginInput:focus{
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
.verifyBtn{
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 3px 30px;
|
||||
color: white;
|
||||
font-weight: 500 !important;
|
||||
font-size: 14px !important;
|
||||
border: none;
|
||||
}
|
||||
.verifyBtn:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
.verifyBtn:hover {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
color: white;
|
||||
}
|
||||
.fakeimg {
|
||||
height: 200px;
|
||||
background: #aaa;
|
||||
}
|
||||
|
||||
.GTRY {
|
||||
border: 1px solid #dee2e6;
|
||||
margin-top: 75px;
|
||||
padding-bottom: 20px;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.main_head {
|
||||
width: 100%;
|
||||
height: 66px;
|
||||
background-color: #fff;
|
||||
margin-bottom: 52px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.main-logo {
|
||||
width: 250px;
|
||||
height: 66px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.card-box {
|
||||
background: #fff;
|
||||
min-height: 50px;
|
||||
box-shadow: 0 20px 20px rgba(0, 0, 0, 0.1);
|
||||
position: relative;
|
||||
margin-bottom: 20px;
|
||||
transition: 0.5s;
|
||||
border: 1px solid #f2f2f2;
|
||||
border-radius: 7px;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.LKJH {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.GTR {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.JUI {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.btn-info {
|
||||
color: #fff;
|
||||
background-color: #15b4e9;
|
||||
border-color: #15b4e9;
|
||||
}
|
||||
|
||||
.btn-info:hover {
|
||||
color: #fff;
|
||||
background-color: #15b4e9;
|
||||
border-color: #15b4e9;
|
||||
}
|
||||
|
||||
.btn-reg {
|
||||
color: #15b4e9;
|
||||
background-color: #ffffff;
|
||||
border-color: #15b4e9;
|
||||
}
|
||||
|
||||
.btn-reg:hover {
|
||||
color: #15b4e9;
|
||||
background-color: #ffffff;
|
||||
border-color: #15b4e9;
|
||||
}
|
||||
|
||||
.SYTU {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.MLKI {
|
||||
float: right;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
|
||||
.login-btn {
|
||||
width: 100% !important;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 667px) {
|
||||
.MLKI {
|
||||
float: inherit;
|
||||
}
|
||||
|
||||
|
||||
.login-btn {
|
||||
width: 210px !important;
|
||||
}
|
||||
}
|
||||
|
||||
.MLKI a {
|
||||
color: #212529;
|
||||
}
|
||||
|
||||
.KNLO {
|
||||
color: #878787;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
margin-left: 17px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
.welcomeText{
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 600px) {
|
||||
.KLO1 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.MLKI a {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
font-size: 12px;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
.MKUY {
|
||||
text-align: center;
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
||||
.main_head {
|
||||
margin-bottom: 12px;
|
||||
padding-top: 10px;
|
||||
border-bottom: 1px dashed #eeeeee;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@media screen and (max-width:366px) {
|
||||
|
||||
.main-logo {
|
||||
width: 150px;
|
||||
height: 46px;
|
||||
display: inline-block;
|
||||
}
|
||||
.welcomeText{
|
||||
font-size: 20px;
|
||||
}
|
||||
.KNLO {
|
||||
color: #878787;
|
||||
font-size: 10px;
|
||||
}
|
||||
.btnContainer{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,225 +0,0 @@
|
||||
.mainDiv {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.successBtn {
|
||||
background: #3ac9d6;
|
||||
border: 1px solid #3ac9d6;
|
||||
}
|
||||
|
||||
.warning {
|
||||
position: absolute;
|
||||
padding: 8px;
|
||||
border: 1px solid black;
|
||||
background: white;
|
||||
width: 300px;
|
||||
border-radius: 5px;
|
||||
animation: inAnimation 2s ease-in-out;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.nameWarning {
|
||||
position: absolute;
|
||||
bottom: -70px;
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.nameWarning::before {
|
||||
content: '';
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-style: outset;
|
||||
border-width: 0px 10px 10px 10px;
|
||||
border-color: transparent transparent black transparent;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: -29%;
|
||||
left: 0;
|
||||
right: 75%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.signWarning {
|
||||
bottom: 70px;
|
||||
left: 50px;
|
||||
}
|
||||
|
||||
.signWarning::before {
|
||||
content: '';
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
border-style: outset;
|
||||
border-width: 0px 10px 10px 10px;
|
||||
border-color: transparent transparent black transparent;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: -29%;
|
||||
left: 0;
|
||||
right: 75%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.successBox {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 13px;
|
||||
animation: inAnimation 2s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes inAnimation {
|
||||
0% {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
25% {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
75% {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.signature {
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: 10px 14px 10px;
|
||||
background: #15b4e9;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.signature:hover {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
background: #13a8da;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.imgupload {
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
padding: 10px 14px 10px;
|
||||
background: #15b4e9;
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
min-width: 105px;
|
||||
}
|
||||
|
||||
.imgupload:hover {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
background: #13a8da;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
.loaderContainer {
|
||||
position: fixed;
|
||||
inset: 0%;
|
||||
width: 100%;
|
||||
height: 100svh;
|
||||
background: linear-gradient(rgba(0, 0, 0, 0.7), rgba(0, 0, 0, 0.7));
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.loader {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
border-top: 4px solid #1b8ef4;
|
||||
border-left: 4px solid #1b8ef4;
|
||||
border-radius: 80%;
|
||||
animation: spin 0.5s linear infinite;
|
||||
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.customBtn {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 10px 14px 10px;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 12px;
|
||||
text-transform: uppercase;
|
||||
border-radius: 2px;
|
||||
margin-left: 10px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.clearbtn {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.clearbtn:hover {
|
||||
text-decoration: underline;
|
||||
text-underline-offset: 2px;
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.successBtn:hover {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
background: #1ab6ce;
|
||||
color: white;
|
||||
|
||||
}
|
||||
|
||||
.resetBtn {
|
||||
background: #188ae2;
|
||||
margin-left: 10;
|
||||
border: 1px solid #188ae2;
|
||||
}
|
||||
|
||||
.resetBtn:hover {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
background: #177ecd;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.signBlock {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 12px;
|
||||
}
|
||||
.signInputManage{
|
||||
width: 50%;
|
||||
}
|
||||
@media (max-width: 815px) {
|
||||
.signBlock {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
.signInputManage{
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +0,0 @@
|
||||
.parentDiv {
|
||||
background: gray;
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
background-color: rgba(0, 0, 0, 0.75);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.childDiv {
|
||||
width: 50%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-content: center;
|
||||
background-color: #fff;
|
||||
margin: 30px 20px;
|
||||
border: 0px 1px 1px 1px solid rgba(0, 0, 0, .2);
|
||||
border-radius: 0.3rem;
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.modalHeadDiv {
|
||||
padding: 10px;
|
||||
color: #fff;
|
||||
border-top-left-radius: 0.3rem;
|
||||
border-top-right-radius: 0.3rem;
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.modalBodyDIv {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.spanTagHead {
|
||||
color: white !important;
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.pTagBody {
|
||||
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
.modalFooterDiv {
|
||||
margin: 10px;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
@media screen and (max-width:500px) {
|
||||
.childDiv {
|
||||
margin: 50px 7px;
|
||||
width: 90%;
|
||||
}
|
||||
}
|
||||
@@ -1,877 +0,0 @@
|
||||
.signatureCanvas {
|
||||
border: 2px solid #888;
|
||||
background-color: rgb(255, 255, 255);
|
||||
width: 460px;
|
||||
height: 184px;
|
||||
}
|
||||
|
||||
.penContainer {
|
||||
width: 460px;
|
||||
}
|
||||
|
||||
.borderResize {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
|
||||
}
|
||||
|
||||
.mailBtn {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 3px 15px !important;
|
||||
background-color: rgb(79 190 241);
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.mailBtn:hover {
|
||||
box-shadow: 0 2px 4px rgba(154, 36, 36, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.emailToast {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
background: #aeedae;
|
||||
padding: 0 3px 3px 3px;
|
||||
margin: 2px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
|
||||
.signatureBtn {
|
||||
border: 1.5px solid #47a3ad;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
padding: 0px;
|
||||
justify-content: space-between;
|
||||
background: white;
|
||||
transition-duration: 0.4s;
|
||||
cursor: all-scroll;
|
||||
width: 150px;
|
||||
height: 30px;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.disableSign {
|
||||
border: 1.5px solid #47a3ad;
|
||||
margin-bottom: 10px;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
padding: 0px;
|
||||
justify-content: space-between;
|
||||
background: white;
|
||||
transition-duration: 0.4s;
|
||||
cursor: all-scroll;
|
||||
width: 150px;
|
||||
height: 30px;
|
||||
color: black;
|
||||
border: 1px solid rgb(203, 203, 203);
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.emailInput {
|
||||
padding: 10px;
|
||||
border: 1.5px solid gray;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.emailInput:focus {
|
||||
outline: none;
|
||||
border: 1.5px solid #47a3ad;
|
||||
}
|
||||
|
||||
.addEmail {
|
||||
padding: "0px";
|
||||
border: 1.5px solid #47a3ad;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.addEmail,
|
||||
.emailInput {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.addEmailInput {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.emailChip {
|
||||
background-color: #47a3ad;
|
||||
margin: 4px;
|
||||
border-radius: 10px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.emailChipClose:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.addEmailInput {
|
||||
padding: 10px;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.addEmailInput:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.signatureInput {
|
||||
padding: 10px;
|
||||
width: 80%;
|
||||
border-radius: 4px;
|
||||
font-size: 0.75rem;
|
||||
border: 1px solid #e2dddd;
|
||||
color: black;
|
||||
font-family: inherit;
|
||||
font-feature-settings: inherit;
|
||||
font-variation-settings: inherit;
|
||||
font-weight: inherit;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
.signatureInput:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.resizable-box-overlay {
|
||||
position: absolute;
|
||||
border: 2px solid #ddd;
|
||||
overflow: hidden;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.box-content {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.close-button {
|
||||
align-self: flex-end;
|
||||
margin: 8px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.placeholdCloseBtn {
|
||||
position: absolute;
|
||||
right: -5px;
|
||||
top: -5px;
|
||||
border-radius: 100%;
|
||||
font-size: 10px;
|
||||
cursor: pointer;
|
||||
padding: 0px 5.1px 1px 5px;
|
||||
}
|
||||
|
||||
.placeholderBlock {
|
||||
padding: 0px;
|
||||
position: absolute;
|
||||
border-style: dashed;
|
||||
width: 150px;
|
||||
height: 60px;
|
||||
background: #daebe0;
|
||||
text-align: center;
|
||||
justify-content: center;
|
||||
border-width: 0.2px;
|
||||
|
||||
}
|
||||
|
||||
.finishBtn {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 3px 30px;
|
||||
color: white;
|
||||
font-weight: 500 !important;
|
||||
font-size: 14px !important;
|
||||
border: none;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.sendMail {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 3px 30px;
|
||||
color: white;
|
||||
font-weight: 500 !important;
|
||||
font-size: 14px !important;
|
||||
border: none;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.finishBtn:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.finishBtn:hover {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.saveBtn {
|
||||
padding: 3px 18px !important;
|
||||
}
|
||||
|
||||
.disabledFinish {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 3px 30px;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.sendHover:hover {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.defaultSignBox {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
width: 180px;
|
||||
height: 111px;
|
||||
padding: 8px 20px;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
font-size: 14px;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.defaultBtn {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 3px 26px;
|
||||
color: black;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
border: 1px solid gray;
|
||||
border-radius: 2px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.backBtn {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.backBtn:hover {
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.defaultBtn:focus {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.downloadBtn {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 3px 15px !important;
|
||||
background-color: rgb(241 79 79);
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.downloadBtn:hover {
|
||||
box-shadow: 0 2px 4px rgba(154, 36, 36, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.printBtn {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 3px 15px !important;
|
||||
background: #188ae2;
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.printBtn:hover {
|
||||
box-shadow: 0 2px 4px rgba(23, 48, 137, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.certificateBtn {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
padding: 3px 15px !important;
|
||||
background: #08bc66;
|
||||
border: none !important;
|
||||
color: white !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.certificateBtn:hover {
|
||||
box-shadow: 0 2px 4px rgba(15, 150, 87, 0.1), 0 2px 4px rgba(0, 0, 0, 0.18);
|
||||
}
|
||||
|
||||
.signerList {
|
||||
overflow-y: scroll;
|
||||
max-height: 180px;
|
||||
}
|
||||
|
||||
.signerList::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.showScroll {
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
|
||||
}
|
||||
|
||||
.showScroll::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.hideScroll {
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
.signedStyle {
|
||||
color: white;
|
||||
padding: 5px;
|
||||
font-family: sans-serif;
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
.userName {
|
||||
font-size: 12px !important;
|
||||
font-weight: bold !important;
|
||||
color: #424242 !important;
|
||||
width: 100px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.useEmail {
|
||||
font-size: 10px;
|
||||
color: #424242;
|
||||
font-weight: 500;
|
||||
width: 100px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.spanTagHead {
|
||||
color: white !important;
|
||||
font-size: 17px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.pTagBody {
|
||||
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
.signTab {
|
||||
cursor: pointer !important;
|
||||
font-weight: 400 !important;
|
||||
margin-left: 10px !important;
|
||||
font-size: 15px !important;
|
||||
}
|
||||
|
||||
.draggable-button {
|
||||
padding: 10px 20px;
|
||||
background: #3498db;
|
||||
color: #fff;
|
||||
border: none;
|
||||
cursor: grab;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
.draggable-button.dragging {
|
||||
opacity: 0.5;
|
||||
/* Reduce opacity while dragging */
|
||||
transform: scale(1.1);
|
||||
/* Apply a scaling effect while dragging */
|
||||
}
|
||||
|
||||
.signatureContainer {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
background-color: #ebebeb;
|
||||
position: "relative"
|
||||
}
|
||||
|
||||
.signatureHeader {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.signerComponent {
|
||||
/* box-shadow: rgba(17, 12, 46, 0.15) 0px 48px 100px 0px; */
|
||||
width: 180px;
|
||||
background-color: white;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.modalBody {
|
||||
padding: 1rem !important;
|
||||
padding-top: 2rem !important;
|
||||
}
|
||||
|
||||
.signLayoutContainer1 {
|
||||
padding: 30px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center
|
||||
}
|
||||
|
||||
.signLayoutContainer2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.preBtn1 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.preBtn2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.headerBtn2 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.uploadImgLogo {
|
||||
font-size: 50px;
|
||||
}
|
||||
|
||||
.DropdownMenuContent,
|
||||
.DropdownMenuSubContent {
|
||||
min-width: 130px;
|
||||
background-color: #fff;
|
||||
border: 1px solid rgba(0, 0, 0, .15);
|
||||
border-radius: 0.25rem;
|
||||
padding: 5px;
|
||||
animation-duration: 400ms;
|
||||
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
will-change: transform, opacity;
|
||||
z-index: 30 !important;
|
||||
}
|
||||
|
||||
.DropdownMenuContent[data-side='top'],
|
||||
.DropdownMenuSubContent[data-side='top'] {
|
||||
animation-name: slideDownAndFade;
|
||||
}
|
||||
|
||||
.DropdownMenuContent[data-side='right'],
|
||||
.DropdownMenuSubContent[data-side='right'] {
|
||||
animation-name: slideLeftAndFade;
|
||||
}
|
||||
|
||||
.DropdownMenuContent[data-side='bottom'],
|
||||
.DropdownMenuSubContent[data-side='bottom'] {
|
||||
animation-name: slideUpAndFade;
|
||||
}
|
||||
|
||||
.DropdownMenuContent[data-side='left'],
|
||||
.DropdownMenuSubContent[data-side='left'] {
|
||||
animation-name: slideRightAndFade;
|
||||
}
|
||||
|
||||
.DropdownMenuItem {
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
color: black;
|
||||
background-color: #fff;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 25px;
|
||||
padding: 0 5px;
|
||||
position: relative;
|
||||
padding-left: 20px;
|
||||
user-select: none;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.SelectTrigger {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
padding: 0 70px;
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
height: 35px;
|
||||
gap: 5px;
|
||||
border: none;
|
||||
background-color: #887abf;
|
||||
|
||||
width: 100px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.selectEmail {
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 4px;
|
||||
padding: 0 15px;
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
height: 35px;
|
||||
gap: 5px;
|
||||
border: none;
|
||||
background-color: #887abf;
|
||||
|
||||
width: 200px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden !important;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
option {
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
|
||||
.SelectTrigger:hover {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.selectEmail:hover {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
.SelectTrigger:focus {
|
||||
/* box-shadow: 0 0 0 2px black; */
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.selectEmail:focus {
|
||||
/* box-shadow: 0 0 0 2px black; */
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.SelectTrigger[data-placeholder] {
|
||||
color: black;
|
||||
}
|
||||
|
||||
.SelectIcon {
|
||||
color: Var(--violet-11);
|
||||
}
|
||||
|
||||
.SelectContent {
|
||||
overflow: hidden;
|
||||
background-color: white;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0px 10px 38px -10px rgba(22, 23, 24, 0.35), 0px 10px 20px -15px rgba(22, 23, 24, 0.2);
|
||||
}
|
||||
|
||||
.SelectViewport {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.SelectItem {
|
||||
font-size: 13px;
|
||||
line-height: 1;
|
||||
color: var(--violet-11);
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 25px;
|
||||
padding: 0 35px 0 25px;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
z-index: 10 !important;
|
||||
}
|
||||
|
||||
.SelectItem[data-disabled] {
|
||||
color: var(--mauve-8);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.SelectItem[data-highlighted] {
|
||||
outline: none;
|
||||
background-color: var(--violet-9);
|
||||
color: var(--violet-1);
|
||||
}
|
||||
|
||||
.SelectLabel {
|
||||
padding: 0 25px;
|
||||
font-size: 12px;
|
||||
line-height: 25px;
|
||||
color: var(--mauve-11);
|
||||
}
|
||||
|
||||
.SelectSeparator {
|
||||
height: 1px;
|
||||
background-color: var(--violet-6);
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
.SelectItemIndicator {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 25px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.SelectScrollButton {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 25px;
|
||||
background-color: white;
|
||||
color: var(--violet-11);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.fontOptionContainer {
|
||||
border: 1px solid #d6d3d3;
|
||||
margin: 10px 5px 5px 5px;
|
||||
|
||||
}
|
||||
|
||||
.dropDownStyle {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width:766px) {
|
||||
|
||||
.showPages {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
min-width: 0rem !important;
|
||||
}
|
||||
|
||||
.signatureContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
|
||||
|
||||
.signerComponent {
|
||||
display: none;
|
||||
|
||||
}
|
||||
|
||||
.preBtn1 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.preBtn2 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
background-color: #ebebeb;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
#navbar {
|
||||
overflow: hidden;
|
||||
z-index: 49;
|
||||
}
|
||||
|
||||
/* Navbar links */
|
||||
#navbar a {
|
||||
float: left;
|
||||
display: block;
|
||||
color: #f2f2f2;
|
||||
text-align: center;
|
||||
padding: 14px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#navbar a.active {
|
||||
background-color: #4caf50;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/* Page content */
|
||||
.content {
|
||||
padding: 16px;
|
||||
}
|
||||
|
||||
/* The sticky class is added to the navbar
|
||||
with JS when it reaches its scroll position */
|
||||
.stickyHead {
|
||||
top: 50px;
|
||||
left: 0.9rem;
|
||||
}
|
||||
|
||||
.stickySignerHead {
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.stickyfooter {
|
||||
position: fixed;
|
||||
z-index: 99 !important;
|
||||
bottom: 0px;
|
||||
right: 0rem;
|
||||
}
|
||||
|
||||
/* Add some top padding to the page content
|
||||
to prevent sudden quick movement (as the
|
||||
navigation bar gets a new position at the top of the
|
||||
page (position:fixed and top:0) */
|
||||
.stickyHead+.content {
|
||||
padding-top: 60px;
|
||||
}
|
||||
|
||||
|
||||
.signLayoutContainer2 {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-around;
|
||||
margin-top: 5px;
|
||||
padding: 2px 5px 10px 5px;
|
||||
position: sticky;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.headerBtn {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.headerBtn2 {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.mobileHead {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width:487px) and (min-width:351px) {
|
||||
.signatureCanvas {
|
||||
|
||||
width: 300px;
|
||||
height: 120px;
|
||||
}
|
||||
|
||||
.penContainer {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
.uploadImgLogo {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.hidePdf {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobileHead {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@media screen and (max-width:350px) and (min-width:311px) {
|
||||
.signatureCanvas {
|
||||
|
||||
width: 280px;
|
||||
height: 112px;
|
||||
}
|
||||
|
||||
.penContainer {
|
||||
width: 280px;
|
||||
}
|
||||
|
||||
.hidePdf {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.signTab {
|
||||
|
||||
font-weight: 500 !important;
|
||||
|
||||
font-size: 10px !important;
|
||||
}
|
||||
|
||||
.uploadImgLogo {
|
||||
font-size: 25px;
|
||||
}
|
||||
|
||||
.uploadImg {
|
||||
|
||||
font-size: 10px !important;
|
||||
}
|
||||
|
||||
.mobileHead {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width:310px) {
|
||||
.signatureCanvas {
|
||||
|
||||
width: 230px;
|
||||
height: 92px;
|
||||
}
|
||||
|
||||
.penContainer {
|
||||
width: 230px;
|
||||
}
|
||||
|
||||
.hidePdf {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.signTab {
|
||||
|
||||
font-weight: 500 !important;
|
||||
|
||||
font-size: 10px !important;
|
||||
}
|
||||
|
||||
.uploadImgLogo {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.uploadImg {
|
||||
|
||||
font-size: 10px !important;
|
||||
}
|
||||
|
||||
.mobileHead {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.signature-backdrop {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
.signature-backdrop.fade.in {
|
||||
opacity: 0.5;
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
import("./bootstrap")
|
||||
@@ -1,7 +0,0 @@
|
||||
export const themeColor =()=>{
|
||||
return "#47a3ad";
|
||||
}
|
||||
|
||||
export const iconColor =()=>{
|
||||
return "#686968"
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
export const toDataUrl = (file) => {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onloadend = (e) => {
|
||||
resolve(e.target.result);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
import { useState } from "react";
|
||||
import axios from "axios";
|
||||
|
||||
export const useFileUpload = () => {
|
||||
const [parseBaseUrl] = useState(localStorage.getItem("baseUrl"));
|
||||
const [parseAppId] = useState(localStorage.getItem("parseAppId"));
|
||||
const [_fileupload, setFileUpload] = useState("");
|
||||
const [fileload, setfileload] = useState(false);
|
||||
const [percentage, setpercentage] = useState(0);
|
||||
|
||||
const onChange = (e) => {
|
||||
try {
|
||||
let files = e.target.files;
|
||||
if (typeof files[0] !== "undefined") {
|
||||
fileUpload(files[0]);
|
||||
} else {
|
||||
alert("Please select file.");
|
||||
return false;
|
||||
}
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
const fileUpload = async (file) => {
|
||||
setfileload(true);
|
||||
let image_url = parseBaseUrl.replace("/app", "");
|
||||
const url = `${image_url}image_upload`;
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
const config = {
|
||||
headers: {
|
||||
"content-type": "multipart/form-data",
|
||||
"X-Parse-Application-Id": parseAppId,
|
||||
},
|
||||
onUploadProgress: function (progressEvent) {
|
||||
var percentCompleted = Math.round(
|
||||
(progressEvent.loaded * 100) / progressEvent.total
|
||||
);
|
||||
setpercentage(percentCompleted);
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
await axios
|
||||
.post(url, formData, config)
|
||||
.then((res) => {
|
||||
if (res.data.status === "Error") {
|
||||
alert(res.data.message);
|
||||
}
|
||||
setFileUpload(res.data.imageUrl);
|
||||
setfileload(false);
|
||||
setpercentage(0);
|
||||
})
|
||||
.catch((err) => {
|
||||
alert(`${err.message}`);
|
||||
setfileload(false);
|
||||
setpercentage(0);
|
||||
});
|
||||
} catch (error) {
|
||||
alert(error.message);
|
||||
setfileload(false);
|
||||
setpercentage(0);
|
||||
}
|
||||
};
|
||||
|
||||
return { onChange, _fileupload, fileload, percentage, setFileUpload };
|
||||
};
|
||||