add SignDocument microfrontend
@@ -51,7 +51,6 @@
|
||||
"eslint": "^8.51.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"eslint-plugin-react": "^7.33.2",
|
||||
"husky": "^8.0.3",
|
||||
"lint-staged": "^15.0.1",
|
||||
"postcss": "^8.4.31",
|
||||
"prettier": "^2.8.0",
|
||||
@@ -10479,21 +10478,6 @@
|
||||
"node": ">=10.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/husky": {
|
||||
"version": "8.0.3",
|
||||
"resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz",
|
||||
"integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"husky": "lib/bin.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/typicode"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
|
||||
@@ -37,7 +37,7 @@ export default function reportJson(id) {
|
||||
textColor: "white",
|
||||
btnIcon: "fa fa-plus",
|
||||
redirectUrl:
|
||||
"remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/draftDocument"
|
||||
"remoteUrl=aHR0cDovL2xvY2FsaG9zdDozMDAwL21mYnVpbGQvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/draftDocument"
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
@@ -0,0 +1,70 @@
|
||||
# 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)
|
||||
@@ -0,0 +1,29 @@
|
||||
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"],
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "signmicroapp",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"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",
|
||||
"web-vitals": "^2.1.4"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "mf-cra start",
|
||||
"build": "CI=false && mf-cra build && mv build ../../apps/OpenSign/public/mfbuild",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
@@ -0,0 +1,81 @@
|
||||
<!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 App</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>
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"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"
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
# https://www.robotstxt.org/robotstxt.html
|
||||
User-agent: *
|
||||
Disallow:
|
||||
@@ -0,0 +1,51 @@
|
||||
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>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import "./certificate.css";
|
||||
|
||||
import { Page, Text, View, Document, StyleSheet } 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",
|
||||
},
|
||||
});
|
||||
|
||||
const generatedDate = () => {
|
||||
const newDate = new Date();
|
||||
const localExpireDate = newDate.toLocaleDateString("en-US", {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
var currentOffset = newDate.getTimezoneOffset();
|
||||
|
||||
var ISTOffset = 330; // IST offset UTC +5:30
|
||||
|
||||
var ISTTime = new Date(
|
||||
newDate.getTime() + (ISTOffset + currentOffset) * 60000
|
||||
);
|
||||
|
||||
// ISTTime now represents the time in IST coordinates
|
||||
|
||||
var hoursIST = ISTTime.getHours();
|
||||
var minutesIST = ISTTime.getMinutes();
|
||||
|
||||
return (
|
||||
<Text
|
||||
style={{
|
||||
textAlign: "right",
|
||||
color: "gray",
|
||||
fontSize: "10px",
|
||||
marginBottom: "30px",
|
||||
}}
|
||||
>
|
||||
Generated On {localExpireDate} {hoursIST}:{minutesIST} IST
|
||||
</Text>
|
||||
);
|
||||
};
|
||||
const changeCompletedDate = () => {
|
||||
const completedOn = pdfData[0].updatedAt;
|
||||
const newDate = new Date(completedOn);
|
||||
const localExpireDate = newDate.toLocaleDateString("en-US", {
|
||||
day: "numeric",
|
||||
month: "long",
|
||||
year: "numeric",
|
||||
});
|
||||
|
||||
var currentOffset = newDate.getTimezoneOffset();
|
||||
|
||||
var ISTOffset = 330; // IST offset UTC +5:30
|
||||
|
||||
var ISTTime = new Date(
|
||||
newDate.getTime() + (ISTOffset + currentOffset) * 60000
|
||||
);
|
||||
|
||||
// ISTTime now represents the time in IST coordinates
|
||||
|
||||
var hoursIST = ISTTime.getHours();
|
||||
var minutesIST = ISTTime.getMinutes();
|
||||
|
||||
return (
|
||||
<Text style={styles.textStyle2}>
|
||||
{localExpireDate} {hoursIST}:{minutesIST} IST
|
||||
</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}>
|
||||
{generatedDate()}
|
||||
<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}>__</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}>
|
||||
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;
|
||||
@@ -0,0 +1,9 @@
|
||||
.containerBox {
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.certificateBox {
|
||||
border: 1px solid rgb(177, 174, 174);
|
||||
padding: 20px;
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import axios from "axios";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import Loader from "./component/loader";
|
||||
import { 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 signObjId =
|
||||
rowLevel && rowLevel?.id
|
||||
? rowLevel.id
|
||||
: rowLevel?.objectId && rowLevel.objectId;
|
||||
useEffect(() => {
|
||||
if (signObjId) {
|
||||
getDocumentDetails();
|
||||
}
|
||||
}, []);
|
||||
|
||||
//get document details
|
||||
const getDocumentDetails = async () => {
|
||||
await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document?where={"objectId":"${signObjId}"}&include=ExtUserPtr,Signers`,
|
||||
{
|
||||
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", res);
|
||||
if (res[0] && res.length > 0) {
|
||||
setPdfDetails(res);
|
||||
const loadObj = {
|
||||
isLoad: false,
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
} else {
|
||||
alert("No data found!");
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("axois err ", err);
|
||||
});
|
||||
};
|
||||
|
||||
//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) {
|
||||
// window.location.hash = `/pdfRequestFiles`;
|
||||
|
||||
navigate(`${hostUrl}pdfRequestFiles`);
|
||||
}
|
||||
//checking document is completed and signer does not exist then navigate to recipientSignPdf file
|
||||
else if (data.IsCompleted && !checkSignerExist) {
|
||||
// window.location.hash = `/recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`;
|
||||
navigate(
|
||||
`${hostUrl}recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`
|
||||
);
|
||||
}
|
||||
//checking document is declined by someone then navigate to pdfRequestFiles file
|
||||
else if (isDecline) {
|
||||
// window.location.hash = `/pdfRequestFiles`;
|
||||
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
|
||||
) {
|
||||
// window.location.hash = `/placeHolderSign`;
|
||||
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;
|
||||
@@ -0,0 +1,608 @@
|
||||
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) => {
|
||||
// console.log("document", 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}recipientSignPdf/${data.objectId}/${data.ExtUserPtr.Phone}`
|
||||
);
|
||||
// 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, `${pdfName}_signed_by_opensign.qik.ai.pdf`);
|
||||
} else if (selectType === "Rename") {
|
||||
// console.log("rename")
|
||||
setRenameValue(data.Name);
|
||||
setRename(data.objectId);
|
||||
}
|
||||
};
|
||||
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;
|
||||
@@ -0,0 +1,530 @@
|
||||
@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;
|
||||
}
|
||||
|
||||
|
||||
.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 (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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,722 @@
|
||||
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";
|
||||
|
||||
function PdfFile() {
|
||||
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 [parentFolderName, setParentFolderName] = useState();
|
||||
// const [parentFolder, setParentFolder] = 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 senderUser =
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
) &&
|
||||
localStorage.getItem(
|
||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||
);
|
||||
const jsonSender = JSON.parse(senderUser);
|
||||
|
||||
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);
|
||||
//?where={"Type":"Folder" }&include=ExtUserPtr,Signers
|
||||
//?where={"$or":[{"Type":{"$exists":true}},{"Folder":{"$exists":false}}]}&include=ExtUserPtr,Signers
|
||||
// "CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${jsonSender.objectId}"}
|
||||
// where={"Folder":{"$exists":false} }&include=ExtUserPtr,Signers`,
|
||||
await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document?where={"Folder":{"$exists":false},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${
|
||||
jsonSender.objectId
|
||||
}"}}]}&include=ExtUserPtr,Signers`,
|
||||
{
|
||||
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("result", res);
|
||||
if (res[0] && res.length > 0) {
|
||||
setPdfData(res);
|
||||
}
|
||||
|
||||
const data = [
|
||||
{
|
||||
name: "OpenSignDrive™",
|
||||
objectId: "",
|
||||
},
|
||||
];
|
||||
setFolderName(data);
|
||||
const loadObj = {
|
||||
isLoad: false,
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
})
|
||||
.catch((err) => {
|
||||
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);
|
||||
//{"$inQuery":{"where":{"objectId":"${docId}"},"className":"${appName}_Document"}}
|
||||
//"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${jsonSender.objectId}"}
|
||||
await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document?where={"Folder":{"__type":"Pointer","className":"${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Document","objectId":"${docId}"},"$or":[{"CreatedBy":{"$exists":false}},{"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"${
|
||||
jsonSender.objectId
|
||||
}"}}]}&include=ExtUserPtr,Signers,Folder`,
|
||||
{
|
||||
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) {
|
||||
setPdfData(res);
|
||||
} else {
|
||||
setPdfData([]);
|
||||
}
|
||||
|
||||
const loadObj = {
|
||||
isLoad: false,
|
||||
};
|
||||
setIsLoading(loadObj);
|
||||
})
|
||||
.catch((err) => {
|
||||
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 {
|
||||
// console.log("go here1",data.objectId)
|
||||
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 isParentId = getParentObjId && getParentObjId.objectId;
|
||||
let data;
|
||||
if (isParentId) {
|
||||
data = {
|
||||
Name: newFolderName,
|
||||
Type: "Folder",
|
||||
Folder: {
|
||||
__type: "Pointer",
|
||||
className: `${localStorage.getItem("_appName")}_Document`,
|
||||
objectId: isParentId,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
data = {
|
||||
Name: newFolderName,
|
||||
Type: "Folder",
|
||||
};
|
||||
}
|
||||
|
||||
// console.log("data", data);
|
||||
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) => {
|
||||
console.log("axois err ", err);
|
||||
alert("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);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("click", closeMenuOnOutsideClick);
|
||||
|
||||
return () => {
|
||||
// Cleanup the event listener when the component unmounts
|
||||
document.removeEventListener("click", closeMenuOnOutsideClick);
|
||||
};
|
||||
}, [isShowSort]);
|
||||
|
||||
return (
|
||||
<div className="folderComponent ">
|
||||
<div>
|
||||
<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="menu-container"
|
||||
class={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 className="sort" onClick={() => getParentFolder()}>
|
||||
<i
|
||||
className="fa fa-plus-square"
|
||||
aria-hidden="true"
|
||||
style={{ fontSize: "25px", color: `${iconColor()}` }}
|
||||
></i>
|
||||
</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;
|
||||
@@ -0,0 +1,704 @@
|
||||
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";
|
||||
|
||||
// console.log("appName ", appName)
|
||||
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);
|
||||
// console.log(res.data.results[0].ImageURL);
|
||||
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);
|
||||
// setTimeout(() => setNameWarning(false), 1000);
|
||||
} 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={{
|
||||
// height: "100%",
|
||||
|
||||
width: "100%",
|
||||
paddingRight: "10px",
|
||||
|
||||
// maxHeight:"500px",
|
||||
}}
|
||||
>
|
||||
<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
|
||||
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;
|
||||
@@ -0,0 +1,58 @@
|
||||
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;
|
||||
@@ -0,0 +1,18 @@
|
||||
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;
|
||||
@@ -0,0 +1,18 @@
|
||||
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;
|
||||
@@ -0,0 +1,122 @@
|
||||
import React, { useEffect } from "react";
|
||||
import axios from "axios";
|
||||
|
||||
function DefaultSignature({
|
||||
themeColor,
|
||||
defaultSignImg,
|
||||
setShowAlreadySignDoc,
|
||||
setDefaultSignImg,
|
||||
userObjectId,
|
||||
setIsLoading,
|
||||
xyPostion,
|
||||
}) {
|
||||
useEffect(() => {
|
||||
getDefaultSignature(userObjectId);
|
||||
}, []);
|
||||
|
||||
//function for fetch default sigature added bu users
|
||||
const getDefaultSignature = async (userObjectId) => {
|
||||
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) => {
|
||||
// this.setState({ loading: false });
|
||||
console.log("axois err ", err);
|
||||
});
|
||||
};
|
||||
|
||||
const confirmToaddDefaultSign = () => {
|
||||
if (xyPostion.length > 0) {
|
||||
const alreadySign = {
|
||||
status: true,
|
||||
mssg: "Are you sure you want to sign at requested locations?",
|
||||
sure: true,
|
||||
};
|
||||
setShowAlreadySignDoc(alreadySign);
|
||||
} 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>You didn't add your default signature yet!</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default DefaultSignature;
|
||||
@@ -0,0 +1,385 @@
|
||||
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,
|
||||
signObjId,
|
||||
pdfName,
|
||||
sender,
|
||||
}) {
|
||||
const [emailCount, setEmailCount] = useState([]);
|
||||
const [emailValue, setEmailValue] = useState();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
//function for send email
|
||||
const sendEmail = async () => {
|
||||
setIsLoading(true);
|
||||
let sendMail, recipent;
|
||||
for (let i = 0; i < emailCount.length; i++) {
|
||||
// await axios
|
||||
// .get(
|
||||
// `${localStorage.getItem("baseUrl")}classes/${localStorage.getItem("_appName")}_Contactbook?where={"Email":"${emailCount[i]}"}`,
|
||||
// {
|
||||
// headers: {
|
||||
// "Content-Type": "application/json",
|
||||
// "X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||
// sessionToken: localStorage.getItem("accesstoken"),
|
||||
// },
|
||||
// }
|
||||
// )
|
||||
// .then((Listdata) => {
|
||||
// const json = Listdata.data;
|
||||
// if (json.results[0]) {
|
||||
// recipent = json.results[0];
|
||||
// }
|
||||
// })
|
||||
// .catch((err) => {
|
||||
// console.log("axois err ", err);
|
||||
// });
|
||||
try {
|
||||
console.log("recipients", recipent);
|
||||
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 serverUrl = localStorage.getItem("baseUrl");
|
||||
// const newServer = serverUrl.replaceAll("/", "%2F");
|
||||
|
||||
// const serverParams = `${newServer}&${localStorage.getItem(
|
||||
// "parseAppId"
|
||||
// )}&${localStorage.getItem("_appName")}`;
|
||||
// let pdfUrlWeb = `<span><a href=https://qik-ai-org.github.io/Sign-MicroappV2/#/login/${signObjId}/${recipent.Email}/${serverParams} style='cursor: pointer;'> ${pdfName}</a><span>`;
|
||||
const themeBGcolor = themeColor();
|
||||
let params = {
|
||||
pdfName: pdfName,
|
||||
url: pdfUrl,
|
||||
recipient: emailCount[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 Open Sign. 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 Open Sign here.</p></div></div></body></html>",
|
||||
//"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;padding-bottom: 20px;'> <div><img src="+imgPng +" height='50' style='padding: 20px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color: #47a3ad;'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " + recipent.Name + " has requested you to review and sign" +pdfName+"</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><span>Sender</span><span>" + recipent.Email + " </span></div><div style='display: flex; justify-content: center;margin-top: 10px;'><button style='padding: 8px 15px 8px 15px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;'>Sign here</button></div></div></div><div><p> This is an automated email from Open Sign. For any queries regarding this email, please contact the sender " + recipent.Email + " directly.If you think this email is inappropriate or spam, you may file a complaint with Open Sign here.</p> </div></div></body> </html>"
|
||||
};
|
||||
sendMail = await axios.post(url, params, { headers: headers });
|
||||
} catch (error) {
|
||||
console.log("error", error);
|
||||
setIsLoading(false);
|
||||
alert("Something went wrong!");
|
||||
}
|
||||
}
|
||||
|
||||
if (sendMail.data.result.status === "success") {
|
||||
setIsEmail(false);
|
||||
setSuccessEmail(true);
|
||||
setTimeout(() => {
|
||||
setSuccessEmail(false);
|
||||
}, 3000);
|
||||
setIsLoading(false);
|
||||
} else if (sendMail.data.result.status === "error") {
|
||||
setIsLoading(false);
|
||||
alert("Something went wrong!");
|
||||
} else {
|
||||
setIsLoading(false);
|
||||
alert("Something went wrong!");
|
||||
}
|
||||
};
|
||||
//function for remove email
|
||||
const removeChip = (index) => {
|
||||
const updateEmailCount = emailCount.filter((data, key) => key !== index);
|
||||
setEmailCount(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) {
|
||||
setEmailCount((prev) => [...prev, emailValue]);
|
||||
setEmailValue("");
|
||||
} else if (e === "add" && emailValue) {
|
||||
setEmailCount((prev) => [...prev, emailValue]);
|
||||
setEmailValue("");
|
||||
}
|
||||
};
|
||||
|
||||
// function for print signed pdf
|
||||
const handleToPrint = async (event) => {
|
||||
event.preventDefault();
|
||||
|
||||
const base64 = await getBase64FromUrl(pdfUrl);
|
||||
printModule({ printable: base64, type: "pdf", base64: true });
|
||||
|
||||
// window.print('https://nxgcreator.s3.ap-south-1.amazonaws.com/exported_file_32_2023-08-22T04%3A59%3A13.432Z.pdf',);
|
||||
};
|
||||
|
||||
//handle download signed pdf
|
||||
const handleDownloadPdf = () => {
|
||||
saveAs(pdfUrl, `${pdfName}_signed_by_opensign.qik.ai.pdf`);
|
||||
};
|
||||
|
||||
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" }}>Email Documents</span>
|
||||
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<div></div>
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
className="btn btn-primary btn-sm"
|
||||
>
|
||||
<i
|
||||
class="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>
|
||||
{emailCount.length > 0 ? (
|
||||
<>
|
||||
<div className="addEmail">
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
width: "450px",
|
||||
flexWrap: "wrap",
|
||||
}}
|
||||
>
|
||||
{emailCount.map((data, ind) => {
|
||||
return (
|
||||
<div className="emailChip" key={ind}>
|
||||
<span
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "13px",
|
||||
marginRight: "20px",
|
||||
}}
|
||||
>
|
||||
{data}
|
||||
</span>
|
||||
|
||||
<img
|
||||
alt="print img"
|
||||
onClick={() => removeChip(ind)}
|
||||
src={close}
|
||||
width={10}
|
||||
height={10}
|
||||
style={{ fontWeight: "600" }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{emailCount.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",
|
||||
}}
|
||||
class="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)}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
<button
|
||||
disabled={emailCount.length === 0 && true}
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white",
|
||||
}}
|
||||
type="button"
|
||||
className={emailCount.length === 0 ? "defaultBtn" : "finishBtn"}
|
||||
onClick={() => sendEmail()}
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</Modal.Footer>
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EmailComponent;
|
||||
@@ -0,0 +1,366 @@
|
||||
import React, { useState } 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,
|
||||
signerPos,
|
||||
signersdata,
|
||||
isSelectListId,
|
||||
setSignerObjId,
|
||||
setIsSelectId,
|
||||
setContractName,
|
||||
isSigners,
|
||||
}) {
|
||||
const signStyle = pdfUrl ? "disableSign" : "signatureBtn";
|
||||
|
||||
const isMobile = window.innerWidth < 712;
|
||||
const [isShowSort, setIsShowSort] = useState(false);
|
||||
const [selectedEmail, setSelectedEmail] = useState("");
|
||||
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>
|
||||
);
|
||||
}
|
||||
);
|
||||
console.log("sign",isSignYourself)
|
||||
return (
|
||||
<>
|
||||
<div 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>
|
||||
{isMobile && isSignYourself && (
|
||||
<div
|
||||
id="navbar"
|
||||
className="stickyfooter"
|
||||
style={{ width: window.innerWidth + "px" }}
|
||||
>
|
||||
{isSigners && (
|
||||
<div
|
||||
style={{
|
||||
background: "#887abf",
|
||||
padding: "10px 20px",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: "18px", fontWeight: "500" }}>
|
||||
Signer :
|
||||
</span>
|
||||
|
||||
<Select.Root onValueChange={(e) => console.log("value", e)}>
|
||||
<Select.Trigger
|
||||
onValueChange={(e) => console.log("value", e)}
|
||||
className="SelectTrigger"
|
||||
aria-label="Food"
|
||||
>
|
||||
<Select.Value placeholder="Select signer" />
|
||||
<Select.Icon className="SelectIcon">
|
||||
<i
|
||||
style={{
|
||||
marginTop: "5px",
|
||||
marginLeft: "5px",
|
||||
color: "#3b15d1",
|
||||
fontSize: "20px",
|
||||
}}
|
||||
class="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",
|
||||
}}
|
||||
class="fa fa-angle-down"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</Select.ScrollUpButton>
|
||||
<Select.Viewport className="SelectViewport">
|
||||
<Select.Group>
|
||||
{signersdata.Signers.map((obj, ind) => {
|
||||
return (
|
||||
<SelectItem key={ind} value={selectedEmail}>
|
||||
{" "}
|
||||
{obj.Email}
|
||||
</SelectItem>
|
||||
);
|
||||
})}
|
||||
</Select.Group>
|
||||
</Select.Viewport>
|
||||
<Select.ScrollDownButton className="SelectScrollButton">
|
||||
<i
|
||||
style={{
|
||||
marginTop: "5px",
|
||||
marginLeft: "5px",
|
||||
color: "#3b15d1",
|
||||
fontSize: "20px",
|
||||
}}
|
||||
class="fa fa-angle-down"
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
</Select.ScrollDownButton>
|
||||
</Select.Content>
|
||||
</Select.Portal>
|
||||
</Select.Root>
|
||||
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className="signLayoutContainer2"
|
||||
style={{ backgroundColor: themeColor() }}
|
||||
>
|
||||
<div
|
||||
onClick={() => 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>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default FieldsComponent;
|
||||
@@ -0,0 +1,660 @@
|
||||
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,
|
||||
isSigned,
|
||||
isCompleted,
|
||||
isShowHeader,
|
||||
decline,
|
||||
currentSigner,
|
||||
}) {
|
||||
const isMobile = window.innerWidth < 712;
|
||||
const navigate = useNavigate();
|
||||
|
||||
//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);
|
||||
|
||||
printModule({ printable: pdf, type: "pdf", base64: true });
|
||||
};
|
||||
|
||||
//handle download signed pdf
|
||||
const handleDownloadPdf = () => {
|
||||
const pdfName = pdfDetails[0] && pdfDetails[0].Name;
|
||||
|
||||
saveAs(pdfUrl, `${pdfName}_signed_by_opensign.qik.ai.pdf`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{ paddingBottom: "5px", paddingTop: "5px" }}
|
||||
className="mobileHead"
|
||||
>
|
||||
<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 && (
|
||||
// <Certificate
|
||||
// pdfData={completePdfData}
|
||||
// />
|
||||
<PDFDownloadLink
|
||||
document={<Certificate pdfData={pdfDetails} />}
|
||||
fileName={`completion certificate-${
|
||||
pdfDetails[0] && pdfDetails[0].Name
|
||||
}.pdf`}
|
||||
>
|
||||
{({ blob, url, loading, error }) =>
|
||||
loading ? (
|
||||
"Loading document..."
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="defaultBtn certificateBtn"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<i
|
||||
class="fa fa-certificate"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px",
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Certificate
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</PDFDownloadLink>
|
||||
)}
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
className="defaultBtn printBtn"
|
||||
>
|
||||
<i
|
||||
class="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>
|
||||
)
|
||||
) : pdfUrl || (documentStatus && documentStatus.isCompleted) ? (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
<PDFDownloadLink
|
||||
document={<Certificate pdfData={pdfDetails} />}
|
||||
fileName={`completion certificate-${
|
||||
pdfDetails[0] && pdfDetails[0].Name
|
||||
}.pdf`}
|
||||
>
|
||||
{({ blob, url, loading, error }) =>
|
||||
loading ? (
|
||||
"Loading document..."
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
className="defaultBtn certificateBtn"
|
||||
>
|
||||
<i
|
||||
class="fa fa-certificate"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px",
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Certificate
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</PDFDownloadLink>
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
type="button"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
className="defaultBtn printBtn"
|
||||
>
|
||||
<i
|
||||
class="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>
|
||||
</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
|
||||
data-tut="reactourFour"
|
||||
style={{
|
||||
background: !isMailSend ? "#188ae2" : "#d3edeb",
|
||||
}}
|
||||
onClick={() => {
|
||||
alertSendEmail();
|
||||
}}
|
||||
className="finishBtn sendHover"
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
) : isPdfRequestFiles ? (
|
||||
isSigned ? (
|
||||
<div style={{ display: "flex", flexDirection: "row" }}>
|
||||
{isCompleted.isCertificate && (
|
||||
<PDFDownloadLink
|
||||
document={<Certificate pdfData={pdfDetails} />}
|
||||
fileName={`completion certificate-${
|
||||
pdfDetails[0] && pdfDetails[0].Name
|
||||
}.pdf`}
|
||||
>
|
||||
{({ blob, url, loading, error }) =>
|
||||
loading ? (
|
||||
"Loading document..."
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
className="defaultBtn certificateBtn"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<i
|
||||
class="fa fa-certificate"
|
||||
style={{
|
||||
color: "white",
|
||||
fontSize: "15px",
|
||||
marginRight: "3px",
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Certificate
|
||||
</button>
|
||||
)
|
||||
}
|
||||
</PDFDownloadLink>
|
||||
)}
|
||||
<button
|
||||
onClick={handleToPrint}
|
||||
type="button"
|
||||
className="defaultBtn printBtn"
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<i
|
||||
class="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>
|
||||
)
|
||||
) : (
|
||||
<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>
|
||||
{isMobile && isShowHeader && (
|
||||
<div
|
||||
id="navbar"
|
||||
className="stickyHead"
|
||||
style={{ width: 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 ? (
|
||||
<DropdownMenu.Root>
|
||||
<DropdownMenu.Trigger asChild>
|
||||
<div
|
||||
// onClick={() => handleDownloadPdf()}
|
||||
style={{
|
||||
color: themeColor(),
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px",
|
||||
}}
|
||||
>
|
||||
<i class="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 class="fa fa-arrow-down" aria-hidden="true" style={{marginRight:"2px"}}></i>
|
||||
Download
|
||||
</div>
|
||||
</DropdownMenu.Item>
|
||||
<DropdownMenu.Item className="DropdownMenuItem">
|
||||
<PDFDownloadLink
|
||||
document={<Certificate pdfData={pdfDetails} />}
|
||||
fileName={`completion certificate-${
|
||||
pdfDetails[0] && pdfDetails[0].Name
|
||||
}.pdf`}
|
||||
>
|
||||
{({ blob, url, loading, error }) =>
|
||||
<>
|
||||
{console.log("error",error)}
|
||||
{loading ? (
|
||||
"Loading document..."
|
||||
) : (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
}}
|
||||
>
|
||||
<i
|
||||
class="fa fa-certificate"
|
||||
style={{
|
||||
fontSize: "15px",
|
||||
marginRight: "3px",
|
||||
}}
|
||||
aria-hidden="true"
|
||||
></i>
|
||||
Certificate
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
}
|
||||
</PDFDownloadLink>
|
||||
</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={() => {
|
||||
alertSendEmail();
|
||||
}}
|
||||
style={{
|
||||
color: themeColor(),
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px",
|
||||
}}
|
||||
>
|
||||
Send
|
||||
</div>
|
||||
):(
|
||||
<div
|
||||
onClick={() => {
|
||||
if (!pdfUrl) {
|
||||
embedImages();
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
color: themeColor(),
|
||||
border: "none",
|
||||
fontWeight: "650",
|
||||
fontSize: "16px",
|
||||
}}
|
||||
>
|
||||
Finish
|
||||
</div>
|
||||
)}
|
||||
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Header;
|
||||
@@ -0,0 +1,28 @@
|
||||
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
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from "react";
|
||||
import Modal from "react-bootstrap/Modal";
|
||||
import ModalHeader from "react-bootstrap/esm/ModalHeader";
|
||||
|
||||
function ModalComponent({ isShow, type }) {
|
||||
return (
|
||||
<Modal show={isShow}>
|
||||
<ModalHeader className="bg-danger" style={{ color: "white" }}>
|
||||
{type === "pdfFail" ? (
|
||||
<span>Failed to load pdf!</span>
|
||||
) : (
|
||||
<span>Document Expired!</span>
|
||||
)}
|
||||
</ModalHeader>
|
||||
|
||||
<Modal.Body>
|
||||
{type === "pdfFail" ? (
|
||||
<p>Something went wrong failed to load pdf file!</p>
|
||||
) : (
|
||||
<p>This Document is no longer available.</p>
|
||||
)}
|
||||
|
||||
</Modal.Body>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ModalComponent;
|
||||
@@ -0,0 +1,58 @@
|
||||
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;
|
||||
@@ -0,0 +1,96 @@
|
||||
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;
|
||||
@@ -0,0 +1,476 @@
|
||||
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 = () => {
|
||||
// console.log("isSign",isSignImg,image)
|
||||
|
||||
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",
|
||||
// background:'rgb(255, 255, 255)'
|
||||
}}
|
||||
className="signatureCanvas"
|
||||
>
|
||||
<img
|
||||
alt="stamp img"
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
background: "rgb(255, 255, 255)",
|
||||
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
|
||||
// style={{ display: "none" }}
|
||||
/>
|
||||
<i className="fas fa-cloud-upload-alt uploadImgLogo"></i>
|
||||
<div className="uploadImg">Upload</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
// position: "relative",
|
||||
|
||||
border: "1px solid black",
|
||||
marginBottom: 6,
|
||||
// justifyContent:"center"
|
||||
overflow: "hidden",
|
||||
}}
|
||||
className="signatureCanvas"
|
||||
>
|
||||
<img
|
||||
alt="print img"
|
||||
ref={imageRef}
|
||||
// alt="preview image"
|
||||
src={image.src}
|
||||
style={{
|
||||
//overflow:"hidden",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
) : (
|
||||
<>
|
||||
{/* {isSignImg ? (
|
||||
<div
|
||||
style={{
|
||||
position: "relative",
|
||||
|
||||
border: "2px solid #888",
|
||||
marginBottom: 6,
|
||||
}}
|
||||
className="signatureCanvas"
|
||||
>
|
||||
<img
|
||||
alt="preview image"
|
||||
src={isSignImg}
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
objectFit: "contain",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : ( */}
|
||||
<SignatureCanvas
|
||||
ref={canvasRef}
|
||||
penColor={penColor}
|
||||
canvasProps={{
|
||||
// width: "460px",
|
||||
// height: "184px",
|
||||
// width:"280px",
|
||||
// height:"112px",
|
||||
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}
|
||||
/>
|
||||
// </button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
<SaveBtn />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</Modal.Body>
|
||||
|
||||
{/* <Modal.Footer>
|
||||
{!isStamp && !isImageSelect && (
|
||||
<button
|
||||
style={{
|
||||
color: "black",
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
onClick={() => handleClear()}
|
||||
>
|
||||
Clear
|
||||
</button>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => {
|
||||
if (!image) {
|
||||
if (isDefaultSign) {
|
||||
onSaveSign(isDefaultSign);
|
||||
} else {
|
||||
onSaveSign();
|
||||
}
|
||||
|
||||
setPenColor("blue");
|
||||
} else {
|
||||
onSaveImage();
|
||||
}
|
||||
setIsSignPad(false);
|
||||
|
||||
setIsImageSelect(false);
|
||||
setIsDefaultSign(false);
|
||||
setImage();
|
||||
}}
|
||||
style={{
|
||||
background: themeColor(),
|
||||
color: "white",
|
||||
}}
|
||||
type="button"
|
||||
className="finishBtn"
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
</Modal.Footer> */}
|
||||
</Modal>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignPad;
|
||||
@@ -0,0 +1,68 @@
|
||||
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;
|
||||
@@ -0,0 +1,163 @@
|
||||
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;
|
||||
@@ -0,0 +1,310 @@
|
||||
import React, { useState } from "react";
|
||||
import signLogo from "../assests/mailLogo.png";
|
||||
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";
|
||||
// import { useHistory } from "react-router-dom/cjs/react-router-dom.min";
|
||||
function Login() {
|
||||
const { id, userMail, serverUrl,serverId } = useParams();
|
||||
let navigate = useNavigate();
|
||||
// const history = useHistory();
|
||||
|
||||
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();
|
||||
}, []);
|
||||
//https://qik-ai-org.github.io/Sign-MicroappV2/#/login/LqgGeZHd17/raktima.c@qik.ai/https:%2F%2Fserver3.qik.ai%2Fdefaultssty%2F&defaultssty&contracts
|
||||
// login/LqgGeZHd17/raktima.c@qik.ai/https:%2F%2Fserver3.qik.ai%2Fdefaultssty&defaultssty&contracts
|
||||
//function generate serverUrl and parseAppId from url and save it in local storage
|
||||
const handleServerUrl = () => {
|
||||
// console.log("params", serverUrl);
|
||||
//split url in array from '&'
|
||||
localStorage.clear();
|
||||
const checkSplit = serverUrl.split("&");
|
||||
const server = checkSplit[0];
|
||||
const parseId = checkSplit[1];
|
||||
const appName = checkSplit[2];
|
||||
// console.log("appName", appName);
|
||||
|
||||
const newServer = server.replaceAll("%2F", "/");
|
||||
localStorage.setItem("baseUrl", newServer);
|
||||
localStorage.setItem("parseAppId", parseId);
|
||||
localStorage.setItem("_appName", appName);
|
||||
setIsLoading(false);
|
||||
// console.log("checkSPlit", newServer, parseId, appName);
|
||||
};
|
||||
|
||||
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");
|
||||
// console.log("server",serverUrl)
|
||||
if (serverUrl && localStorage) {
|
||||
setLoading(true);
|
||||
e.preventDefault();
|
||||
setEmail(email);
|
||||
|
||||
try {
|
||||
// const { baseUrl, parseAppId, mobile } = this.state;
|
||||
let url = `${serverUrl}functions/SendOTPMailV1/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId,
|
||||
};
|
||||
let body = {
|
||||
email: email.toString(),
|
||||
// appId: {
|
||||
// __type: "Pointer",
|
||||
// className: "w_appinfo",
|
||||
// objectId: localStorage.getItem("_app_objectId"),
|
||||
// },
|
||||
};
|
||||
let Otp = await axios.post(url, body, { headers: headers });
|
||||
|
||||
if (Otp) {
|
||||
setLoading(false);
|
||||
setEnterOtp(true);
|
||||
}
|
||||
} catch (error) {
|
||||
// this.setState({ loading: false });
|
||||
}
|
||||
} 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 {
|
||||
// AuthLoginAs
|
||||
let url = `${serverUrl}functions/AuthLoginAsMail/`;
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
"X-Parse-Application-Id": parseId,
|
||||
};
|
||||
let body = {
|
||||
email: email,
|
||||
// email,
|
||||
otp: OTP,
|
||||
};
|
||||
let user = await axios.post(url, body, { headers: headers });
|
||||
// console.log("user", user.data.result);
|
||||
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("userEmail", email);
|
||||
localStorage.setItem("username", _user.name);
|
||||
// console.log("session token", _user.sessionToken);
|
||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||
|
||||
setLoading(false);
|
||||
//navigate user to on signature page
|
||||
// history.push(`/recipientSignPdf/${id}/${_user.phone}`);
|
||||
navigate(`/recipientSignPdf/${id}/${_user.phone}`);
|
||||
}
|
||||
} catch (error) {}
|
||||
} else {
|
||||
alert("Please Enter OTP!");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
{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",
|
||||
// box-shadow: 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 ? (
|
||||
<form>
|
||||
<div className="row">
|
||||
<div className="col-sm-6 KLO">
|
||||
<h2>Welcome Back !</h2>
|
||||
<span className="KNLO">
|
||||
Verification code is sent to your email
|
||||
</span>
|
||||
<div className="card card-box">
|
||||
<div className="card-body">
|
||||
<input
|
||||
type="email"
|
||||
className="form-control"
|
||||
name="mobile"
|
||||
value={email}
|
||||
disabled
|
||||
height={30}
|
||||
style={{ fontSize: "20px", fontWeight: "600" }}
|
||||
/>
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="col-md-4 col-sm-4"
|
||||
style={{
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
}}
|
||||
>
|
||||
{loading ? (
|
||||
<button
|
||||
className="btn btn-info loadinBtn "
|
||||
type="button"
|
||||
style={{ marginBottom: "4px", width: "210px" }}
|
||||
disabled
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
className="btn btn-sm otpButton"
|
||||
onClick={(e) => SendOtp(e)}
|
||||
style={{
|
||||
marginBottom: "4px",
|
||||
width: "210px",
|
||||
background: themeColor(),
|
||||
color: "white",
|
||||
fontWeight: "600",
|
||||
}}
|
||||
>
|
||||
Send OTP
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
) : (
|
||||
<form>
|
||||
<div className="row">
|
||||
<div className="col-sm-6 KLO">
|
||||
<h2>Welcome Back !</h2>
|
||||
<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="form-control"
|
||||
name="OTP"
|
||||
value={OTP}
|
||||
min="4"
|
||||
max="4"
|
||||
onChange={handleChange}
|
||||
/>
|
||||
|
||||
<br />
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="col-md-4 col-sm-4"
|
||||
style={{ textAlign: "center" }}
|
||||
>
|
||||
{loading ? (
|
||||
<button
|
||||
className="btn btn-info "
|
||||
type="button"
|
||||
style={{ marginBottom: "4px", width: "210px" }}
|
||||
disabled
|
||||
>
|
||||
<span
|
||||
className="spinner-border spinner-border-sm "
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
Loading...
|
||||
</button>
|
||||
) : (
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => VerifyOTP(e)}
|
||||
className="btn btn-info login-btn"
|
||||
>
|
||||
Verify
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
export default Login;
|
||||
@@ -0,0 +1,49 @@
|
||||
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";
|
||||
|
||||
// `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/:userPhone"
|
||||
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/: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 />} />
|
||||
</Routes>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default AppRoutes;
|
||||
|
After Width: | Height: | Size: 430 B |
|
After Width: | Height: | Size: 574 B |
|
After Width: | Height: | Size: 448 B |
|
After Width: | Height: | Size: 324 B |
|
After Width: | Height: | Size: 259 B |
|
After Width: | Height: | Size: 272 B |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 76 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 61 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
|
After Width: | Height: | Size: 234 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 208 B |
|
After Width: | Height: | Size: 569 B |
|
After Width: | Height: | Size: 804 B |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 561 B |
@@ -0,0 +1,7 @@
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom/client";
|
||||
import App from "./App";
|
||||
|
||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||
|
||||
root.render(<App />);
|
||||
@@ -0,0 +1,151 @@
|
||||
.react-tel-input .form-control {
|
||||
width: 100%;
|
||||
height: 45px;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.form-check-label {
|
||||
margin-left: 17px;
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
border-color: #ccc !important;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
.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%;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,723 @@
|
||||
/* html, body {margin: 0; height: 100%; overflow: hidden} */
|
||||
/* #04b565 */
|
||||
/* div {
|
||||
margin: 0px;
|
||||
font-family:system-ui;
|
||||
} */
|
||||
.signatureCanvas {
|
||||
border: 2px solid #888;
|
||||
background-color: rgb(255, 255, 255);
|
||||
width: 460px;
|
||||
height: 184px;
|
||||
}
|
||||
.penContainer{
|
||||
width: 460px;
|
||||
}
|
||||
|
||||
.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;
|
||||
/* transform: translate(); */
|
||||
|
||||
}
|
||||
|
||||
/* .signatureBtn:hover {
|
||||
background-color:#47a3ad;
|
||||
color: white;
|
||||
} */
|
||||
|
||||
.disableSign {
|
||||
border: none;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.18);
|
||||
margin-bottom: 10px;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
padding: 0px;
|
||||
justify-content: space-between;
|
||||
background: #d3edeb;
|
||||
transition-duration: 0.4s;
|
||||
cursor: pointer;
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.emailInput {
|
||||
padding: 10px;
|
||||
border: 1.5px solid gray;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
.emailInput:focus {
|
||||
outline: none;
|
||||
border: 1.5px solid #47a3ad;
|
||||
}
|
||||
|
||||
.addEmail {
|
||||
padding: "0px";
|
||||
border: 1.5px solid #47a3ad;
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
|
||||
}
|
||||
|
||||
.addEmail,
|
||||
.emailInput {
|
||||
|
||||
outline: none;
|
||||
}
|
||||
.addEmailInput{
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.emailChip {
|
||||
background-color: #47a3ad;
|
||||
margin: 4px;
|
||||
border-radius: 10px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.addEmailInput {
|
||||
padding: 10px;
|
||||
|
||||
border-radius: 4px;
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
|
||||
|
||||
}
|
||||
|
||||
.addEmailInput:focus {
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.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;
|
||||
}
|
||||
|
||||
.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;
|
||||
/* for Chrome, Safari, and Opera */
|
||||
}
|
||||
|
||||
.showScroll {
|
||||
height: 100%;
|
||||
overflow: scroll;
|
||||
|
||||
}
|
||||
|
||||
.showScroll::-webkit-scrollbar {
|
||||
display: none;
|
||||
/* for Chrome, Safari, and Opera */
|
||||
}
|
||||
|
||||
.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;
|
||||
/* max-height: 800px; */
|
||||
/* overflow: auto; */
|
||||
}
|
||||
|
||||
.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: #887abf;
|
||||
border: none;
|
||||
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: #887abf;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 25px;
|
||||
padding: 0 5px;
|
||||
position: relative;
|
||||
padding-left: 25px;
|
||||
user-select: none;
|
||||
outline: none;
|
||||
border: none;
|
||||
}
|
||||
.SelectTrigger {
|
||||
display: inline-flex;
|
||||
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;
|
||||
color: black
|
||||
|
||||
}
|
||||
option{
|
||||
overflow-y:scroll;
|
||||
}
|
||||
.SelectTrigger:hover {
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
.SelectTrigger: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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media screen and (max-width:767px) {
|
||||
|
||||
.showPages {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.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: 10;
|
||||
}
|
||||
|
||||
/* 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 {
|
||||
position: fixed;
|
||||
top: 50px;
|
||||
left: 0.9rem;
|
||||
|
||||
}
|
||||
|
||||
.stickyfooter {
|
||||
position: fixed;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
import("./bootstrap")
|
||||
@@ -0,0 +1,7 @@
|
||||
export const themeColor =()=>{
|
||||
return "#47a3ad";
|
||||
}
|
||||
|
||||
export const iconColor =()=>{
|
||||
return "#686968"
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
import axios from "axios";
|
||||
|
||||
export async function getBase64FromUrl(url) {
|
||||
const data = await fetch(url);
|
||||
const blob = await data.blob();
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
reader.onloadend = function () {
|
||||
const pdfBase = this.result;
|
||||
const removeBase64Prefix = "data:application/octet-stream;base64,";
|
||||
const suffixbase64 = pdfBase.replace(removeBase64Prefix, "");
|
||||
resolve(suffixbase64);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export async function getBase64FromIMG(url) {
|
||||
const data = await fetch(url);
|
||||
const blob = await data.blob();
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(blob);
|
||||
reader.onloadend = function () {
|
||||
const pdfBase = this.result;
|
||||
|
||||
resolve(pdfBase);
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
export function getHostUrl() {
|
||||
const hostUrl = window.location.href;
|
||||
/// const hostUrl = "https://contracts-defaultssty.qik.ai/#/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive";
|
||||
// const hostUrl = "https://contracts-defaultssty.qik.ai/#/"
|
||||
// const hostUrl = "https://lionfish-app-75ly7.ondigitalocean.app/mf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/legadrive"
|
||||
//const hostUrl = "https://app.opensignlabs.com/rpmf/remoteUrl=aHR0cHM6Ly9xaWstYWktb3JnLmdpdGh1Yi5pby9TaWduLU1pY3JvYXBwVjIvcmVtb3RlRW50cnkuanM=&moduleToLoad=AppRoutes&remoteName=signmicroapp/draftDocument";
|
||||
|
||||
if (hostUrl) {
|
||||
const urlSplit = hostUrl.split("/");
|
||||
const concatUrl = urlSplit[3] + "/" + urlSplit[4];
|
||||
|
||||
if (urlSplit) {
|
||||
const desireUrl = "/" + concatUrl;
|
||||
if (desireUrl) {
|
||||
return desireUrl + "/";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return "/";
|
||||
}
|
||||
}
|
||||
|
||||
//function for upload stamp or image
|
||||
export function onSaveImage(xyPostion, index, signKey, imgWH, image) {
|
||||
const updateFilter = xyPostion[index].pos.filter(
|
||||
(data, ind) =>
|
||||
data.key === signKey && data.Width && data.Height && data.SignUrl
|
||||
);
|
||||
|
||||
if (updateFilter.length > 0) {
|
||||
let newWidth, nweHeight;
|
||||
const aspectRatio = imgWH.width / imgWH.height;
|
||||
const getXYdata = xyPostion[index].pos;
|
||||
if (aspectRatio === 1) {
|
||||
newWidth = aspectRatio * 100;
|
||||
nweHeight = aspectRatio * 100;
|
||||
} else if (aspectRatio < 2) {
|
||||
newWidth = aspectRatio * 100;
|
||||
nweHeight = 100;
|
||||
} else if (aspectRatio > 2 && aspectRatio < 4) {
|
||||
newWidth = aspectRatio * 70;
|
||||
nweHeight = 70;
|
||||
} else if (aspectRatio > 4) {
|
||||
newWidth = aspectRatio * 40;
|
||||
nweHeight = 40;
|
||||
} else if (aspectRatio > 5) {
|
||||
newWidth = aspectRatio * 10;
|
||||
nweHeight = 10;
|
||||
}
|
||||
const getPosData = getXYdata;
|
||||
const addSign = getPosData.map((url, ind) => {
|
||||
if (url.key === signKey) {
|
||||
return {
|
||||
...url,
|
||||
Width: newWidth,
|
||||
Height: nweHeight,
|
||||
SignUrl: image.src,
|
||||
ImageType: image.imgType,
|
||||
};
|
||||
}
|
||||
return url;
|
||||
});
|
||||
|
||||
const newUpdateUrl = xyPostion.map((obj, ind) => {
|
||||
if (ind === index) {
|
||||
return { ...obj, pos: addSign };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
return newUpdateUrl;
|
||||
// setXyPostion(newUpdateUrl);
|
||||
} else {
|
||||
const getXYdata = xyPostion[index].pos;
|
||||
|
||||
const getPosData = getXYdata;
|
||||
|
||||
const aspectRatio = imgWH.width / imgWH.height;
|
||||
|
||||
let newWidth, newHeight;
|
||||
if (aspectRatio === 1) {
|
||||
newWidth = aspectRatio * 100;
|
||||
newHeight = aspectRatio * 100;
|
||||
} else if (aspectRatio < 2) {
|
||||
newWidth = aspectRatio * 100;
|
||||
newHeight = 100;
|
||||
} else if (aspectRatio > 2 && aspectRatio < 4) {
|
||||
newWidth = aspectRatio * 70;
|
||||
newHeight = 70;
|
||||
} else if (aspectRatio > 4) {
|
||||
newWidth = aspectRatio * 40;
|
||||
newHeight = 40;
|
||||
} else if (aspectRatio > 5) {
|
||||
newWidth = aspectRatio * 10;
|
||||
newHeight = 10;
|
||||
}
|
||||
|
||||
const addSign = getPosData.map((url, ind) => {
|
||||
if (url.key === signKey) {
|
||||
return {
|
||||
...url,
|
||||
Width: newWidth,
|
||||
Height: newHeight,
|
||||
SignUrl: image.src,
|
||||
ImageType: image.imgType,
|
||||
};
|
||||
}
|
||||
return url;
|
||||
});
|
||||
|
||||
const newUpdateUrl = xyPostion.map((obj, ind) => {
|
||||
if (ind === index) {
|
||||
return { ...obj, pos: addSign };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
return newUpdateUrl;
|
||||
// setXyPostion(newUpdateUrl);
|
||||
}
|
||||
}
|
||||
|
||||
//function for save button to save signature or image url
|
||||
export function onSaveSign(xyPostion, index, signKey, signatureImg) {
|
||||
const updateFilter = xyPostion[index].pos.filter(
|
||||
(data) => data.key === signKey && data.SignUrl
|
||||
);
|
||||
|
||||
if (updateFilter.length > 0) {
|
||||
const getXYdata = xyPostion[index].pos;
|
||||
// updateFilter[0].SignUrl = signatureImg;
|
||||
|
||||
const getPosData = getXYdata;
|
||||
const addSign = getPosData.map((url, ind) => {
|
||||
if (url.key === signKey) {
|
||||
return {
|
||||
...url,
|
||||
Width: 150,
|
||||
Height: 60,
|
||||
SignUrl: signatureImg,
|
||||
};
|
||||
}
|
||||
return url;
|
||||
});
|
||||
|
||||
const newUpdateUrl = xyPostion.map((obj, ind) => {
|
||||
if (ind === index) {
|
||||
return { ...obj, pos: addSign };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
return newUpdateUrl;
|
||||
} else {
|
||||
const getXYdata = xyPostion[index].pos;
|
||||
|
||||
const getPosData = getXYdata;
|
||||
|
||||
const addSign = getPosData.map((url, ind) => {
|
||||
if (url.key === signKey) {
|
||||
return { ...url, SignUrl: signatureImg, Width: 150, Height: 60 };
|
||||
}
|
||||
return url;
|
||||
});
|
||||
|
||||
const newUpdateUrl = xyPostion.map((obj, ind) => {
|
||||
if (ind === index) {
|
||||
return { ...obj, pos: addSign };
|
||||
}
|
||||
return obj;
|
||||
});
|
||||
return newUpdateUrl;
|
||||
}
|
||||
}
|
||||
|
||||
//function for getting contract_User details
|
||||
export const contractUsers = async (objectId) => {
|
||||
const result = await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Users?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${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;
|
||||
return res;
|
||||
})
|
||||
.catch((err) => {
|
||||
return "Error: Something went wrong!";
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
//function for getting contrscts_contactbook details
|
||||
export const contactBook = async (objectId) => {
|
||||
const result = await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}_Contactbook?where={"UserId": {"__type": "Pointer","className": "_User", "objectId":"${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;
|
||||
return res;
|
||||
})
|
||||
|
||||
.catch((err) => {
|
||||
return "Error: Something went wrong!";
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
export const contactBookName = async (userPhone, className) => {
|
||||
const result = await axios
|
||||
.get(
|
||||
`${localStorage.getItem("baseUrl")}classes/${localStorage.getItem(
|
||||
"_appName"
|
||||
)}${className}?where={"Phone":"${userPhone}"}`,
|
||||
{
|
||||
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;
|
||||
return json;
|
||||
})
|
||||
.catch((err) => {
|
||||
return "Error: Something went wrong!";
|
||||
});
|
||||
return result;
|
||||
};
|
||||
@@ -0,0 +1,10 @@
|
||||
export const toDataUrl = (file) => {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.readAsDataURL(file);
|
||||
reader.onloadend = (e) => {
|
||||
resolve(e.target.result);
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
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 };
|
||||
};
|
||||