mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-05 01:07:39 +02:00
Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
72401291f8 | ||
|
|
7b34314b9e | ||
|
|
b6f1cceeca | ||
|
|
c422cdac06 | ||
|
|
ab08d2615d | ||
|
|
2b0c7488d9 | ||
|
|
6927540741 | ||
|
|
1ceeee36ac |
@@ -3,11 +3,11 @@
|
|||||||
|
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
|
<meta name="description" content="The fastest way to sign PDFs & request signatures from others" />
|
||||||
<!-- <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> -->
|
<!-- <link rel="apple-touch-icon" href="/logo192.png" /> -->
|
||||||
|
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css"
|
||||||
@@ -17,5 +17,6 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root" style="touch-action:pan-x pan-y;"></div>
|
<div id="root" style="touch-action:pan-x pan-y;"></div>
|
||||||
|
<script type="module" src="/src/index.jsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Generated
+3382
-638
File diff suppressed because it is too large
Load Diff
+27
-14
@@ -4,7 +4,7 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@formkit/auto-animate": "^0.8.2",
|
"@formkit/auto-animate": "^0.8.2",
|
||||||
"@lottiefiles/dotlottie-react": "^0.13.4",
|
"@lottiefiles/dotlottie-react": "^0.13.5",
|
||||||
"@pdf-lib/fontkit": "^1.1.1",
|
"@pdf-lib/fontkit": "^1.1.1",
|
||||||
"@radix-ui/themes": "^3.1.6",
|
"@radix-ui/themes": "^3.1.6",
|
||||||
"@reduxjs/toolkit": "^2.7.0",
|
"@reduxjs/toolkit": "^2.7.0",
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
"date-fns-tz": "^3.2.0",
|
"date-fns-tz": "^3.2.0",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"i18next": "^23.16.8",
|
"i18next": "^23.16.8",
|
||||||
"i18next-browser-languagedetector": "^8.0.5",
|
"i18next-browser-languagedetector": "^8.1.0",
|
||||||
"i18next-http-backend": "^3.0.2",
|
"i18next-http-backend": "^3.0.2",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"jwt-decode": "^4.0.0",
|
"jwt-decode": "^4.0.0",
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
"react-quill-new": "^3.4.6",
|
"react-quill-new": "^3.4.6",
|
||||||
"react-redux": "^9.2.0",
|
"react-redux": "^9.2.0",
|
||||||
"react-rnd": "^10.5.2",
|
"react-rnd": "^10.5.2",
|
||||||
"react-router": "^7.5.2",
|
"react-router": "^7.5.3",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"react-scrollbars-custom": "^4.1.1",
|
"react-scrollbars-custom": "^4.1.1",
|
||||||
"react-select": "^5.10.1",
|
"react-select": "^5.10.1",
|
||||||
@@ -57,18 +57,20 @@
|
|||||||
"serve": "^14.2.4",
|
"serve": "^14.2.4",
|
||||||
"styled-components": "^5.3.0",
|
"styled-components": "^5.3.0",
|
||||||
"web-vitals": "^4.2.4",
|
"web-vitals": "^4.2.4",
|
||||||
"ws": "^8.18.1",
|
"ws": "^8.18.2",
|
||||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npm run version && react-scripts build",
|
"build": "npm run version && NODE_OPTIONS=\"--max-old-space-size=8192\" vite build",
|
||||||
"start-dev": "react-scripts start",
|
"start-dev": "vite",
|
||||||
|
"dev": "vite",
|
||||||
|
"preview": "vite preview",
|
||||||
"start": "serve -s build",
|
"start": "serve -s build",
|
||||||
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
|
"version": "curl -s https://api.github.com/repos/opensignlabs/opensign/releases/latest | grep '\"tag_name\":' | awk -F '\"' '{print $4}' > ./public/version.txt",
|
||||||
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
|
"version-win": "powershell -Command \"Invoke-RestMethod -Uri 'https://api.github.com/repos/opensignlabs/opensign/releases/latest' | Select-Object -ExpandProperty tag_name | Out-File -FilePath ./public/version.txt\"",
|
||||||
"build-win": "npm run version-win && react-scripts build",
|
"build-win": "npm run version-win && vite build",
|
||||||
"test": "react-scripts test",
|
"test": "vitest run",
|
||||||
"eject": "react-scripts eject",
|
"test:watch": "vitest",
|
||||||
"release": "standard-version",
|
"release": "standard-version",
|
||||||
"commit": "cz"
|
"commit": "cz"
|
||||||
},
|
},
|
||||||
@@ -96,10 +98,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.26.10",
|
"@babel/core": "^7.27.1",
|
||||||
"@babel/preset-env": "^7.26.9",
|
"@babel/preset-env": "^7.27.1",
|
||||||
"@babel/preset-react": "^7.26.3",
|
"@babel/preset-react": "^7.27.1",
|
||||||
"@babel/runtime-corejs2": "^7.27.0",
|
"@babel/runtime-corejs2": "^7.27.1",
|
||||||
|
"@testing-library/jest-dom": "^6.6.3",
|
||||||
|
"@testing-library/react": "^16.3.0",
|
||||||
|
"@testing-library/user-event": "^14.6.1",
|
||||||
|
"@types/react": "^18.3.21",
|
||||||
|
"@vitejs/plugin-react": "^4.4.1",
|
||||||
|
"@vitejs/plugin-react-swc": "^3.9.0",
|
||||||
"autoprefixer": "^10.4.21",
|
"autoprefixer": "^10.4.21",
|
||||||
"babel-loader": "^10.0.0",
|
"babel-loader": "^10.0.0",
|
||||||
"commitizen": "^4.3.1",
|
"commitizen": "^4.3.1",
|
||||||
@@ -109,15 +117,20 @@
|
|||||||
"dotenv": "^16.5.0",
|
"dotenv": "^16.5.0",
|
||||||
"dotenv-webpack": "^8.1.0",
|
"dotenv-webpack": "^8.1.0",
|
||||||
"eslint": "^8.57.1",
|
"eslint": "^8.57.1",
|
||||||
"eslint-plugin-prettier": "^5.2.6",
|
"eslint-plugin-prettier": "^5.4.0",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
"lint-staged": "^15.5.1",
|
"lint-staged": "^15.5.1",
|
||||||
"mini-css-extract-plugin": "^2.9.2",
|
"mini-css-extract-plugin": "^2.9.2",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
"prettier": "^3.5.3",
|
"prettier": "^3.5.3",
|
||||||
"pretty-quick": "^4.1.1",
|
"pretty-quick": "^4.1.1",
|
||||||
|
"rollup-plugin-node-polyfills": "^0.2.1",
|
||||||
"tailwindcss": "^3.4.17",
|
"tailwindcss": "^3.4.17",
|
||||||
"terser-webpack-plugin": "^5.3.14",
|
"terser-webpack-plugin": "^5.3.14",
|
||||||
|
"vite": "^6.3.5",
|
||||||
|
"vite-plugin-svgr": "^4.3.0",
|
||||||
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
|
"vitest": "^3.1.3",
|
||||||
"webpack-cli": "^5.1.4"
|
"webpack-cli": "^5.1.4"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
|||||||
Binary file not shown.
@@ -0,0 +1 @@
|
|||||||
|
import "@testing-library/jest-dom";
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect, lazy } from "react";
|
import React, { useState, useEffect, lazy } from "react";
|
||||||
import { Routes, Route, BrowserRouter } from "react-router";
|
import { Routes, Route, BrowserRouter } from "react-router";
|
||||||
import { pdfjs } from "react-pdf";
|
import { pdfjs } from "react-pdf";
|
||||||
import Login from "./pages/Login";
|
|
||||||
import Form from "./pages/Form";
|
import Form from "./pages/Form";
|
||||||
import Report from "./pages/Report";
|
import Report from "./pages/Report";
|
||||||
import Dashboard from "./pages/Dashboard";
|
import Dashboard from "./pages/Dashboard";
|
||||||
@@ -30,6 +29,7 @@ const ManageSign = lazy(() => import("./pages/Managesign"));
|
|||||||
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
|
const AddAdmin = lazy(() => import("./pages/AddAdmin"));
|
||||||
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
|
const UpdateExistUserAdmin = lazy(() => import("./pages/UpdateExistUserAdmin"));
|
||||||
const Preferences = lazy(() => import("./pages/Preferences"));
|
const Preferences = lazy(() => import("./pages/Preferences"));
|
||||||
|
const Login = lazy(() => import("./pages/Login"));
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
|
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/legacy/build/pdf.worker.min.mjs`;
|
||||||
const AppLoader = () => {
|
const AppLoader = () => {
|
||||||
@@ -67,7 +67,7 @@ function App() {
|
|||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route element={<ValidateRoute />}>
|
<Route element={<ValidateRoute />}>
|
||||||
<Route exact path="/" element={<Login />} />
|
<Route exact path="/" element={<LazyPage Page={Login} />} />
|
||||||
<Route
|
<Route
|
||||||
path="/addadmin"
|
path="/addadmin"
|
||||||
element={<LazyPage Page={AddAdmin} />}
|
element={<LazyPage Page={AddAdmin} />}
|
||||||
@@ -1,275 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import Title from "./Title";
|
|
||||||
import Loader from "../primitives/Loader";
|
|
||||||
import { copytoData, usertimezone } from "../constant/Utils";
|
|
||||||
import { emailRegex } from "../constant/const";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
function generatePassword(length) {
|
|
||||||
const characters =
|
|
||||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
|
||||||
let result = "";
|
|
||||||
const charactersLength = characters.length;
|
|
||||||
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
const AddUser = (props) => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [formdata, setFormdata] = useState({
|
|
||||||
name: "",
|
|
||||||
phone: "",
|
|
||||||
email: "",
|
|
||||||
team: "",
|
|
||||||
password: "",
|
|
||||||
role: ""
|
|
||||||
});
|
|
||||||
const [isFormLoader, setIsFormLoader] = useState(false);
|
|
||||||
const [teamList, setTeamList] = useState([]);
|
|
||||||
const role = ["OrgAdmin", "Editor", "User"];
|
|
||||||
useEffect(() => {
|
|
||||||
getTeamList();
|
|
||||||
// eslint-disable-next-line
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const getTeamList = async () => {
|
|
||||||
setFormdata((prev) => ({ ...prev, password: generatePassword(12) }));
|
|
||||||
const teamRes = await Parse.Cloud.run("getteams", { active: true });
|
|
||||||
if (teamRes.length > 0) {
|
|
||||||
const _teamRes = JSON.parse(JSON.stringify(teamRes));
|
|
||||||
setTeamList(_teamRes);
|
|
||||||
const allUserId =
|
|
||||||
_teamRes.find((x) => x.Name === "All Users")?.objectId || "";
|
|
||||||
setFormdata((prev) => ({ ...prev, team: allUserId }));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const checkUserExist = async () => {
|
|
||||||
try {
|
|
||||||
const res = await Parse.Cloud.run("getUserDetails", {
|
|
||||||
email: formdata.email
|
|
||||||
});
|
|
||||||
if (res) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
console.log("err", err);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Define a function to handle form submission
|
|
||||||
const handleSubmit = async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
if (!emailRegex.test(formdata.email)) {
|
|
||||||
alert("Please enter a valid email address.");
|
|
||||||
} else {
|
|
||||||
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
|
||||||
setIsFormLoader(true);
|
|
||||||
const res = await checkUserExist();
|
|
||||||
if (res) {
|
|
||||||
props.showAlert("danger", t("user-already-exist"));
|
|
||||||
setIsFormLoader(false);
|
|
||||||
} else {
|
|
||||||
if (localStorage.getItem("TenantId")) {
|
|
||||||
const timezone = usertimezone;
|
|
||||||
try {
|
|
||||||
const params = {
|
|
||||||
name: formdata.name,
|
|
||||||
email: formdata.email,
|
|
||||||
phone: formdata.phone,
|
|
||||||
password: formdata.password,
|
|
||||||
role: formdata.role,
|
|
||||||
team: formdata.team,
|
|
||||||
timezone: timezone,
|
|
||||||
tenantId: localStorage.getItem("TenantId"),
|
|
||||||
organization: {
|
|
||||||
objectId: localUser?.OrganizationId?.objectId,
|
|
||||||
company: localUser?.Company
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const res = await Parse.Cloud.run("adduser", params);
|
|
||||||
const parseData = JSON.parse(JSON.stringify(res));
|
|
||||||
console.log("parseData ", parseData);
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
|
||||||
if (props.handleUserData) {
|
|
||||||
if (formdata?.team) {
|
|
||||||
const team = teamList.find((x) => x.objectId === formdata.team);
|
|
||||||
parseData.TeamIds = parseData.TeamIds.map((y) =>
|
|
||||||
y.objectId === team.objectId ? team : y
|
|
||||||
);
|
|
||||||
}
|
|
||||||
props.handleUserData(parseData);
|
|
||||||
}
|
|
||||||
setIsFormLoader(false);
|
|
||||||
setFormdata({
|
|
||||||
name: "",
|
|
||||||
email: "",
|
|
||||||
phone: "",
|
|
||||||
team: "",
|
|
||||||
role: ""
|
|
||||||
});
|
|
||||||
props.showAlert("success", t("user-created-successfully"));
|
|
||||||
} catch (err) {
|
|
||||||
console.log("err", err);
|
|
||||||
setIsFormLoader(false);
|
|
||||||
props.showAlert("danger", t("something-went-wrong-mssg"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
props.showAlert("danger", t("something-went-wrong-mssg"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Define a function to handle the "add yourself" checkbox
|
|
||||||
const handleReset = () => {
|
|
||||||
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
|
|
||||||
if (props.closePopup) {
|
|
||||||
props.closePopup();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleChange = (event) => {
|
|
||||||
let { name, value } = event.target;
|
|
||||||
if (name === "email") {
|
|
||||||
value = value?.toLowerCase()?.replace(/\s/g, "");
|
|
||||||
}
|
|
||||||
setFormdata((prev) => ({ ...prev, [name]: value }));
|
|
||||||
};
|
|
||||||
|
|
||||||
const copytoclipboard = (text) => {
|
|
||||||
copytoData(text);
|
|
||||||
props.showAlert("success", t("copied"));
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="shadow-md rounded-box my-[1px] p-3 bg-base-100 relative">
|
|
||||||
<Title title={t("add-user")} />
|
|
||||||
{isFormLoader && (
|
|
||||||
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<div className="w-full mx-auto">
|
|
||||||
<form onSubmit={handleSubmit}>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="name"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("name")}
|
|
||||||
<span className="text-[red] text-[13px]"> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="name"
|
|
||||||
value={formdata.name}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
|
||||||
required
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="email"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("email")}
|
|
||||||
<span className="text-[red] text-[13px]"> *</span>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="email"
|
|
||||||
name="email"
|
|
||||||
value={formdata.email}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
required
|
|
||||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label className="block text-xs text-gray-700 font-semibold">
|
|
||||||
{t("password")}
|
|
||||||
</label>
|
|
||||||
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
|
|
||||||
<div className="break-all">{formdata?.password}</div>
|
|
||||||
<i
|
|
||||||
onClick={() => copytoclipboard(formdata?.password)}
|
|
||||||
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
|
|
||||||
></i>
|
|
||||||
</div>
|
|
||||||
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
|
|
||||||
{t("password-generateed")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="phone"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("phone")}
|
|
||||||
{/* <span className="text-[red] text-[13px]"> *</span> */}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="phone"
|
|
||||||
placeholder={t("phone-optional")}
|
|
||||||
value={formdata.phone}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mb-3">
|
|
||||||
<label
|
|
||||||
htmlFor="phone"
|
|
||||||
className="block text-xs text-gray-700 font-semibold"
|
|
||||||
>
|
|
||||||
{t("Role")}
|
|
||||||
<span className="text-[red] text-[13px]"> *</span>
|
|
||||||
</label>
|
|
||||||
<select
|
|
||||||
value={formdata.role}
|
|
||||||
onChange={(e) => handleChange(e)}
|
|
||||||
name="role"
|
|
||||||
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
onInvalid={(e) => e.target.setCustomValidity(t("input-required"))}
|
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
|
||||||
required
|
|
||||||
>
|
|
||||||
<option defaultValue={""} value={""}>
|
|
||||||
{t("Select")}
|
|
||||||
</option>
|
|
||||||
{role.length > 0 &&
|
|
||||||
role.map((x) => (
|
|
||||||
<option key={x} value={x}>
|
|
||||||
{x}
|
|
||||||
</option>
|
|
||||||
))}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
|
||||||
<button type="submit" className="op-btn op-btn-primary">
|
|
||||||
{t("submit")}
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
type="button"
|
|
||||||
onClick={() => handleReset()}
|
|
||||||
className="op-btn op-btn-secondary"
|
|
||||||
>
|
|
||||||
{t("cancel")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AddUser;
|
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Parse from "parse";
|
||||||
|
import Title from "./Title";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
import {
|
||||||
|
copytoData,
|
||||||
|
usertimezone
|
||||||
|
} from "../constant/Utils";
|
||||||
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
|
import {
|
||||||
|
useTranslation
|
||||||
|
} from "react-i18next";
|
||||||
|
function generatePassword(length) {
|
||||||
|
const characters =
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
|
let result = "";
|
||||||
|
const charactersLength = characters.length;
|
||||||
|
|
||||||
|
for (let i = 0; i < length; i++) {
|
||||||
|
result += characters.charAt(Math.floor(Math.random() * charactersLength));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AddUser = (props) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [formdata, setFormdata] = useState({
|
||||||
|
name: "",
|
||||||
|
phone: "",
|
||||||
|
email: "",
|
||||||
|
team: "",
|
||||||
|
password: "",
|
||||||
|
role: ""
|
||||||
|
});
|
||||||
|
const [isFormLoader, setIsFormLoader] = useState(false);
|
||||||
|
const [teamList, setTeamList] = useState([]);
|
||||||
|
const role = ["OrgAdmin", "Editor", "User"];
|
||||||
|
useEffect(() => {
|
||||||
|
getTeamList();
|
||||||
|
// eslint-disable-next-line
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const getTeamList = async () => {
|
||||||
|
setFormdata((prev) => ({ ...prev, password: generatePassword(12) }));
|
||||||
|
const teamRes = await Parse.Cloud.run("getteams", { active: true });
|
||||||
|
if (teamRes.length > 0) {
|
||||||
|
const _teamRes = JSON.parse(JSON.stringify(teamRes));
|
||||||
|
setTeamList(_teamRes);
|
||||||
|
const allUserId =
|
||||||
|
_teamRes.find((x) => x.Name === "All Users")?.objectId || "";
|
||||||
|
setFormdata((prev) => ({ ...prev, team: allUserId }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const checkUserExist = async () => {
|
||||||
|
try {
|
||||||
|
const res = await Parse.Cloud.run("getUserDetails", {
|
||||||
|
email: formdata.email
|
||||||
|
});
|
||||||
|
if (res) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err", err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Define a function to handle form submission
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
if (!emailRegex.test(formdata.email)) {
|
||||||
|
alert("Please enter a valid email address.");
|
||||||
|
} else {
|
||||||
|
const localUser = JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
|
setIsFormLoader(true);
|
||||||
|
const res = await checkUserExist();
|
||||||
|
if (res) {
|
||||||
|
props.showAlert("danger", t("user-already-exist"));
|
||||||
|
setIsFormLoader(false);
|
||||||
|
} else {
|
||||||
|
if (localStorage.getItem("TenantId")) {
|
||||||
|
const timezone = usertimezone;
|
||||||
|
try {
|
||||||
|
const params = {
|
||||||
|
name: formdata.name,
|
||||||
|
email: formdata.email,
|
||||||
|
phone: formdata.phone,
|
||||||
|
password: formdata.password,
|
||||||
|
role: formdata.role,
|
||||||
|
team: formdata.team,
|
||||||
|
timezone: timezone,
|
||||||
|
tenantId: localStorage.getItem("TenantId"),
|
||||||
|
organization: {
|
||||||
|
objectId: localUser?.OrganizationId?.objectId,
|
||||||
|
company: localUser?.Company
|
||||||
|
},
|
||||||
|
};
|
||||||
|
const res = await Parse.Cloud.run("adduser", params);
|
||||||
|
const parseData = JSON.parse(JSON.stringify(res));
|
||||||
|
console.log("parseData ", parseData);
|
||||||
|
if (props.closePopup) {
|
||||||
|
props.closePopup();
|
||||||
|
}
|
||||||
|
if (props.handleUserData) {
|
||||||
|
if (formdata?.team) {
|
||||||
|
const team = teamList.find((x) => x.objectId === formdata.team);
|
||||||
|
parseData.TeamIds = parseData.TeamIds.map((y) =>
|
||||||
|
y.objectId === team.objectId ? team : y
|
||||||
|
);
|
||||||
|
}
|
||||||
|
props.handleUserData(parseData);
|
||||||
|
}
|
||||||
|
setIsFormLoader(false);
|
||||||
|
setFormdata({
|
||||||
|
name: "",
|
||||||
|
email: "",
|
||||||
|
phone: "",
|
||||||
|
team: "",
|
||||||
|
role: ""
|
||||||
|
});
|
||||||
|
props.showAlert("success", t("user-created-successfully"));
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err", err);
|
||||||
|
setIsFormLoader(false);
|
||||||
|
props.showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props.showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Define a function to handle the "add yourself" checkbox
|
||||||
|
const handleReset = () => {
|
||||||
|
setFormdata({ name: "", email: "", phone: "", team: "", role: "" });
|
||||||
|
if (props.closePopup) {
|
||||||
|
props.closePopup();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleChange = (event) => {
|
||||||
|
let { name, value } = event.target;
|
||||||
|
if (name === "email") {
|
||||||
|
value = value?.toLowerCase()?.replace(/\s/g, "");
|
||||||
|
}
|
||||||
|
setFormdata((prev) => ({ ...prev, [name]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const copytoclipboard = (text) => {
|
||||||
|
copytoData(text);
|
||||||
|
props.showAlert("success", t("copied"));
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="shadow-md rounded-box my-[1px] p-3 bg-base-100 relative">
|
||||||
|
<Title title={t("add-user")} />
|
||||||
|
{isFormLoader && (
|
||||||
|
<div className="absolute w-full h-full inset-0 flex justify-center items-center bg-base-content/30 z-50">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className="w-full mx-auto">
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="name"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("name")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="name"
|
||||||
|
value={formdata.name}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
required
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="email"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("email")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="email"
|
||||||
|
name="email"
|
||||||
|
value={formdata.email}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
required
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label className="block text-xs text-gray-700 font-semibold">
|
||||||
|
{t("password")}
|
||||||
|
</label>
|
||||||
|
<div className="flex justify-between items-center op-input op-input-bordered op-input-sm text-base-content w-full h-full text-[13px]">
|
||||||
|
<div className="break-all">{formdata?.password}</div>
|
||||||
|
<i
|
||||||
|
onClick={() => copytoclipboard(formdata?.password)}
|
||||||
|
className="fa-light fa-copy rounded-full hover:bg-base-300 p-[8px] cursor-pointer "
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
<div className="text-[12px] ml-2 mb-0 text-[red] select-none">
|
||||||
|
{t("password-generateed")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="phone"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("phone")}
|
||||||
|
{/* <span className="text-[red] text-[13px]"> *</span> */}
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="phone"
|
||||||
|
placeholder={t("phone-optional")}
|
||||||
|
value={formdata.phone}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="mb-3">
|
||||||
|
<label
|
||||||
|
htmlFor="phone"
|
||||||
|
className="block text-xs text-gray-700 font-semibold"
|
||||||
|
>
|
||||||
|
{t("Role")}
|
||||||
|
<span className="text-[red] text-[13px]"> *</span>
|
||||||
|
</label>
|
||||||
|
<select
|
||||||
|
value={formdata.role}
|
||||||
|
onChange={(e) => handleChange(e)}
|
||||||
|
name="role"
|
||||||
|
className="op-select op-select-bordered op-select-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(t("input-required"))
|
||||||
|
}
|
||||||
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option defaultValue={""} value={""}>
|
||||||
|
{t("Select")}
|
||||||
|
</option>
|
||||||
|
{role.length > 0 &&
|
||||||
|
role.map((x) => (
|
||||||
|
<option key={x} value={x}>
|
||||||
|
{x}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center mt-3 gap-2 text-white">
|
||||||
|
<button type="submit" className="op-btn op-btn-primary">
|
||||||
|
{t("submit")}
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
type="button"
|
||||||
|
onClick={() => handleReset()}
|
||||||
|
className="op-btn op-btn-secondary"
|
||||||
|
>
|
||||||
|
{t("cancel")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default AddUser;
|
||||||
+80
-77
@@ -3,7 +3,9 @@ import axios from "axios";
|
|||||||
import SuggestionInput from "./shared/fields/SuggestionInput";
|
import SuggestionInput from "./shared/fields/SuggestionInput";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { emailRegex } from "../constant/const";
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
const BulkSendUi = (props) => {
|
const BulkSendUi = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [forms, setForms] = useState([]);
|
const [forms, setForms] = useState([]);
|
||||||
@@ -20,15 +22,15 @@ const BulkSendUi = (props) => {
|
|||||||
|
|
||||||
//function to check atleast one signature field exist
|
//function to check atleast one signature field exist
|
||||||
const signatureExist = async () => {
|
const signatureExist = async () => {
|
||||||
setIsDisableBulkSend(false);
|
setIsDisableBulkSend(false);
|
||||||
const getPlaceholder = props?.Placeholders;
|
const getPlaceholder = props?.Placeholders;
|
||||||
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
const checkIsSignatureExistt = getPlaceholder?.every((placeholderObj) =>
|
||||||
placeholderObj?.placeHolder?.some((holder) =>
|
placeholderObj?.placeHolder?.some((holder) =>
|
||||||
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
holder?.pos?.some((posItem) => posItem?.type === "signature")
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
setIsSignatureExist(checkIsSignatureExistt);
|
setIsSignatureExist(checkIsSignatureExistt);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
};
|
};
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (scrollOnNextUpdate && formRef.current) {
|
if (scrollOnNextUpdate && formRef.current) {
|
||||||
@@ -72,6 +74,7 @@ const BulkSendUi = (props) => {
|
|||||||
setForms(newForms);
|
setForms(newForms);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleRemoveForm = (index) => {
|
const handleRemoveForm = (index) => {
|
||||||
const updatedForms = forms.filter((_, i) => i !== index);
|
const updatedForms = forms.filter((_, i) => i !== index);
|
||||||
setForms(updatedForms);
|
setForms(updatedForms);
|
||||||
@@ -92,83 +95,82 @@ const BulkSendUi = (props) => {
|
|||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
setIsSubmit(true);
|
setIsSubmit(true);
|
||||||
if (validateEmails(forms)) {
|
if (validateEmails(forms)) {
|
||||||
// Create a copy of Placeholders array from props.item
|
// Create a copy of Placeholders array from props.item
|
||||||
let Placeholders = [...props.Placeholders];
|
let Placeholders = [...props.Placeholders];
|
||||||
// Initialize an empty array to store updated documents
|
// Initialize an empty array to store updated documents
|
||||||
let Documents = [];
|
let Documents = [];
|
||||||
// Loop through each form
|
// Loop through each form
|
||||||
forms.forEach((form) => {
|
forms.forEach((form) => {
|
||||||
//checking if user enter email which already exist as a signer then add user in a signers array
|
//checking if user enter email which already exist as a signer then add user in a signers array
|
||||||
let existSigner = [];
|
let existSigner = [];
|
||||||
form.fields.map((data) => {
|
form.fields.map((data) => {
|
||||||
if (data.signer) {
|
if (data.signer) {
|
||||||
existSigner.push(data.signer);
|
existSigner.push(data.signer);
|
||||||
}
|
|
||||||
});
|
|
||||||
// Map through the copied Placeholders array to update email values
|
|
||||||
const updatedPlaceholders = Placeholders.map((placeholder) => {
|
|
||||||
// Find the field in the current form that matches the placeholder Id
|
|
||||||
const field = form.fields.find(
|
|
||||||
(element) => parseInt(element.fieldId) === placeholder.Id
|
|
||||||
);
|
|
||||||
// If a matching field is found, update the email value in the placeholder
|
|
||||||
const signer = field?.signer?.objectId ? field.signer : "";
|
|
||||||
if (field) {
|
|
||||||
if (signer) {
|
|
||||||
return {
|
|
||||||
...placeholder,
|
|
||||||
signerObjId: field?.signer?.objectId || "",
|
|
||||||
signerPtr: signer
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
...placeholder,
|
|
||||||
email: field.email,
|
|
||||||
signerObjId: field?.signer?.objectId || "",
|
|
||||||
signerPtr: signer
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
// If no matching field is found, keep the placeholder as is
|
// Map through the copied Placeholders array to update email values
|
||||||
return placeholder;
|
const updatedPlaceholders = Placeholders.map((placeholder) => {
|
||||||
});
|
// Find the field in the current form that matches the placeholder Id
|
||||||
|
const field = form.fields.find(
|
||||||
|
(element) => parseInt(element.fieldId) === placeholder.Id
|
||||||
|
);
|
||||||
|
// If a matching field is found, update the email value in the placeholder
|
||||||
|
const signer = field?.signer?.objectId ? field.signer : "";
|
||||||
|
if (field) {
|
||||||
|
if (signer) {
|
||||||
|
return {
|
||||||
|
...placeholder,
|
||||||
|
signerObjId: field?.signer?.objectId || "",
|
||||||
|
signerPtr: signer
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
...placeholder,
|
||||||
|
email: field.email,
|
||||||
|
signerObjId: field?.signer?.objectId || "",
|
||||||
|
signerPtr: signer
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no matching field is found, keep the placeholder as is
|
||||||
|
return placeholder;
|
||||||
|
});
|
||||||
|
|
||||||
// Push a new document object with updated Placeholders into the Documents array
|
// Push a new document object with updated Placeholders into the Documents array
|
||||||
if (existSigner?.length > 0) {
|
if (existSigner?.length > 0) {
|
||||||
Documents.push({
|
Documents.push({
|
||||||
...props.item,
|
...props.item,
|
||||||
Placeholders: updatedPlaceholders,
|
Placeholders: updatedPlaceholders,
|
||||||
Signers: props.item.Signers
|
Signers: props.item.Signers
|
||||||
? [...props.item.Signers, ...existSigner]
|
? [...props.item.Signers, ...existSigner]
|
||||||
: [...existSigner]
|
: [...existSigner]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
Documents.push({
|
Documents.push({
|
||||||
...props.item,
|
...props.item,
|
||||||
Placeholders: updatedPlaceholders,
|
Placeholders: updatedPlaceholders,
|
||||||
SignatureType: props.signatureType
|
SignatureType: props.signatureType
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
await batchQuery(Documents);
|
await batchQuery(Documents);
|
||||||
} else {
|
} else {
|
||||||
setIsSubmit(false);
|
setIsSubmit(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const batchQuery = async (Documents) => {
|
const batchQuery = async (Documents) => {
|
||||||
const token = {
|
const token =
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||||
};
|
|
||||||
const functionsUrl = `${localStorage.getItem(
|
const functionsUrl = `${localStorage.getItem(
|
||||||
"baseUrl"
|
"baseUrl"
|
||||||
)}functions/batchdocuments`;
|
)}functions/batchdocuments`;
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
...token
|
...token,
|
||||||
};
|
};
|
||||||
const params = { Documents: JSON.stringify(Documents) };
|
const params = { Documents: JSON.stringify(Documents) };
|
||||||
try {
|
try {
|
||||||
@@ -275,7 +277,8 @@ const BulkSendUi = (props) => {
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<></>
|
<>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -32,14 +32,15 @@ const Header = ({ showSidebar, setIsMenu, isConsole }) => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
async function initializeHead() {
|
async function initializeHead() {
|
||||||
const applogo = await getAppLogo();
|
const applogo = await getAppLogo();
|
||||||
if (applogo?.logo) {
|
if (applogo?.logo) {
|
||||||
setAppLogo(applogo?.logo);
|
setAppLogo(applogo?.logo);
|
||||||
} else {
|
} else {
|
||||||
const logo = localStorage.getItem("appLogo") || appInfo.applogo;
|
const logo = localStorage.getItem("appLogo") || appInfo.applogo;
|
||||||
setAppLogo(logo);
|
setAppLogo(logo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeDropdown = async () => {
|
const closeDropdown = async () => {
|
||||||
@@ -152,15 +153,15 @@ const Header = ({ showSidebar, setIsMenu, isConsole }) => {
|
|||||||
>
|
>
|
||||||
{!isConsole && (
|
{!isConsole && (
|
||||||
<>
|
<>
|
||||||
<li
|
<li
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
openInNewTab("https://docs.opensignlabs.com")
|
openInNewTab("https://docs.opensignlabs.com")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
<i className="fa-light fa-book"></i> {t("docs")}
|
<i className="fa-light fa-book"></i> {t("docs")}
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
<li
|
<li
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsOpen(false);
|
setIsOpen(false);
|
||||||
+21
-6
@@ -1,4 +1,7 @@
|
|||||||
import React, { useState, useRef } from "react";
|
import React, {
|
||||||
|
useState,
|
||||||
|
useRef,
|
||||||
|
} from "react";
|
||||||
import {
|
import {
|
||||||
base64ToArrayBuffer,
|
base64ToArrayBuffer,
|
||||||
convertBase64ToFile,
|
convertBase64ToFile,
|
||||||
@@ -24,9 +27,10 @@ const EditTemplate = ({
|
|||||||
template,
|
template,
|
||||||
onSuccess,
|
onSuccess,
|
||||||
setPdfArrayBuffer,
|
setPdfArrayBuffer,
|
||||||
setPdfBase64Url
|
setPdfBase64Url,
|
||||||
}) => {
|
}) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const inputFileRef = useRef(null);
|
const inputFileRef = useRef(null);
|
||||||
const [formData, setFormData] = useState({
|
const [formData, setFormData] = useState({
|
||||||
@@ -165,7 +169,10 @@ const EditTemplate = ({
|
|||||||
}
|
}
|
||||||
let pdfUrl;
|
let pdfUrl;
|
||||||
if (uploadPdf?.base64) {
|
if (uploadPdf?.base64) {
|
||||||
pdfUrl = await convertBase64ToFile(uploadPdf.name, uploadPdf.base64);
|
pdfUrl = await convertBase64ToFile(
|
||||||
|
uploadPdf.name,
|
||||||
|
uploadPdf.base64,
|
||||||
|
);
|
||||||
setUploadPdf((prev) => ({ ...prev, url: pdfUrl }));
|
setUploadPdf((prev) => ({ ...prev, url: pdfUrl }));
|
||||||
const pdfBuffer = base64ToArrayBuffer(uploadPdf.base64);
|
const pdfBuffer = base64ToArrayBuffer(uploadPdf.base64);
|
||||||
setPdfArrayBuffer && setPdfArrayBuffer(pdfBuffer);
|
setPdfArrayBuffer && setPdfArrayBuffer(pdfBuffer);
|
||||||
@@ -447,7 +454,11 @@ const EditTemplate = ({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-col md:flex-row md:gap-4">
|
<div className="flex flex-col md:flex-row md:gap-4">
|
||||||
<div className={`flex items-center gap-2 ml-2 mb-1`}>
|
<div
|
||||||
|
className={
|
||||||
|
`flex items-center gap-2 ml-2 mb-1`
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
className="mr-[2px] op-radio op-radio-xs"
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
@@ -456,7 +467,11 @@ const EditTemplate = ({
|
|||||||
/>
|
/>
|
||||||
<div className="text-center">{t("yes")}</div>
|
<div className="text-center">{t("yes")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`flex items-center gap-2 ml-2 mb-1`}>
|
<div
|
||||||
|
className={
|
||||||
|
`flex items-center gap-2 ml-2 mb-1`
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
className="mr-[2px] op-radio op-radio-xs"
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
+8
-3
@@ -1,6 +1,10 @@
|
|||||||
import React, { useState } from "react";
|
import React, { useState } from "react";
|
||||||
import { handleToPrint } from "../../constant/Utils";
|
import {
|
||||||
import { emailRegex } from "../../constant/const";
|
handleToPrint,
|
||||||
|
} from "../../constant/Utils";
|
||||||
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../../constant/const";
|
||||||
import Loader from "../../primitives/Loader";
|
import Loader from "../../primitives/Loader";
|
||||||
import ModalUi from "../../primitives/ModalUi";
|
import ModalUi from "../../primitives/ModalUi";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -37,7 +41,8 @@ function EmailComponent({
|
|||||||
setEmailList([]);
|
setEmailList([]);
|
||||||
}, 1500);
|
}, 1500);
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
setIsEmail(false);
|
setIsEmail(false);
|
||||||
setIsAlert({
|
setIsAlert({
|
||||||
+14
@@ -276,6 +276,20 @@ function Header(props) {
|
|||||||
className="bg-white shadow-md rounded-md px-3 py-2"
|
className="bg-white shadow-md rounded-md px-3 py-2"
|
||||||
sideOffset={5}
|
sideOffset={5}
|
||||||
>
|
>
|
||||||
|
{props?.setIsEditTemplate && (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
className="DropdownMenuItem"
|
||||||
|
onClick={() => props?.setIsEditTemplate(true)}
|
||||||
|
>
|
||||||
|
<div className="flex flex-row">
|
||||||
|
<i
|
||||||
|
className="fa-light fa-gear mr-[3px]"
|
||||||
|
aria-hidden="true"
|
||||||
|
></i>
|
||||||
|
<span className="font-[500]">{t("Edit")}</span>
|
||||||
|
</div>
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
)}
|
||||||
<DropdownMenu.Item
|
<DropdownMenu.Item
|
||||||
className="DropdownMenuItem"
|
className="DropdownMenuItem"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
+25
-25
@@ -197,31 +197,31 @@ function Placeholder(props) {
|
|||||||
if (props?.ispublicTemplate) {
|
if (props?.ispublicTemplate) {
|
||||||
props.handleUserDetails();
|
props.handleUserDetails();
|
||||||
} else {
|
} else {
|
||||||
if (props?.isNeedSign) {
|
if (props?.isNeedSign) {
|
||||||
//funcion is used to heightlight widgets on top if two widgets on overlap
|
//funcion is used to heightlight widgets on top if two widgets on overlap
|
||||||
const getCurrentSignerPos = props.xyPosition.find(
|
const getCurrentSignerPos = props.xyPosition.find(
|
||||||
(x) => x.Id === props.uniqueId
|
(x) => x.Id === props.uniqueId
|
||||||
);
|
);
|
||||||
const updateZindex = handleHeighlightWidget(
|
const updateZindex = handleHeighlightWidget(
|
||||||
getCurrentSignerPos,
|
getCurrentSignerPos,
|
||||||
props.pos.key,
|
props.pos.key,
|
||||||
props.pageNumber
|
props.pageNumber
|
||||||
);
|
);
|
||||||
const updatesignerPos = props.xyPosition.map((x) =>
|
const updatesignerPos = props.xyPosition.map((x) =>
|
||||||
x.Id === props.uniqueId ? { ...x, placeHolder: updateZindex } : x
|
x.Id === props.uniqueId ? { ...x, placeHolder: updateZindex } : x
|
||||||
);
|
);
|
||||||
props.setXyPosition(updatesignerPos);
|
props.setXyPosition(updatesignerPos);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
["signature", "stamp", "image", "initials"].includes(props.pos.type)
|
["signature", "stamp", "image", "initials"].includes(props.pos.type)
|
||||||
) {
|
) {
|
||||||
props.setIsSignPad(true);
|
props.setIsSignPad(true);
|
||||||
props.setSignKey(props.pos.key);
|
props.setSignKey(props.pos.key);
|
||||||
props.setIsStamp(props.pos.isStamp);
|
props.setIsStamp(props.pos.isStamp);
|
||||||
}
|
}
|
||||||
if (props.pos.type === "initials") {
|
if (props.pos.type === "initials") {
|
||||||
props.setIsInitial(true);
|
props.setIsInitial(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
props.isPlaceholder &&
|
props.isPlaceholder &&
|
||||||
+23
-41
@@ -7,7 +7,8 @@ import {
|
|||||||
radioButtonWidget,
|
radioButtonWidget,
|
||||||
range,
|
range,
|
||||||
textInputWidget,
|
textInputWidget,
|
||||||
textWidget
|
textWidget,
|
||||||
|
widgetDataValue
|
||||||
} from "../../constant/Utils";
|
} from "../../constant/Utils";
|
||||||
import DatePicker from "react-datepicker";
|
import DatePicker from "react-datepicker";
|
||||||
import "react-datepicker/dist/react-datepicker.css";
|
import "react-datepicker/dist/react-datepicker.css";
|
||||||
@@ -24,6 +25,8 @@ const widgetCls =
|
|||||||
function PlaceholderType(props) {
|
function PlaceholderType(props) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const type = props?.pos?.type;
|
const type = props?.pos?.type;
|
||||||
|
const widgetData =
|
||||||
|
props.pos?.options?.defaultValue || props.pos?.options?.response;
|
||||||
const widgetTypeTranslation = t(`widgets-name.${props?.pos?.type}`);
|
const widgetTypeTranslation = t(`widgets-name.${props?.pos?.type}`);
|
||||||
const [selectOption, setSelectOption] = useState("");
|
const [selectOption, setSelectOption] = useState("");
|
||||||
const [validatePlaceholder, setValidatePlaceholder] = useState("");
|
const [validatePlaceholder, setValidatePlaceholder] = useState("");
|
||||||
@@ -141,29 +144,6 @@ function PlaceholderType(props) {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (
|
|
||||||
["name", "email", "job title", "company"].includes(props.pos?.type) &&
|
|
||||||
props.isNeedSign &&
|
|
||||||
props.data?.signerObjId === props?.signerObjId
|
|
||||||
) {
|
|
||||||
const defaultData = props.pos?.options?.defaultValue;
|
|
||||||
if (defaultData) {
|
|
||||||
setTextValue(defaultData);
|
|
||||||
}
|
|
||||||
if (props.pos?.options?.hint) {
|
|
||||||
setHint(props.pos?.options.hint);
|
|
||||||
} else {
|
|
||||||
setHint(props.pos?.type);
|
|
||||||
}
|
|
||||||
} else if ([textInputWidget].includes(props.pos?.type)) {
|
|
||||||
const defaultData = props.pos?.options?.defaultValue;
|
|
||||||
if (defaultData) {
|
|
||||||
setTextValue(defaultData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [props.pos?.options?.defaultValue]);
|
|
||||||
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
const ExampleCustomInput = forwardRef(({ value, onClick }, ref) => (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
@@ -180,28 +160,26 @@ function PlaceholderType(props) {
|
|||||||
</div>
|
</div>
|
||||||
));
|
));
|
||||||
ExampleCustomInput.displayName = "ExampleCustomInput";
|
ExampleCustomInput.displayName = "ExampleCustomInput";
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (
|
if (
|
||||||
["name", "email", "job title", "company"].includes(type) &&
|
["name", "email", "job title", "company", textInputWidget].includes(
|
||||||
|
type
|
||||||
|
) &&
|
||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
props.data?.signerObjId === props.signerObjId
|
props.data?.signerObjId === props.signerObjId
|
||||||
) {
|
) {
|
||||||
const isDefault = true;
|
if (widgetData) {
|
||||||
const senderUser = localStorage.getItem("Extand_Class");
|
setTextValue(widgetData);
|
||||||
const jsonSender = JSON.parse(senderUser);
|
}
|
||||||
onChangeInput(
|
}
|
||||||
jsonSender && jsonSender[0],
|
|
||||||
null,
|
if (props.pos?.options?.hint) {
|
||||||
props.xyPosition,
|
setHint(props.pos?.options.hint);
|
||||||
null,
|
} else {
|
||||||
props.setXyPosition,
|
setHint(props.pos?.type);
|
||||||
props.data.Id,
|
|
||||||
isDefault
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [type]);
|
}, [type, widgetData]);
|
||||||
//function for show checked checkbox
|
//function for show checked checkbox
|
||||||
const selectCheckbox = (ind) => {
|
const selectCheckbox = (ind) => {
|
||||||
const res = props.pos.options?.response;
|
const res = props.pos.options?.response;
|
||||||
@@ -462,10 +440,14 @@ function PlaceholderType(props) {
|
|||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
(props.pos.options?.isReadOnly ||
|
(props.pos.options?.isReadOnly ||
|
||||||
props.data?.signerObjId !== props.signerObjId)
|
props.data?.signerObjId !== props.signerObjId)
|
||||||
? " bg-black/68 select-none "
|
? "select-none"
|
||||||
: "" + textWidgetCls
|
: "" + textWidgetCls
|
||||||
}`}
|
}`}
|
||||||
style={{ fontSize: fontSize, color: fontColor }}
|
style={{
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: fontColor,
|
||||||
|
background: props.data?.blockColor
|
||||||
|
}}
|
||||||
disabled={
|
disabled={
|
||||||
props.isNeedSign &&
|
props.isNeedSign &&
|
||||||
(props.pos.options?.isReadOnly ||
|
(props.pos.options?.isReadOnly ||
|
||||||
+6
-34
@@ -460,15 +460,7 @@ function SignPad(props) {
|
|||||||
props?.convertToImg(fontSelect, typedSignature, data);
|
props?.convertToImg(fontSelect, typedSignature, data);
|
||||||
setPenColor(allColor[key]);
|
setPenColor(allColor[key]);
|
||||||
}}
|
}}
|
||||||
className={`border-b-[2px] ${
|
className={`border-b-[2px] ${key === 0 && penColor === "blue" ? "border-blue-600" : key === 1 && penColor === "red" ? "border-red-500" : key === 2 && penColor === "black" ? "border-black" : "border-white"} text-[${data}] text-[16px] fa-light fa-pen-nib`}
|
||||||
key === 0 && penColor === "blue"
|
|
||||||
? "border-blue-600"
|
|
||||||
: key === 1 && penColor === "red"
|
|
||||||
? "border-red-500"
|
|
||||||
: key === 2 && penColor === "black"
|
|
||||||
? "border-black"
|
|
||||||
: "border-white"
|
|
||||||
} text-[${data}] text-[16px] fa-light fa-pen-nib`}
|
|
||||||
></i>
|
></i>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -651,11 +643,7 @@ function SignPad(props) {
|
|||||||
<>
|
<>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
||||||
props?.isInitial
|
|
||||||
? "intialSignatureCanvas"
|
|
||||||
: "signatureCanvas"
|
|
||||||
} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="stamp img"
|
alt="stamp img"
|
||||||
@@ -682,11 +670,7 @@ function SignPad(props) {
|
|||||||
<>
|
<>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
||||||
props?.isInitial
|
|
||||||
? "intialSignatureCanvas"
|
|
||||||
: "signatureCanvas"
|
|
||||||
} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="stamp img"
|
alt="stamp img"
|
||||||
@@ -711,11 +695,7 @@ function SignPad(props) {
|
|||||||
!props?.image ? (
|
!props?.image ? (
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
||||||
props?.isInitial
|
|
||||||
? "intialSignatureCanvas"
|
|
||||||
: "signatureCanvas"
|
|
||||||
} bg-white border-[1.3px] border-[#007bff] flex flex-col justify-center items-center mb-[6px] cursor-pointer`}
|
|
||||||
onClick={() => props?.imageRef.current.click()}
|
onClick={() => props?.imageRef.current.click()}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
@@ -734,11 +714,7 @@ function SignPad(props) {
|
|||||||
<>
|
<>
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<div
|
<div
|
||||||
className={`${
|
className={`${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} bg-white border-[1.3px] border-[#007bff] mb-[6px] overflow-hidden`}
|
||||||
props?.isInitial
|
|
||||||
? "intialSignatureCanvas"
|
|
||||||
: "signatureCanvas"
|
|
||||||
} bg-white border-[1.3px] border-[#007bff] mb-[6px] overflow-hidden`}
|
|
||||||
>
|
>
|
||||||
<img
|
<img
|
||||||
alt="print img"
|
alt="print img"
|
||||||
@@ -826,11 +802,7 @@ function SignPad(props) {
|
|||||||
ref={canvasRef}
|
ref={canvasRef}
|
||||||
penColor={penColor}
|
penColor={penColor}
|
||||||
canvasProps={{
|
canvasProps={{
|
||||||
className: `${
|
className: `${props?.isInitial ? "intialSignatureCanvas" : "signatureCanvas"} border-[1.3px] border-[#007bff]`
|
||||||
props?.isInitial
|
|
||||||
? "intialSignatureCanvas"
|
|
||||||
: "signatureCanvas"
|
|
||||||
} border-[1.3px] border-[#007bff]`
|
|
||||||
}}
|
}}
|
||||||
onEnd={() =>
|
onEnd={() =>
|
||||||
handleSignatureChange(
|
handleSignatureChange(
|
||||||
+1
@@ -117,6 +117,7 @@ const WidgetNameModal = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const handleCheckboxChange = (index) => {
|
const handleCheckboxChange = (index) => {
|
||||||
// Update the state with the modified array
|
// Update the state with the modified array
|
||||||
setSignatureType((prev) =>
|
setSignatureType((prev) =>
|
||||||
+2
-1
@@ -6,7 +6,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
|
|
||||||
const FolderModal = (props) => {
|
const FolderModal = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const [clickFolder, setClickFolder] = useState("");
|
const [clickFolder, setClickFolder] = useState("");
|
||||||
const [folderList, setFolderList] = useState([]);
|
const [folderList, setFolderList] = useState([]);
|
||||||
+2
-1
@@ -6,7 +6,8 @@ import Tooltip from "../../../primitives/Tooltip";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
const SelectFolder = ({ required, onSuccess, folderCls, isReset }) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [isOpen, SetIsOpen] = useState(false);
|
const [isOpen, SetIsOpen] = useState(false);
|
||||||
+4
-4
@@ -117,7 +117,9 @@ const SignersInput = (props) => {
|
|||||||
};
|
};
|
||||||
const loadOptions = async (inputValue) => {
|
const loadOptions = async (inputValue) => {
|
||||||
try {
|
try {
|
||||||
const contactRes = await findContact(inputValue);
|
const contactRes = await findContact(
|
||||||
|
inputValue,
|
||||||
|
);
|
||||||
if (contactRes) {
|
if (contactRes) {
|
||||||
const res = JSON.parse(JSON.stringify(contactRes));
|
const res = JSON.parse(JSON.stringify(contactRes));
|
||||||
//compareArrays is a function where compare between two array (total signersList and dcument signers list)
|
//compareArrays is a function where compare between two array (total signersList and dcument signers list)
|
||||||
@@ -152,9 +154,7 @@ const SignersInput = (props) => {
|
|||||||
{props.label ? props.label : t("signers")}
|
{props.label ? props.label : t("signers")}
|
||||||
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
{props.required && <span className="text-red-500 text-[13px]">*</span>}
|
||||||
<span
|
<span
|
||||||
className={`z-[${
|
className={`z-[${props?.helptextZindex ? props.helptextZindex : 30}] absolute ml-1 text-xs`}
|
||||||
props?.helptextZindex ? props.helptextZindex : 30
|
|
||||||
}] absolute ml-1 text-xs`}
|
|
||||||
>
|
>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={`${props.label ? props.label : "signers"}-tooltip`}
|
id={`${props.label ? props.label : "signers"}-tooltip`}
|
||||||
+2
-1
@@ -3,7 +3,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { NavLink } from "react-router";
|
import { NavLink } from "react-router";
|
||||||
|
|
||||||
const Menu = ({ item, isOpen, closeSidebar }) => {
|
const Menu = ({ item, isOpen, closeSidebar }) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
return (
|
return (
|
||||||
+2
-1
@@ -3,7 +3,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { NavLink } from "react-router";
|
import { NavLink } from "react-router";
|
||||||
|
|
||||||
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
const Submenu = ({ item, closeSidebar, toggleSubmenu, submenuOpen }) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { title, icon, children } = item;
|
const { title, icon, children } = item;
|
||||||
@@ -7,7 +7,9 @@ import { appInfo } from "./appinfo";
|
|||||||
import { saveAs } from "file-saver";
|
import { saveAs } from "file-saver";
|
||||||
import printModule from "print-js";
|
import printModule from "print-js";
|
||||||
import fontkit from "@pdf-lib/fontkit";
|
import fontkit from "@pdf-lib/fontkit";
|
||||||
import { themeColor } from "./const";
|
import {
|
||||||
|
themeColor
|
||||||
|
} from "./const";
|
||||||
import { format, toZonedTime } from "date-fns-tz";
|
import { format, toZonedTime } from "date-fns-tz";
|
||||||
|
|
||||||
export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28];
|
export const fontsizeArr = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28];
|
||||||
@@ -135,12 +137,15 @@ export const pdfNewWidthFun = (divRef) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//`contractUsers` function is used to get contract_User details
|
//`contractUsers` function is used to get contract_User details
|
||||||
export const contractUsers = async () => {
|
export const contractUsers = async (
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const url = `${localStorage.getItem("baseUrl")}functions/getUserDetails`;
|
const url = `${localStorage.getItem("baseUrl")}functions/getUserDetails`;
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
const accesstoken = localStorage.getItem("accesstoken");
|
const accesstoken =
|
||||||
const token = { "X-Parse-Session-Token": accesstoken };
|
localStorage.getItem("accesstoken");
|
||||||
|
const token =
|
||||||
|
{ "X-Parse-Session-Token": accesstoken };
|
||||||
const headers = {
|
const headers = {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -298,7 +303,7 @@ export const changeDateToMomentFormat = (format) => {
|
|||||||
return "L";
|
return "L";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
export const addWidgetOptions = (type, signer) => {
|
export const addWidgetOptions = (type, signer, widgetValue) => {
|
||||||
const defaultOpt = { name: type, status: "required" };
|
const defaultOpt = { name: type, status: "required" };
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case "signature":
|
case "signature":
|
||||||
@@ -315,11 +320,11 @@ export const addWidgetOptions = (type, signer) => {
|
|||||||
case "initials":
|
case "initials":
|
||||||
return defaultOpt;
|
return defaultOpt;
|
||||||
case "name":
|
case "name":
|
||||||
return { ...defaultOpt };
|
return { ...defaultOpt, defaultValue: widgetValue ? widgetValue : "" };
|
||||||
case "company":
|
case "company":
|
||||||
return { ...defaultOpt };
|
return { ...defaultOpt, defaultValue: widgetValue ? widgetValue : "" };
|
||||||
case "job title":
|
case "job title":
|
||||||
return { ...defaultOpt };
|
return { ...defaultOpt, defaultValue: widgetValue ? widgetValue : "" };
|
||||||
case "date": {
|
case "date": {
|
||||||
const dateFormat = signer?.DateFormat
|
const dateFormat = signer?.DateFormat
|
||||||
? selectFormat(signer?.DateFormat)
|
? selectFormat(signer?.DateFormat)
|
||||||
@@ -333,7 +338,11 @@ export const addWidgetOptions = (type, signer) => {
|
|||||||
case "image":
|
case "image":
|
||||||
return defaultOpt;
|
return defaultOpt;
|
||||||
case "email":
|
case "email":
|
||||||
return { ...defaultOpt, validation: { type: "email", pattern: "" } };
|
return {
|
||||||
|
...defaultOpt,
|
||||||
|
validation: { type: "email", pattern: "" },
|
||||||
|
defaultValue: widgetValue ? widgetValue : ""
|
||||||
|
};
|
||||||
case "dropdown":
|
case "dropdown":
|
||||||
return defaultOpt;
|
return defaultOpt;
|
||||||
case radioButtonWidget:
|
case radioButtonWidget:
|
||||||
@@ -556,7 +565,7 @@ export const signPdfFun = async (
|
|||||||
documentId,
|
documentId,
|
||||||
signerObjectId,
|
signerObjectId,
|
||||||
objectId,
|
objectId,
|
||||||
widgets
|
widgets,
|
||||||
) => {
|
) => {
|
||||||
let isCustomCompletionMail = false;
|
let isCustomCompletionMail = false;
|
||||||
try {
|
try {
|
||||||
@@ -565,7 +574,10 @@ export const signPdfFun = async (
|
|||||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
return { status: "error", message: "User does not exist." };
|
return { status: "error", message: "User does not exist." };
|
||||||
} else {
|
} else {
|
||||||
if (tenantDetails?.CompletionBody && tenantDetails?.CompletionSubject) {
|
if (
|
||||||
|
tenantDetails?.CompletionBody &&
|
||||||
|
tenantDetails?.CompletionSubject
|
||||||
|
) {
|
||||||
isCustomCompletionMail = true;
|
isCustomCompletionMail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -855,7 +867,8 @@ export const onChangeInput = (
|
|||||||
...position,
|
...position,
|
||||||
options: {
|
options: {
|
||||||
...position.options,
|
...position.options,
|
||||||
response: value
|
response: value,
|
||||||
|
defaultValue:""
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1009,21 +1022,21 @@ export const calculateInitialWidthHeight = (widgetData) => {
|
|||||||
document.body.removeChild(span);
|
document.body.removeChild(span);
|
||||||
return { getWidth: width, getHeight: height };
|
return { getWidth: width, getHeight: height };
|
||||||
};
|
};
|
||||||
export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
export const widgetDataValue = (type, value) => {
|
||||||
function widgetDataValue(type) {
|
switch (type) {
|
||||||
switch (type) {
|
case "name":
|
||||||
case "name":
|
return value?.Name;
|
||||||
return value?.Name;
|
case "company":
|
||||||
case "company":
|
return value?.Company;
|
||||||
return value?.Company;
|
case "job title":
|
||||||
case "job title":
|
return value?.JobTitle;
|
||||||
return value?.JobTitle;
|
case "email":
|
||||||
case "email":
|
return value?.Email;
|
||||||
return value?.Email;
|
default:
|
||||||
default:
|
return "";
|
||||||
return "";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
||||||
return signerPos.map((item) => {
|
return signerPos.map((item) => {
|
||||||
if (item.placeHolder && item.placeHolder.length > 0) {
|
if (item.placeHolder && item.placeHolder.length > 0) {
|
||||||
// If there is a nested array, recursively add the field to the last object
|
// If there is a nested array, recursively add the field to the last object
|
||||||
@@ -1048,7 +1061,7 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
|||||||
// Adjust this line to add the desired field
|
// Adjust this line to add the desired field
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
const widgetData = widgetDataValue(item.type);
|
const widgetData = widgetDataValue(item.type, value);
|
||||||
if (["name", "company", "job title", "email"].includes(item.type)) {
|
if (["name", "company", "job title", "email"].includes(item.type)) {
|
||||||
return {
|
return {
|
||||||
...item,
|
...item,
|
||||||
@@ -1066,7 +1079,8 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
|||||||
|
|
||||||
//function for embed document id
|
//function for embed document id
|
||||||
export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
// `fontBytes` is used to embed custom font in pdf
|
// `fontBytes` is used to embed custom font in pdf
|
||||||
const fontBytes = await fileasbytes(
|
const fontBytes = await fileasbytes(
|
||||||
"https://cdn.opensignlabs.com/webfonts/times.ttf"
|
"https://cdn.opensignlabs.com/webfonts/times.ttf"
|
||||||
@@ -1075,7 +1089,8 @@ export const embedDocId = async (pdfDoc, documentId, allPages) => {
|
|||||||
const font = await pdfDoc.embedFont(fontBytes, { subset: true });
|
const font = await pdfDoc.embedFont(fontBytes, { subset: true });
|
||||||
for (let i = 0; i < allPages; i++) {
|
for (let i = 0; i < allPages; i++) {
|
||||||
const fontSize = 10;
|
const fontSize = 10;
|
||||||
const textContent = documentId && `${appName} DocumentId: ${documentId} `;
|
const textContent =
|
||||||
|
documentId && `${appName} DocumentId: ${documentId} `;
|
||||||
const pages = pdfDoc.getPages();
|
const pages = pdfDoc.getPages();
|
||||||
const page = pages[i];
|
const page = pages[i];
|
||||||
try {
|
try {
|
||||||
@@ -1900,7 +1915,9 @@ export const placeholderHeight = (pos) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//function for getting contracts_contactbook details
|
//function for getting contracts_contactbook details
|
||||||
export const contactBook = async (objectId) => {
|
export const contactBook = async (
|
||||||
|
objectId,
|
||||||
|
) => {
|
||||||
const result = await axios
|
const result = await axios
|
||||||
.get(
|
.get(
|
||||||
`${localStorage.getItem(
|
`${localStorage.getItem(
|
||||||
@@ -1910,7 +1927,8 @@ export const contactBook = async (objectId) => {
|
|||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
"X-Parse-Session-Token":
|
||||||
|
localStorage.getItem("accesstoken")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@@ -1928,9 +1946,12 @@ export const contactBook = async (objectId) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//function for getting document details from contract_Documents class
|
//function for getting document details from contract_Documents class
|
||||||
export const contractDocument = async (documentId) => {
|
export const contractDocument = async (
|
||||||
|
documentId,
|
||||||
|
) => {
|
||||||
const data = { docId: documentId };
|
const data = { docId: documentId };
|
||||||
const token = { sessionToken: localStorage.getItem("accesstoken") };
|
const token =
|
||||||
|
{ sessionToken: localStorage.getItem("accesstoken") };
|
||||||
const documentDeatils = await axios
|
const documentDeatils = await axios
|
||||||
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
|
.post(`${localStorage.getItem("baseUrl")}functions/getDocument`, data, {
|
||||||
headers: {
|
headers: {
|
||||||
@@ -2114,31 +2135,36 @@ export const getFileName = (fileUrl) => {
|
|||||||
|
|
||||||
//fetch tenant app logo from `partners_Tenant` class by domain name
|
//fetch tenant app logo from `partners_Tenant` class by domain name
|
||||||
export const getAppLogo = async () => {
|
export const getAppLogo = async () => {
|
||||||
const domain = window.location.host;
|
const domain = window.location.host;
|
||||||
try {
|
try {
|
||||||
const tenant = await Parse.Cloud.run("getlogobydomain", {
|
const tenant = await Parse.Cloud.run("getlogobydomain", {
|
||||||
domain: domain
|
domain: domain
|
||||||
});
|
});
|
||||||
if (tenant) {
|
if (tenant) {
|
||||||
localStorage.setItem("appname", "OpenSign™");
|
localStorage.setItem("appname", "OpenSign™");
|
||||||
return { logo: tenant?.logo, user: tenant?.user };
|
return { logo: tenant?.logo, user: tenant?.user };
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("err in getlogo ", err);
|
||||||
|
if (err?.message?.includes("valid JSON")) {
|
||||||
|
return { logo: appInfo.applogo, user: "exist", error: "invalid_json" };
|
||||||
|
} else {
|
||||||
|
return { logo: appInfo.applogo, user: "exist" };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
console.log("err in getlogo ", err);
|
|
||||||
if (err?.message?.includes("valid JSON")) {
|
|
||||||
return { logo: appInfo.applogo, user: "exist", error: "invalid_json" };
|
|
||||||
} else {
|
|
||||||
return { logo: appInfo.applogo, user: "exist" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
export const getTenantDetails = async (objectId, contactId) => {
|
export const getTenantDetails = async (
|
||||||
|
objectId,
|
||||||
|
contactId
|
||||||
|
) => {
|
||||||
try {
|
try {
|
||||||
const url = `${localStorage.getItem("baseUrl")}functions/gettenant`;
|
const url = `${localStorage.getItem("baseUrl")}functions/gettenant`;
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
const accesstoken = localStorage.getItem("accesstoken");
|
const accesstoken = localStorage.getItem("accesstoken");
|
||||||
const token = { "X-Parse-Session-Token": accesstoken };
|
const token =
|
||||||
const data = { userId: objectId, contactId: contactId };
|
{ "X-Parse-Session-Token": accesstoken };
|
||||||
|
const data =
|
||||||
|
{ userId: objectId, contactId: contactId };
|
||||||
const res = await axios.post(url, data, {
|
const res = await axios.post(url, data, {
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -2219,7 +2245,7 @@ export const handleSendOTP = async (email) => {
|
|||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||||
};
|
};
|
||||||
const body = {
|
const body = {
|
||||||
email: email
|
email: email,
|
||||||
};
|
};
|
||||||
await axios.post(url, body, { headers: headers });
|
await axios.post(url, body, { headers: headers });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -2227,7 +2253,8 @@ export const handleSendOTP = async (email) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
export const fetchUrl = async (url, pdfName) => {
|
export const fetchUrl = async (url, pdfName) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
try {
|
try {
|
||||||
const response = await fetch(url);
|
const response = await fetch(url);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@@ -2241,7 +2268,11 @@ export const fetchUrl = async (url, pdfName) => {
|
|||||||
console.error("Error downloading the file:", error);
|
console.error("Error downloading the file:", error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
export const getSignedUrl = async (pdfUrl, docId, templateId) => {
|
export const getSignedUrl = async (
|
||||||
|
pdfUrl,
|
||||||
|
docId,
|
||||||
|
templateId
|
||||||
|
) => {
|
||||||
//use only axios here due to public template sign
|
//use only axios here due to public template sign
|
||||||
const axiosRes = await axios.post(
|
const axiosRes = await axios.post(
|
||||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||||
@@ -2302,7 +2333,10 @@ export const handleDownloadPdf = async (
|
|||||||
setIsDownloading && setIsDownloading("pdf");
|
setIsDownloading && setIsDownloading("pdf");
|
||||||
const docId = pdfDetails?.[0]?.objectId || "";
|
const docId = pdfDetails?.[0]?.objectId || "";
|
||||||
try {
|
try {
|
||||||
const url = await getSignedUrl(pdfUrl, docId);
|
const url = await getSignedUrl(
|
||||||
|
pdfUrl,
|
||||||
|
docId,
|
||||||
|
);
|
||||||
await fetchUrl(url, pdfName);
|
await fetchUrl(url, pdfName);
|
||||||
setIsDownloading && setIsDownloading("");
|
setIsDownloading && setIsDownloading("");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -2332,7 +2366,7 @@ export const handleToPrint = async (event, setIsDownloading, pdfDetails) => {
|
|||||||
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
`${localStorage.getItem("baseUrl")}/functions/getsignedurl`,
|
||||||
{
|
{
|
||||||
url: pdfUrl,
|
url: pdfUrl,
|
||||||
docId: docId
|
docId: docId,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -2376,7 +2410,8 @@ export const handleDownloadCertificate = async (
|
|||||||
setIsDownloading,
|
setIsDownloading,
|
||||||
isZip
|
isZip
|
||||||
) => {
|
) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
|
if (pdfDetails?.length > 0 && pdfDetails[0]?.CertificateUrl) {
|
||||||
try {
|
try {
|
||||||
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
|
await fetch(pdfDetails[0] && pdfDetails[0]?.CertificateUrl);
|
||||||
@@ -2460,13 +2495,14 @@ export const handleDownloadCertificate = async (
|
|||||||
export function escapeRegExp(string) {
|
export function escapeRegExp(string) {
|
||||||
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Escape special characters
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // Escape special characters
|
||||||
}
|
}
|
||||||
export async function findContact(value) {
|
export async function findContact(
|
||||||
|
value,
|
||||||
|
) {
|
||||||
try {
|
try {
|
||||||
const baseURL = localStorage.getItem("baseUrl");
|
const baseURL = localStorage.getItem("baseUrl");
|
||||||
const url = `${baseURL}functions/getsigners`;
|
const url = `${baseURL}functions/getsigners`;
|
||||||
const token = {
|
const token =
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||||
};
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
@@ -2678,20 +2714,23 @@ export function base64ToArrayBuffer(base64) {
|
|||||||
return bytes.buffer;
|
return bytes.buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const convertBase64ToFile = async (pdfName, pdfBase64) => {
|
export const convertBase64ToFile = async (
|
||||||
|
pdfName,
|
||||||
|
pdfBase64,
|
||||||
|
) => {
|
||||||
const fileName = sanitizeFileName(pdfName) + ".pdf";
|
const fileName = sanitizeFileName(pdfName) + ".pdf";
|
||||||
try {
|
try {
|
||||||
const pdfFile = new Parse.File(fileName, { base64: pdfBase64 });
|
const pdfFile = new Parse.File(fileName, { base64: pdfBase64 });
|
||||||
// Save the Parse File if needed
|
// Save the Parse File if needed
|
||||||
const pdfData = await pdfFile.save();
|
const pdfData = await pdfFile.save();
|
||||||
const pdfUrl = pdfData.url();
|
const pdfUrl = pdfData.url();
|
||||||
const fileRes = await getSecureUrl(pdfUrl);
|
const fileRes = await getSecureUrl(pdfUrl);
|
||||||
if (fileRes?.url) {
|
if (fileRes?.url) {
|
||||||
return fileRes.url;
|
return fileRes.url;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log("error in convertbase64tofile", e);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
console.log("error in convertbase64tofile", e);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
export const onClickZoomIn = (scale, zoomPercent, setScale, setZoomPercent) => {
|
export const onClickZoomIn = (scale, zoomPercent, setScale, setZoomPercent) => {
|
||||||
setScale(scale + 0.1 * scale);
|
setScale(scale + 0.1 * scale);
|
||||||
@@ -2981,10 +3020,13 @@ export const flattenPdf = async (pdfFile) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const mailTemplate = (param) => {
|
export const mailTemplate = (param) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
const logo = `<div style='padding:10px'><img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' /></div>`;
|
"OpenSign™";
|
||||||
|
const logo =
|
||||||
|
`<div style='padding:10px'><img src='https://qikinnovation.ams3.digitaloceanspaces.com/logo.png' height='50' /></div>`;
|
||||||
|
|
||||||
const opurl = ` <a href='https://www.opensignlabs.com' target=_blank>here</a>.</p></div></div></body></html>`;
|
const opurl =
|
||||||
|
` <a href='https://www.opensignlabs.com' target=_blank>here</a>.</p></div></div></body></html>`;
|
||||||
|
|
||||||
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
const subject = `${param.senderName} has requested you to sign "${param.title}"`;
|
||||||
const body =
|
const body =
|
||||||
@@ -3027,7 +3069,14 @@ export function formatDateTime(date, dateFormat, timeZone, is12Hour) {
|
|||||||
: formatTimeInTimezone(date, timeZone);
|
: formatTimeInTimezone(date, timeZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const updateDateWidgetsRes = (placeHolders, signerId) => {
|
export const updateDateWidgetsRes = (documentData, signerId, journey) => {
|
||||||
|
const extUser =
|
||||||
|
localStorage.getItem("Extand_Class");
|
||||||
|
const contactUser = documentData?.Signers.find(
|
||||||
|
(data) => data.objectId === signerId
|
||||||
|
);
|
||||||
|
const placeHolders = documentData?.Placeholders;
|
||||||
|
const userDetails = extUser ? JSON.parse(extUser)[0] : contactUser;
|
||||||
return placeHolders?.map((item) => {
|
return placeHolders?.map((item) => {
|
||||||
if (item?.signerObjId === signerId) {
|
if (item?.signerObjId === signerId) {
|
||||||
return {
|
return {
|
||||||
@@ -3046,6 +3095,18 @@ export const updateDateWidgetsRes = (placeHolders, signerId) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
} else if (
|
||||||
|
["name", "email", "job title", "company"].includes(widget.type) &&
|
||||||
|
!widget.options.defaultValue &&
|
||||||
|
!widget.options.response
|
||||||
|
) {
|
||||||
|
return {
|
||||||
|
...widget,
|
||||||
|
options: {
|
||||||
|
...widget.options,
|
||||||
|
response: widgetDataValue(widget.type, userDetails)
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
return widget;
|
return widget;
|
||||||
})
|
})
|
||||||
@@ -11,9 +11,6 @@ export const appInfo = {
|
|||||||
appId: process.env.REACT_APP_APPID ? process.env.REACT_APP_APPID : "opensign",
|
appId: process.env.REACT_APP_APPID ? process.env.REACT_APP_APPID : "opensign",
|
||||||
baseUrl: serverUrl_fn(),
|
baseUrl: serverUrl_fn(),
|
||||||
defaultRole: "contracts_User",
|
defaultRole: "contracts_User",
|
||||||
fbAppId: process.env.REACT_APP_FBAPPID
|
|
||||||
? `${process.env.REACT_APP_FBAPPID}`
|
|
||||||
: "",
|
|
||||||
fev_Icon:
|
fev_Icon:
|
||||||
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC",
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAALlJREFUaEPtmN0NwjAMBpNxYDKYiM1Yp90g93CKStH1NbIdfz921Dker2Pc+Js1cDF7MXAxASMGYkAigBI6vh9ZwoXP53uZoAYcvhwdA3mAVbI2aSb+9zFKU4IURB6j/HoPUIEa2G3iGIAhQQDlAUIoE2diabIklISS0NoFPebo77RF6OenEF3QntOm128he0GKrwHyACFoz2MgBqSGkpAEcHs47oHtN5AFakACqMNjQEMoE8SABFCHn4HE2zGHSLeEAAAAAElFTkSuQmCC",
|
||||||
googleClietId: process.env.REACT_APP_GOOGLECLIENTID
|
googleClietId: process.env.REACT_APP_GOOGLECLIENTID
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
export default function linkURL(url) {
|
|
||||||
let newURL = (url && decodeURIComponent(url)) || "";
|
|
||||||
return newURL.substring(newURL.indexOf(".com/") + 5, newURL.indexOf("_"));
|
|
||||||
}
|
|
||||||
@@ -13,15 +13,13 @@ import {
|
|||||||
MouseTransition,
|
MouseTransition,
|
||||||
Preview
|
Preview
|
||||||
} from "react-dnd-multi-backend";
|
} from "react-dnd-multi-backend";
|
||||||
import DragElement from "./components/pdf/DragElement";
|
import DragElement from "./components/pdf/DragElement.jsx";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import "./polyfills";
|
import "./polyfills";
|
||||||
import { serverUrl_fn } from "./constant/appinfo";
|
import { serverUrl_fn } from "./constant/appinfo";
|
||||||
import "./i18n";
|
import "./i18n";
|
||||||
|
|
||||||
const appId = process.env.REACT_APP_APPID
|
const appId = import.meta.env.VITE_APPID || process.env.REACT_APP_APPID || "opensign";
|
||||||
? process.env.REACT_APP_APPID
|
|
||||||
: "opensign";
|
|
||||||
const serverUrl = serverUrl_fn();
|
const serverUrl = serverUrl_fn();
|
||||||
Parse.initialize(appId);
|
Parse.initialize(appId);
|
||||||
Parse.serverURL = serverUrl;
|
Parse.serverURL = serverUrl;
|
||||||
@@ -55,6 +53,7 @@ const generatePreview = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById("root"));
|
const root = ReactDOM.createRoot(document.getElementById("root"));
|
||||||
root.render(
|
root.render(
|
||||||
<CookiesProvider defaultSetOptions={{ path: "/" }}>
|
<CookiesProvider defaultSetOptions={{ path: "/" }}>
|
||||||
@@ -36,7 +36,7 @@ const dashboardJson = [
|
|||||||
queryType: "",
|
queryType: "",
|
||||||
class: "contracts_Document",
|
class: "contracts_Document",
|
||||||
query:
|
query:
|
||||||
'where={"Type":{"#*ne":"Folder"},"Signers":{"#*exists":true,"#*ne":[]},"Placeholders":{"#*ne":null},"SignedUrl":{"#*ne":null},"IsCompleted":{"#*ne":true},"IsDeclined":{"#*ne":true},"IsArchive":{"#*ne":true},"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"#UserId.objectId#"},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&count=1',
|
'where={"Type":null,"Signers":{"#*exists":true},"Placeholders":{"#*exists":true},"SignedUrl":{"#*exists":true},"IsCompleted":false,"IsDeclined":false,"IsArchive":null,"CreatedBy":{"__type":"Pointer","className":"_User","objectId":"#UserId.objectId#"},"ExpiryDate":{"#*gt":{"__type":"#Date#","iso":"#today#"}}}&keys=Name,ExpiryDate,SignedUrl,Signers&count=1',
|
||||||
key: "count",
|
key: "count",
|
||||||
Redirect_type: "Report",
|
Redirect_type: "Report",
|
||||||
Redirect_id: "1MwEuxLEkF",
|
Redirect_id: "1MwEuxLEkF",
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import { showHeader } from "../redux/reducers/showHeader";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
const HomeLayout = () => {
|
const HomeLayout = () => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -53,8 +54,8 @@ const HomeLayout = () => {
|
|||||||
});
|
});
|
||||||
if (user) {
|
if (user) {
|
||||||
localStorage.setItem("profileImg", user.get("ProfilePic") || "");
|
localStorage.setItem("profileImg", user.get("ProfilePic") || "");
|
||||||
setIsUserValid(true);
|
setIsUserValid(true);
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} else {
|
} else {
|
||||||
setIsUserValid(false);
|
setIsUserValid(false);
|
||||||
}
|
}
|
||||||
@@ -16,7 +16,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import { emailRegex } from "../constant/const";
|
import { emailRegex } from "../constant/const";
|
||||||
|
|
||||||
const AddAdmin = () => {
|
const AddAdmin = () => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
@@ -175,7 +176,6 @@ const AddAdmin = () => {
|
|||||||
localStorage.setItem("accesstoken", sessionToken);
|
localStorage.setItem("accesstoken", sessionToken);
|
||||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
||||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
localStorage.setItem("accesstoken", _user.sessionToken);
|
||||||
localStorage.setItem("scriptId", true);
|
|
||||||
if (_user.ProfilePic) {
|
if (_user.ProfilePic) {
|
||||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
localStorage.setItem("profileImg", _user.ProfilePic);
|
||||||
} else {
|
} else {
|
||||||
+1
-1
@@ -5,7 +5,7 @@ import {
|
|||||||
getBase64FromUrl,
|
getBase64FromUrl,
|
||||||
handleDownloadCertificate,
|
handleDownloadCertificate,
|
||||||
handleDownloadPdf,
|
handleDownloadPdf,
|
||||||
handleToPrint
|
handleToPrint,
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
+5
-3
@@ -7,7 +7,9 @@ import Alert from "../primitives/Alert";
|
|||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
import { useDispatch } from "react-redux";
|
import { useDispatch } from "react-redux";
|
||||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
import { emailRegex } from "../constant/const";
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
|
|
||||||
@@ -46,7 +48,7 @@ function ForgotPassword() {
|
|||||||
if (state.email) {
|
if (state.email) {
|
||||||
const username = state.email;
|
const username = state.email;
|
||||||
try {
|
try {
|
||||||
await Parse.User.requestPasswordReset(username);
|
await Parse.User.requestPasswordReset(username);
|
||||||
setToast({ type: "success", message: t("reset-password-alert-1") });
|
setToast({ type: "success", message: t("reset-password-alert-1") });
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err ", err.code);
|
console.log("err ", err.code);
|
||||||
@@ -76,7 +78,7 @@ function ForgotPassword() {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err while logging out ", err);
|
console.log("err while logging out ", err);
|
||||||
}
|
}
|
||||||
setImage(appInfo?.applogo || undefined);
|
setImage(appInfo?.applogo || undefined);
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
@@ -42,7 +42,8 @@ function Form() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Forms = (props) => {
|
const Forms = (props) => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const inputFileRef = useRef(null);
|
const inputFileRef = useRef(null);
|
||||||
@@ -105,12 +106,12 @@ const Forms = (props) => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
const initializeValues = async () => {
|
const initializeValues = async () => {
|
||||||
setFormData((obj) => ({
|
setFormData((obj) => ({
|
||||||
...obj,
|
...obj,
|
||||||
NotifyOnSignatures: true,
|
NotifyOnSignatures: true,
|
||||||
SendinOrder: sendinorder,
|
SendinOrder: sendinorder,
|
||||||
IsTourEnabled: istourenabled
|
IsTourEnabled: istourenabled
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
function getFileAsArrayBuffer(file) {
|
function getFileAsArrayBuffer(file) {
|
||||||
@@ -148,81 +149,17 @@ const Forms = (props) => {
|
|||||||
const name = generatePdfName(16);
|
const name = generatePdfName(16);
|
||||||
const pdfName = `${name?.split(".")[0]}.pdf`;
|
const pdfName = `${name?.split(".")[0]}.pdf`;
|
||||||
setfileload(true);
|
setfileload(true);
|
||||||
try {
|
|
||||||
const res = await getFileAsArrayBuffer(files[0]);
|
|
||||||
const flatPdf = await flattenPdf(res);
|
|
||||||
const parseFile = new Parse.File(
|
|
||||||
pdfName,
|
|
||||||
[...flatPdf],
|
|
||||||
"application/pdf"
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await parseFile.save({
|
const res = await getFileAsArrayBuffer(files[0]);
|
||||||
progress: (progressValue, loaded, total, { type }) => {
|
const flatPdf = await flattenPdf(res);
|
||||||
if (type === "upload" && progressValue !== null) {
|
const parseFile = new Parse.File(
|
||||||
const percentCompleted = Math.round(
|
pdfName,
|
||||||
(loaded * 100) / total
|
[...flatPdf],
|
||||||
);
|
"application/pdf"
|
||||||
setpercentage(percentCompleted);
|
);
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// The response object will contain information about the uploaded file
|
|
||||||
// You can access the URL of the uploaded file using response.url()
|
|
||||||
if (response.url()) {
|
|
||||||
const fileRes = await getSecureUrl(response.url());
|
|
||||||
if (fileRes.url) {
|
|
||||||
setFileUpload(fileRes.url);
|
|
||||||
setfileload(false);
|
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
|
||||||
const title = generateTitleFromFilename(files?.[0]?.name);
|
|
||||||
setFormData((obj) => ({ ...obj, Name: title }));
|
|
||||||
SaveFileSize(size, fileRes.url, tenantId);
|
|
||||||
return fileRes.url;
|
|
||||||
} else {
|
|
||||||
removeFile(e);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
removeFile(e);
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
removeFile(e);
|
|
||||||
console.error("Error uploading file:", error);
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
if (err?.message?.includes("is encrypted")) {
|
|
||||||
try {
|
|
||||||
setIsDecrypting(true);
|
|
||||||
const size = files?.[0].size;
|
|
||||||
const name = generatePdfName(16);
|
|
||||||
const url = "https://ai.nxglabs.in/decryptpdf"; //
|
|
||||||
let formData = new FormData();
|
|
||||||
formData.append("file", files[0]);
|
|
||||||
formData.append("password", "");
|
|
||||||
const config = {
|
|
||||||
headers: { "content-type": "multipart/form-data" },
|
|
||||||
responseType: "blob"
|
|
||||||
};
|
|
||||||
const response = await axios.post(url, formData, config);
|
|
||||||
const pdfBlob = new Blob([response.data], {
|
|
||||||
type: "application/pdf"
|
|
||||||
});
|
|
||||||
const pdfFile = new File([pdfBlob], name, {
|
|
||||||
type: "application/pdf"
|
|
||||||
});
|
|
||||||
setIsDecrypting(false);
|
|
||||||
setfileload(true);
|
|
||||||
const res = await getFileAsArrayBuffer(pdfFile);
|
|
||||||
const flatPdf = await flattenPdf(res);
|
|
||||||
// Upload the file to Parse Server
|
|
||||||
const parseFile = new Parse.File(
|
|
||||||
name,
|
|
||||||
[...flatPdf],
|
|
||||||
"application/pdf"
|
|
||||||
);
|
|
||||||
|
|
||||||
await parseFile.save({
|
try {
|
||||||
|
const response = await parseFile.save({
|
||||||
progress: (progressValue, loaded, total, { type }) => {
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
if (type === "upload" && progressValue !== null) {
|
if (type === "upload" && progressValue !== null) {
|
||||||
const percentCompleted = Math.round(
|
const percentCompleted = Math.round(
|
||||||
@@ -232,16 +169,16 @@ const Forms = (props) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// The response object will contain information about the uploaded file
|
||||||
// Retrieve the URL of the uploaded file
|
// You can access the URL of the uploaded file using response.url()
|
||||||
if (parseFile.url()) {
|
if (response.url()) {
|
||||||
const fileRes = await getSecureUrl(parseFile.url());
|
const fileRes = await getSecureUrl(response.url());
|
||||||
if (fileRes.url) {
|
if (fileRes.url) {
|
||||||
setFileUpload(fileRes.url);
|
setFileUpload(fileRes.url);
|
||||||
removeFile();
|
setfileload(false);
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
const title = generateTitleFromFilename(files?.[0]?.name);
|
const title = generateTitleFromFilename(files?.[0]?.name);
|
||||||
setFormData((obj) => ({ ...obj, Name: title }));
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
|
||||||
SaveFileSize(size, fileRes.url, tenantId);
|
SaveFileSize(size, fileRes.url, tenantId);
|
||||||
return fileRes.url;
|
return fileRes.url;
|
||||||
} else {
|
} else {
|
||||||
@@ -250,22 +187,88 @@ const Forms = (props) => {
|
|||||||
} else {
|
} else {
|
||||||
removeFile(e);
|
removeFile(e);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
removeFile();
|
removeFile(e);
|
||||||
if (err?.response?.status === 401) {
|
console.error("Error uploading file:", error);
|
||||||
setIsPassword(true);
|
}
|
||||||
} else {
|
} catch (err) {
|
||||||
console.log("Error uploading file: ", err?.response);
|
if (err?.message?.includes("is encrypted")) {
|
||||||
setIsDecrypting(false);
|
try {
|
||||||
e.target.value = "";
|
setIsDecrypting(true);
|
||||||
}
|
const size = files?.[0].size;
|
||||||
|
const name = generatePdfName(16);
|
||||||
|
const url = "https://ai.nxglabs.in/decryptpdf"; //
|
||||||
|
let formData = new FormData();
|
||||||
|
formData.append("file", files[0]);
|
||||||
|
formData.append("password", "");
|
||||||
|
const config = {
|
||||||
|
headers: { "content-type": "multipart/form-data" },
|
||||||
|
responseType: "blob"
|
||||||
|
};
|
||||||
|
const response = await axios.post(url, formData, config);
|
||||||
|
const pdfBlob = new Blob([response.data], {
|
||||||
|
type: "application/pdf"
|
||||||
|
});
|
||||||
|
const pdfFile = new File([pdfBlob], name, {
|
||||||
|
type: "application/pdf"
|
||||||
|
});
|
||||||
|
setIsDecrypting(false);
|
||||||
|
setfileload(true);
|
||||||
|
const res = await getFileAsArrayBuffer(pdfFile);
|
||||||
|
const flatPdf = await flattenPdf(res);
|
||||||
|
// Upload the file to Parse Server
|
||||||
|
const parseFile = new Parse.File(
|
||||||
|
name,
|
||||||
|
[...flatPdf],
|
||||||
|
"application/pdf"
|
||||||
|
);
|
||||||
|
|
||||||
|
await parseFile.save({
|
||||||
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
|
if (type === "upload" && progressValue !== null) {
|
||||||
|
const percentCompleted = Math.round(
|
||||||
|
(loaded * 100) / total
|
||||||
|
);
|
||||||
|
setpercentage(percentCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Retrieve the URL of the uploaded file
|
||||||
|
if (parseFile.url()) {
|
||||||
|
const fileRes = await getSecureUrl(parseFile.url());
|
||||||
|
if (fileRes.url) {
|
||||||
|
setFileUpload(fileRes.url);
|
||||||
|
removeFile();
|
||||||
|
const title = generateTitleFromFilename(
|
||||||
|
files?.[0]?.name
|
||||||
|
);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, fileRes.url, tenantId);
|
||||||
|
return fileRes.url;
|
||||||
|
} else {
|
||||||
|
removeFile(e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
removeFile(e);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
removeFile();
|
||||||
|
if (err?.response?.status === 401) {
|
||||||
|
setIsPassword(true);
|
||||||
|
} else {
|
||||||
|
console.log("Error uploading file: ", err?.response);
|
||||||
|
setIsDecrypting(false);
|
||||||
|
e.target.value = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("err ", err);
|
||||||
|
setFileUpload("");
|
||||||
|
removeFile(e);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.log("err ", err);
|
|
||||||
setFileUpload("");
|
|
||||||
removeFile(e);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const isImage = files?.[0]?.type.includes("image/");
|
const isImage = files?.[0]?.type.includes("image/");
|
||||||
if (isImage) {
|
if (isImage) {
|
||||||
@@ -290,50 +293,50 @@ const Forms = (props) => {
|
|||||||
});
|
});
|
||||||
const size = files?.[0]?.size;
|
const size = files?.[0]?.size;
|
||||||
const name = generatePdfName(16);
|
const name = generatePdfName(16);
|
||||||
const getFile = await pdfDoc.save({
|
const getFile = await pdfDoc.save({
|
||||||
useObjectStreams: false
|
useObjectStreams: false
|
||||||
});
|
|
||||||
setfileload(true);
|
|
||||||
const pdfName = `${name?.split(".")[0]}.pdf`;
|
|
||||||
const parseFile = new Parse.File(
|
|
||||||
pdfName,
|
|
||||||
[...getFile],
|
|
||||||
"application/pdf"
|
|
||||||
);
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await parseFile.save({
|
|
||||||
progress: (progressValue, loaded, total, { type }) => {
|
|
||||||
if (type === "upload" && progressValue !== null) {
|
|
||||||
const percentCompleted = Math.round(
|
|
||||||
(loaded * 100) / total
|
|
||||||
);
|
|
||||||
setpercentage(percentCompleted);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// The response object will contain information about the uploaded file
|
setfileload(true);
|
||||||
// You can access the URL of the uploaded file using response.url()
|
const pdfName = `${name?.split(".")[0]}.pdf`;
|
||||||
if (response.url()) {
|
const parseFile = new Parse.File(
|
||||||
const fileRes = await getSecureUrl(response.url());
|
pdfName,
|
||||||
if (fileRes.url) {
|
[...getFile],
|
||||||
setFileUpload(fileRes.url);
|
"application/pdf"
|
||||||
setfileload(false);
|
);
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
|
||||||
const title = generateTitleFromFilename(files?.[0]?.name);
|
try {
|
||||||
setFormData((obj) => ({ ...obj, Name: title }));
|
const response = await parseFile.save({
|
||||||
SaveFileSize(size, fileRes.url, tenantId);
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
return fileRes.url;
|
if (type === "upload" && progressValue !== null) {
|
||||||
|
const percentCompleted = Math.round(
|
||||||
|
(loaded * 100) / total
|
||||||
|
);
|
||||||
|
setpercentage(percentCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// The response object will contain information about the uploaded file
|
||||||
|
// You can access the URL of the uploaded file using response.url()
|
||||||
|
if (response.url()) {
|
||||||
|
const fileRes = await getSecureUrl(response.url());
|
||||||
|
if (fileRes.url) {
|
||||||
|
setFileUpload(fileRes.url);
|
||||||
|
setfileload(false);
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
const title = generateTitleFromFilename(files?.[0]?.name);
|
||||||
|
setFormData((obj) => ({ ...obj, Name: title }));
|
||||||
|
SaveFileSize(size, fileRes.url, tenantId);
|
||||||
|
return fileRes.url;
|
||||||
|
} else {
|
||||||
|
removeFile(e);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
removeFile(e);
|
removeFile(e);
|
||||||
}
|
}
|
||||||
} else {
|
} catch (error) {
|
||||||
removeFile(e);
|
removeFile(e);
|
||||||
|
console.error("Error uploading file:", error);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
|
||||||
removeFile(e);
|
|
||||||
console.error("Error uploading file:", error);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,11 +411,11 @@ const Forms = (props) => {
|
|||||||
object.set("RemindOnceInEvery", remindOnceInEvery);
|
object.set("RemindOnceInEvery", remindOnceInEvery);
|
||||||
object.set("IsTourEnabled", isTourEnabled);
|
object.set("IsTourEnabled", isTourEnabled);
|
||||||
object.set("TimeToCompleteDays", TimeToCompleteDays);
|
object.set("TimeToCompleteDays", TimeToCompleteDays);
|
||||||
object.set("AllowModifications", false);
|
object.set("AllowModifications", false);
|
||||||
object.set("IsEnableOTP", false);
|
object.set("IsEnableOTP", false);
|
||||||
if (formData.NotifyOnSignatures !== undefined) {
|
if (formData.NotifyOnSignatures !== undefined) {
|
||||||
object.set("NotifyOnSignatures", formData.NotifyOnSignatures);
|
object.set("NotifyOnSignatures", formData.NotifyOnSignatures);
|
||||||
}
|
}
|
||||||
if (formData?.RedirectUrl) {
|
if (formData?.RedirectUrl) {
|
||||||
object.set("RedirectUrl", formData.RedirectUrl);
|
object.set("RedirectUrl", formData.RedirectUrl);
|
||||||
}
|
}
|
||||||
@@ -451,9 +454,10 @@ const Forms = (props) => {
|
|||||||
setSigners([]);
|
setSigners([]);
|
||||||
setBcc([]);
|
setBcc([]);
|
||||||
setFolder({ ObjectId: "", Name: "" });
|
setFolder({ ObjectId: "", Name: "" });
|
||||||
const notifySign = extUserData?.NotifyOnSignatures
|
const notifySign =
|
||||||
? extUserData?.NotifyOnSignatures
|
extUserData?.NotifyOnSignatures
|
||||||
: true;
|
? extUserData?.NotifyOnSignatures
|
||||||
|
: true;
|
||||||
setFormData({
|
setFormData({
|
||||||
Name: "",
|
Name: "",
|
||||||
Description: "",
|
Description: "",
|
||||||
@@ -529,9 +533,10 @@ const Forms = (props) => {
|
|||||||
setSigners([]);
|
setSigners([]);
|
||||||
setBcc([]);
|
setBcc([]);
|
||||||
setFolder({ ObjectId: "", Name: "" });
|
setFolder({ ObjectId: "", Name: "" });
|
||||||
const notifySign = extUserData?.NotifyOnSignatures
|
const notifySign =
|
||||||
? extUserData?.NotifyOnSignatures
|
extUserData?.NotifyOnSignatures
|
||||||
: true;
|
? extUserData?.NotifyOnSignatures
|
||||||
|
: true;
|
||||||
let obj = {
|
let obj = {
|
||||||
Name: "",
|
Name: "",
|
||||||
Description: "",
|
Description: "",
|
||||||
@@ -585,28 +590,36 @@ const Forms = (props) => {
|
|||||||
type: "application/pdf"
|
type: "application/pdf"
|
||||||
});
|
});
|
||||||
setIsDecrypting(false);
|
setIsDecrypting(false);
|
||||||
const res = await getFileAsArrayBuffer(pdfFile);
|
const res = await getFileAsArrayBuffer(pdfFile);
|
||||||
const flatPdf = await flattenPdf(res);
|
const flatPdf = await flattenPdf(res);
|
||||||
const parseFile = new Parse.File(name, [...flatPdf], "application/pdf");
|
const parseFile = new Parse.File(name, [...flatPdf], "application/pdf");
|
||||||
await parseFile.save({
|
await parseFile.save({
|
||||||
progress: (progressValue, loaded, total, { type }) => {
|
progress: (progressValue, loaded, total, { type }) => {
|
||||||
if (type === "upload" && progressValue !== null) {
|
if (type === "upload" && progressValue !== null) {
|
||||||
const percentCompleted = Math.round((loaded * 100) / total);
|
const percentCompleted = Math.round((loaded * 100) / total);
|
||||||
setpercentage(percentCompleted);
|
setpercentage(percentCompleted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Retrieve the URL of the uploaded file
|
||||||
|
if (parseFile.url()) {
|
||||||
|
const fileRes = await getSecureUrl(parseFile.url());
|
||||||
|
if (fileRes.url) {
|
||||||
|
setFileUpload(fileRes.url);
|
||||||
|
removeFile();
|
||||||
|
const title = generateTitleFromFilename(formData?.file?.name);
|
||||||
|
setFormData((obj) => ({ ...obj, password: "", Name: title }));
|
||||||
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
|
SaveFileSize(size, fileRes.url, tenantId);
|
||||||
|
return fileRes.url;
|
||||||
|
} else {
|
||||||
|
removeFile();
|
||||||
|
setFormData((prev) => ({ ...prev, password: "" }));
|
||||||
|
setIsDecrypting(false);
|
||||||
|
if (inputFileRef.current) {
|
||||||
|
inputFileRef.current.value = ""; // Set file input value to empty string
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
// Retrieve the URL of the uploaded file
|
|
||||||
if (parseFile.url()) {
|
|
||||||
const fileRes = await getSecureUrl(parseFile.url());
|
|
||||||
if (fileRes.url) {
|
|
||||||
setFileUpload(fileRes.url);
|
|
||||||
removeFile();
|
|
||||||
const title = generateTitleFromFilename(formData?.file?.name);
|
|
||||||
setFormData((obj) => ({ ...obj, password: "", Name: title }));
|
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
|
||||||
SaveFileSize(size, fileRes.url, tenantId);
|
|
||||||
return fileRes.url;
|
|
||||||
} else {
|
} else {
|
||||||
removeFile();
|
removeFile();
|
||||||
setFormData((prev) => ({ ...prev, password: "" }));
|
setFormData((prev) => ({ ...prev, password: "" }));
|
||||||
@@ -615,14 +628,6 @@ const Forms = (props) => {
|
|||||||
inputFileRef.current.value = ""; // Set file input value to empty string
|
inputFileRef.current.value = ""; // Set file input value to empty string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
removeFile();
|
|
||||||
setFormData((prev) => ({ ...prev, password: "" }));
|
|
||||||
setIsDecrypting(false);
|
|
||||||
if (inputFileRef.current) {
|
|
||||||
inputFileRef.current.value = ""; // Set file input value to empty string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
removeFile();
|
removeFile();
|
||||||
if (err?.response?.status === 401) {
|
if (err?.response?.status === 401) {
|
||||||
@@ -744,7 +749,9 @@ const Forms = (props) => {
|
|||||||
)}
|
)}
|
||||||
<div className="text-xs">
|
<div className="text-xs">
|
||||||
<label className="block">
|
<label className="block">
|
||||||
{`${`${t("report-heading.File")} (${t("file-type")}`}${")"}`}
|
{`${`${t("report-heading.File")} (${t("file-type")}`}${
|
||||||
|
")"
|
||||||
|
}`}
|
||||||
<span className="text-red-500 text-[13px]">*</span>
|
<span className="text-red-500 text-[13px]">*</span>
|
||||||
</label>
|
</label>
|
||||||
{fileupload.length > 0 ? (
|
{fileupload.length > 0 ? (
|
||||||
@@ -768,7 +775,9 @@ const Forms = (props) => {
|
|||||||
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
className="op-file-input op-file-input-bordered op-file-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
onChange={(e) => handleFileInput(e)}
|
onChange={(e) => handleFileInput(e)}
|
||||||
ref={inputFileRef}
|
ref={inputFileRef}
|
||||||
accept={"application/pdf,image/png,image/jpeg"}
|
accept={
|
||||||
|
"application/pdf,image/png,image/jpeg"
|
||||||
|
}
|
||||||
onInvalid={(e) =>
|
onInvalid={(e) =>
|
||||||
e.target.setCustomValidity(t("input-required"))
|
e.target.setCustomValidity(t("input-required"))
|
||||||
}
|
}
|
||||||
@@ -1058,7 +1067,10 @@ const Forms = (props) => {
|
|||||||
{isAdvanceOpt && (
|
{isAdvanceOpt && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: props.title === "New Template" ? "100px" : "280px"
|
height:
|
||||||
|
props.title === "New Template"
|
||||||
|
? "100px"
|
||||||
|
: "280px"
|
||||||
}}
|
}}
|
||||||
className="w-[1px] bg-gray-300 m-auto hidden md:inline-block"
|
className="w-[1px] bg-gray-300 m-auto hidden md:inline-block"
|
||||||
></div>
|
></div>
|
||||||
@@ -1167,7 +1179,11 @@ const Forms = (props) => {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-col md:flex-row md:gap-4">
|
<div className="flex flex-col md:flex-row md:gap-4">
|
||||||
<div className={`flex items-center gap-2 ml-2 mb-1`}>
|
<div
|
||||||
|
className={
|
||||||
|
`flex items-center gap-2 ml-2 mb-1`
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
className="mr-[2px] op-radio op-radio-xs"
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
@@ -1176,7 +1192,11 @@ const Forms = (props) => {
|
|||||||
/>
|
/>
|
||||||
<div className="text-center">{t("yes")}</div>
|
<div className="text-center">{t("yes")}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={`flex items-center gap-2 ml-2 mb-1`}>
|
<div
|
||||||
|
className={
|
||||||
|
`flex items-center gap-2 ml-2 mb-1`
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
className="mr-[2px] op-radio op-radio-xs"
|
className="mr-[2px] op-radio op-radio-xs"
|
||||||
type="radio"
|
type="radio"
|
||||||
@@ -1,8 +1,13 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { useNavigate, useParams } from "react-router";
|
import { useNavigate, useParams } from "react-router";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { emailRegex } from "../constant/const";
|
import {
|
||||||
import { contractUsers, saveLanguageInLocal } from "../constant/Utils";
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
|
import {
|
||||||
|
contractUsers,
|
||||||
|
saveLanguageInLocal
|
||||||
|
} from "../constant/Utils";
|
||||||
import logo from "../assets/images/logo.png";
|
import logo from "../assets/images/logo.png";
|
||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
@@ -33,6 +38,7 @@ function GuestLogin() {
|
|||||||
const [sendmail, setSendmail] = useState();
|
const [sendmail, setSendmail] = useState();
|
||||||
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
const [contact, setContact] = useState({ name: "", phone: "", email: "" });
|
||||||
|
|
||||||
|
|
||||||
const navigateToDoc = async (docId, contactId) => {
|
const navigateToDoc = async (docId, contactId) => {
|
||||||
try {
|
try {
|
||||||
const docDetails = await Parse.Cloud.run("getDocument", {
|
const docDetails = await Parse.Cloud.run("getDocument", {
|
||||||
@@ -62,12 +68,16 @@ function GuestLogin() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
//function generate serverUrl and parseAppId from url and save it in local storage
|
//function generate serverUrl and parseAppId from url and save it in local storage
|
||||||
const handleServerUrl = async () => {
|
const handleServerUrl = async () => {
|
||||||
setAppLogo(logo);
|
setAppLogo(logo);
|
||||||
|
|
||||||
localStorage.clear(); // Clears everything
|
localStorage.clear(); // Clears everything
|
||||||
localStorage.setItem("appname", "OpenSign™");
|
localStorage.setItem(
|
||||||
|
"appname",
|
||||||
|
"OpenSign™"
|
||||||
|
);
|
||||||
//save isGuestSigner true in local to handle login flow header in mobile view
|
//save isGuestSigner true in local to handle login flow header in mobile view
|
||||||
localStorage.setItem("isGuestSigner", true);
|
localStorage.setItem("isGuestSigner", true);
|
||||||
saveLanguageInLocal(i18n);
|
saveLanguageInLocal(i18n);
|
||||||
@@ -119,7 +129,7 @@ function GuestLogin() {
|
|||||||
try {
|
try {
|
||||||
const params = {
|
const params = {
|
||||||
email: email?.toLowerCase()?.replace(/\s/g, "")?.toString(),
|
email: email?.toLowerCase()?.replace(/\s/g, "")?.toString(),
|
||||||
docId: documentId
|
docId: documentId,
|
||||||
};
|
};
|
||||||
const Otp = await Parse.Cloud.run("SendOTPMailV1", params);
|
const Otp = await Parse.Cloud.run("SendOTPMailV1", params);
|
||||||
if (Otp) {
|
if (Otp) {
|
||||||
@@ -200,6 +210,7 @@ function GuestLogin() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const handleUserData = async (e) => {
|
const handleUserData = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!emailRegex.test(contact.email?.toLowerCase()?.replace(/\s/g, ""))) {
|
if (!emailRegex.test(contact.email?.toLowerCase()?.replace(/\s/g, ""))) {
|
||||||
@@ -323,12 +334,12 @@ function GuestLogin() {
|
|||||||
className="op-btn op-btn-primary flex items-center"
|
className="op-btn op-btn-primary flex items-center"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
SendOtp();
|
SendOtp();
|
||||||
}}
|
}}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-message-sms mr-2"></i>
|
<i className="fa-light fa-message-sms mr-2"></i>
|
||||||
{loading ? t("loading") : t("get-verification-code")}
|
{loading ? t("loading") : t("get-verification-code")}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -7,7 +7,9 @@ import { NavLink, useNavigate, useLocation } from "react-router";
|
|||||||
import login_img from "../assets/images/login_img.svg";
|
import login_img from "../assets/images/login_img.svg";
|
||||||
import { useWindowSize } from "../hook/useWindowSize";
|
import { useWindowSize } from "../hook/useWindowSize";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import { emailRegex } from "../constant/const";
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import { appInfo } from "../constant/appinfo";
|
import { appInfo } from "../constant/appinfo";
|
||||||
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
import { fetchAppInfo } from "../redux/reducers/infoReducer";
|
||||||
@@ -22,7 +24,8 @@ import { useTranslation } from "react-i18next";
|
|||||||
import SelectLanguage from "../components/pdf/SelectLanguage";
|
import SelectLanguage from "../components/pdf/SelectLanguage";
|
||||||
|
|
||||||
function Login() {
|
function Login() {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t, i18n } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const location = useLocation();
|
const location = useLocation();
|
||||||
@@ -30,17 +33,12 @@ function Login() {
|
|||||||
const { width } = useWindowSize();
|
const { width } = useWindowSize();
|
||||||
const [state, setState] = useState({
|
const [state, setState] = useState({
|
||||||
email: "",
|
email: "",
|
||||||
|
password: "",
|
||||||
alertType: "success",
|
alertType: "success",
|
||||||
alertMsg: "",
|
alertMsg: "",
|
||||||
password: "",
|
|
||||||
passwordVisible: false,
|
passwordVisible: false,
|
||||||
mobile: "",
|
|
||||||
phone: "",
|
|
||||||
scanResult: "",
|
|
||||||
baseUrl: localStorage.getItem("baseUrl"),
|
|
||||||
parseAppId: localStorage.getItem("parseAppId"),
|
|
||||||
loading: false,
|
loading: false,
|
||||||
thirdpartyLoader: false
|
thirdpartyLoader: false,
|
||||||
});
|
});
|
||||||
const [userDetails, setUserDetails] = useState({
|
const [userDetails, setUserDetails] = useState({
|
||||||
Company: "",
|
Company: "",
|
||||||
@@ -54,6 +52,18 @@ function Login() {
|
|||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
const setLocalVar = (user) => {
|
||||||
|
localStorage.setItem("accesstoken", user.sessionToken);
|
||||||
|
localStorage.setItem("UserInformation", JSON.stringify(user));
|
||||||
|
localStorage.setItem("userEmail", user.email);
|
||||||
|
if (user.ProfilePic) {
|
||||||
|
localStorage.setItem("profileImg", user.ProfilePic);
|
||||||
|
} else {
|
||||||
|
localStorage.setItem("profileImg", "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const showToast = (type, msg) => {
|
const showToast = (type, msg) => {
|
||||||
setState({ ...state, loading: false, alertType: type, alertMsg: msg });
|
setState({ ...state, loading: false, alertType: type, alertMsg: msg });
|
||||||
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
|
||||||
@@ -62,7 +72,9 @@ function Login() {
|
|||||||
const app = await getAppLogo();
|
const app = await getAppLogo();
|
||||||
if (app?.error === "invalid_json") {
|
if (app?.error === "invalid_json") {
|
||||||
setErrMsg(t("server-down", { appName: appName }));
|
setErrMsg(t("server-down", { appName: appName }));
|
||||||
} else if (app?.user === "not_exist") {
|
} else if (
|
||||||
|
app?.user === "not_exist"
|
||||||
|
) {
|
||||||
navigate("/addadmin");
|
navigate("/addadmin");
|
||||||
}
|
}
|
||||||
if (app?.logo) {
|
if (app?.logo) {
|
||||||
@@ -109,21 +121,11 @@ function Login() {
|
|||||||
// Get extended user data (including 2FA status) using cloud function
|
// Get extended user data (including 2FA status) using cloud function
|
||||||
try {
|
try {
|
||||||
await Parse.User.become(_user.sessionToken);
|
await Parse.User.become(_user.sessionToken);
|
||||||
// Store basic user info needed for further steps
|
setLocalVar(_user);
|
||||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
|
||||||
localStorage.setItem("userEmail", email);
|
|
||||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
|
||||||
localStorage.setItem("scriptId", true);
|
|
||||||
if (_user.ProfilePic) {
|
|
||||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("profileImg", "");
|
|
||||||
}
|
|
||||||
await continueLoginFlow();
|
await continueLoginFlow();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error checking 2FA status:", error);
|
console.error("Error checking 2FA status:", error);
|
||||||
showToast("danger", t("something-went-wrong-mssg"));
|
showToast("danger", t("something-went-wrong-mssg"));
|
||||||
setState({ ...state, loading: false });
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error while logging in user", error);
|
console.error("Error while logging in user", error);
|
||||||
@@ -134,6 +136,7 @@ function Login() {
|
|||||||
const setThirdpartyLoader = (value) => {
|
const setThirdpartyLoader = (value) => {
|
||||||
setState({ ...state, thirdpartyLoader: value });
|
setState({ ...state, thirdpartyLoader: value });
|
||||||
};
|
};
|
||||||
|
|
||||||
const thirdpartyLoginfn = async (sessionToken) => {
|
const thirdpartyLoginfn = async (sessionToken) => {
|
||||||
const baseUrl = localStorage.getItem("baseUrl");
|
const baseUrl = localStorage.getItem("baseUrl");
|
||||||
const parseAppId = localStorage.getItem("parseAppId");
|
const parseAppId = localStorage.getItem("parseAppId");
|
||||||
@@ -148,74 +151,57 @@ function Login() {
|
|||||||
});
|
});
|
||||||
if (res.data) {
|
if (res.data) {
|
||||||
let _user = res.data;
|
let _user = res.data;
|
||||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
setLocalVar(_user);
|
||||||
localStorage.setItem("userEmail", _user.email);
|
|
||||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
|
||||||
localStorage.setItem("scriptId", true);
|
|
||||||
if (_user.ProfilePic) {
|
|
||||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("profileImg", "");
|
|
||||||
}
|
|
||||||
// Check extended class user role and tenentId
|
// Check extended class user role and tenentId
|
||||||
try {
|
try {
|
||||||
const userSettings = appInfo.settings;
|
const userSettings = appInfo.settings;
|
||||||
await Parse.Cloud.run("getUserDetails")
|
const extUser = await Parse.Cloud.run("getUserDetails");
|
||||||
.then(async (extUser) => {
|
if (extUser) {
|
||||||
if (extUser) {
|
const IsDisabled = extUser?.get("IsDisabled") || false;
|
||||||
const IsDisabled = extUser?.get("IsDisabled") || false;
|
if (!IsDisabled) {
|
||||||
if (!IsDisabled) {
|
const userRole = extUser?.get("UserRole");
|
||||||
const userRole = extUser?.get("UserRole");
|
const menu =
|
||||||
const menu =
|
userRole && userSettings.find((menu) => menu.role === userRole);
|
||||||
userRole &&
|
if (menu) {
|
||||||
userSettings.find((menu) => menu.role === userRole);
|
const _currentRole = userRole;
|
||||||
if (menu) {
|
const redirectUrl =
|
||||||
const _currentRole = userRole;
|
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
||||||
const redirectUrl =
|
const _role = _currentRole.replace("contracts_", "");
|
||||||
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||||
const _role = _currentRole.replace("contracts_", "");
|
localStorage.setItem("_user_role", _role);
|
||||||
localStorage.setItem("_user_role", _role);
|
localStorage.setItem("Extand_Class", JSON.stringify([extUser]));
|
||||||
const results = [extUser];
|
localStorage.setItem("userEmail", extInfo?.Email);
|
||||||
const extUser_stringify = JSON.stringify(results);
|
localStorage.setItem("username", extInfo?.Name);
|
||||||
localStorage.setItem("Extand_Class", extUser_stringify);
|
if (extInfo?.TenantId) {
|
||||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
const tenant = {
|
||||||
localStorage.setItem("userEmail", extInfo?.Email);
|
Id: extInfo?.TenantId?.objectId || "",
|
||||||
localStorage.setItem("username", extInfo?.Name);
|
Name: extInfo?.TenantId?.TenantName || ""
|
||||||
if (extInfo?.TenantId) {
|
};
|
||||||
const tenant = {
|
localStorage.setItem("TenantId", tenant?.Id);
|
||||||
Id: extInfo?.TenantId?.objectId || "",
|
dispatch(showTenant(tenant?.Name));
|
||||||
Name: extInfo?.TenantId?.TenantName || ""
|
localStorage.setItem("TenantName", tenant?.Name);
|
||||||
};
|
|
||||||
localStorage.setItem("TenantId", tenant?.Id);
|
|
||||||
dispatch(showTenant(tenant?.Name));
|
|
||||||
localStorage.setItem("TenantName", tenant?.Name);
|
|
||||||
}
|
|
||||||
localStorage.setItem("PageLanding", menu.pageId);
|
|
||||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
|
||||||
localStorage.setItem("pageType", menu.pageType);
|
|
||||||
navigate(redirectUrl);
|
|
||||||
} else {
|
|
||||||
showToast("danger", t("role-not-found"));
|
|
||||||
logOutUser();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showToast("danger", t("do-not-access-contact-admin"));
|
|
||||||
logOutUser();
|
|
||||||
}
|
}
|
||||||
|
localStorage.setItem("PageLanding", menu.pageId);
|
||||||
|
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||||
|
localStorage.setItem("pageType", menu.pageType);
|
||||||
|
navigate(redirectUrl);
|
||||||
} else {
|
} else {
|
||||||
showToast("danger", t("user-not-found"));
|
showToast("danger", t("role-not-found"));
|
||||||
logOutUser();
|
logOutUser();
|
||||||
}
|
}
|
||||||
})
|
} else {
|
||||||
.catch((err) => {
|
showToast("danger", t("do-not-access-contact-admin"));
|
||||||
console.error("err in fetching extUser", err);
|
logOutUser();
|
||||||
showToast("danger", `${err.message}`);
|
}
|
||||||
const payload = { sessionToken: sessionToken };
|
} else {
|
||||||
handleSubmitbtn(payload);
|
showToast("danger", t("user-not-found"));
|
||||||
});
|
logOutUser();
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showToast("danger", `${error.message}`);
|
console.error("err in fetching extUser", err);
|
||||||
console.log(error);
|
showToast("danger", `${err.message}`);
|
||||||
|
const payload = { sessionToken: _user.sessionToken };
|
||||||
|
handleSubmitbtn(payload);
|
||||||
} finally {
|
} finally {
|
||||||
setThirdpartyLoader(false);
|
setThirdpartyLoader(false);
|
||||||
}
|
}
|
||||||
@@ -227,14 +213,7 @@ function Login() {
|
|||||||
try {
|
try {
|
||||||
const user = await Parse.User.become(localStorage.getItem("accesstoken"));
|
const user = await Parse.User.become(localStorage.getItem("accesstoken"));
|
||||||
const _user = user.toJSON();
|
const _user = user.toJSON();
|
||||||
localStorage.setItem("UserInformation", JSON.stringify(_user));
|
setLocalVar(_user);
|
||||||
localStorage.setItem("accesstoken", _user.sessionToken);
|
|
||||||
localStorage.setItem("scriptId", true);
|
|
||||||
if (_user.ProfilePic) {
|
|
||||||
localStorage.setItem("profileImg", _user.ProfilePic);
|
|
||||||
} else {
|
|
||||||
localStorage.setItem("profileImg", "");
|
|
||||||
}
|
|
||||||
const userSettings = appInfo.settings;
|
const userSettings = appInfo.settings;
|
||||||
const extUser = await Parse.Cloud.run("getUserDetails");
|
const extUser = await Parse.Cloud.run("getUserDetails");
|
||||||
if (extUser) {
|
if (extUser) {
|
||||||
@@ -245,14 +224,12 @@ function Login() {
|
|||||||
const menu =
|
const menu =
|
||||||
userRole && userSettings.find((menu) => menu.role === userRole);
|
userRole && userSettings.find((menu) => menu.role === userRole);
|
||||||
if (menu) {
|
if (menu) {
|
||||||
|
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||||
const _role = _currentRole.replace("contracts_", "");
|
const _role = _currentRole.replace("contracts_", "");
|
||||||
localStorage.setItem("_user_role", _role);
|
localStorage.setItem("_user_role", _role);
|
||||||
const redirectUrl =
|
const redirectUrl =
|
||||||
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
||||||
const results = [extUser];
|
localStorage.setItem("Extand_Class", JSON.stringify([extUser]));
|
||||||
const extendedInfo_stringify = JSON.stringify(results);
|
|
||||||
localStorage.setItem("Extand_Class", extendedInfo_stringify);
|
|
||||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
|
||||||
localStorage.setItem("userEmail", extInfo.Email);
|
localStorage.setItem("userEmail", extInfo.Email);
|
||||||
localStorage.setItem("username", extInfo.Name);
|
localStorage.setItem("username", extInfo.Name);
|
||||||
if (extInfo?.TenantId) {
|
if (extInfo?.TenantId) {
|
||||||
@@ -267,8 +244,7 @@ function Login() {
|
|||||||
localStorage.setItem("PageLanding", menu.pageId);
|
localStorage.setItem("PageLanding", menu.pageId);
|
||||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||||
localStorage.setItem("pageType", menu.pageType);
|
localStorage.setItem("pageType", menu.pageType);
|
||||||
// Redirect to the appropriate URL after successful login
|
navigate(redirectUrl);
|
||||||
navigate(redirectUrl);
|
|
||||||
} else {
|
} else {
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
logOutUser();
|
logOutUser();
|
||||||
@@ -377,18 +353,15 @@ function Login() {
|
|||||||
const _currentRole = userRole;
|
const _currentRole = userRole;
|
||||||
const redirectUrl =
|
const redirectUrl =
|
||||||
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
||||||
let _role = _currentRole.replace("contracts_", "");
|
const _role = _currentRole.replace("contracts_", "");
|
||||||
localStorage.setItem("_user_role", _role);
|
localStorage.setItem("_user_role", _role);
|
||||||
const checkLanguage = extUser?.get("Language");
|
const checkLanguage = extUser?.get("Language");
|
||||||
if (checkLanguage) {
|
if (checkLanguage) {
|
||||||
checkLanguage && i18n.changeLanguage(checkLanguage);
|
checkLanguage && i18n.changeLanguage(checkLanguage);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Continue with storing user data and redirecting
|
|
||||||
const results = [extUser];
|
|
||||||
const extUser_str = JSON.stringify(results);
|
|
||||||
localStorage.setItem("Extand_Class", extUser_str);
|
|
||||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||||
|
// Continue with storing user data and redirecting
|
||||||
|
localStorage.setItem("Extand_Class", JSON.stringify([extUser]));
|
||||||
localStorage.setItem("userEmail", extInfo.Email);
|
localStorage.setItem("userEmail", extInfo.Email);
|
||||||
localStorage.setItem("username", extInfo.Name);
|
localStorage.setItem("username", extInfo.Name);
|
||||||
if (extInfo?.TenantId) {
|
if (extInfo?.TenantId) {
|
||||||
@@ -403,9 +376,8 @@ function Login() {
|
|||||||
localStorage.setItem("PageLanding", menu.pageId);
|
localStorage.setItem("PageLanding", menu.pageId);
|
||||||
localStorage.setItem("defaultmenuid", menu.menuId);
|
localStorage.setItem("defaultmenuid", menu.menuId);
|
||||||
localStorage.setItem("pageType", menu.pageType);
|
localStorage.setItem("pageType", menu.pageType);
|
||||||
|
setState({ ...state, loading: false });
|
||||||
setState({ ...state, loading: false });
|
navigate(redirectUrl);
|
||||||
navigate(redirectUrl);
|
|
||||||
} else {
|
} else {
|
||||||
setState({ ...state, loading: false });
|
setState({ ...state, loading: false });
|
||||||
setIsModal(true);
|
setIsModal(true);
|
||||||
@@ -415,8 +387,8 @@ function Login() {
|
|||||||
logOutUser();
|
logOutUser();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
showToast("danger", t("user-not-found"));
|
showToast("danger", t("user-not-found"));
|
||||||
logOutUser();
|
logOutUser();
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error during login flow", error);
|
console.error("Error during login flow", error);
|
||||||
@@ -483,35 +455,39 @@ function Login() {
|
|||||||
onInput={(e) => e.target.setCustomValidity("")}
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
/>
|
/>
|
||||||
<hr className="my-1 border-none" />
|
<hr className="my-1 border-none" />
|
||||||
<label className="block text-xs" htmlFor="password">
|
<label className="block text-xs" htmlFor="password">
|
||||||
{t("password")}
|
{t("password")}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
id="password"
|
id="password"
|
||||||
type={state.passwordVisible ? "text" : "password"}
|
type={
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
state.passwordVisible ? "text" : "password"
|
||||||
name="password"
|
}
|
||||||
value={state.password}
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
autoComplete="current-password"
|
name="password"
|
||||||
onChange={handleChange}
|
value={state.password}
|
||||||
onInvalid={(e) =>
|
autoComplete="current-password"
|
||||||
e.target.setCustomValidity(t("input-required"))
|
onChange={handleChange}
|
||||||
}
|
onInvalid={(e) =>
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
e.target.setCustomValidity(
|
||||||
required
|
t("input-required")
|
||||||
/>
|
)
|
||||||
<span
|
}
|
||||||
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
onClick={togglePasswordVisibility}
|
required
|
||||||
>
|
/>
|
||||||
{state.passwordVisible ? (
|
<span
|
||||||
<i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon
|
className="absolute cursor-pointer top-[50%] right-[10px] -translate-y-[50%] text-base-content"
|
||||||
) : (
|
onClick={togglePasswordVisibility}
|
||||||
<i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
|
>
|
||||||
)}
|
{state.passwordVisible ? (
|
||||||
</span>
|
<i className="fa-light fa-eye-slash text-xs pb-1" /> // Close eye icon
|
||||||
</div>
|
) : (
|
||||||
|
<i className="fa-light fa-eye text-xs pb-1 " /> // Open eye icon
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="relative mt-1">
|
<div className="relative mt-1">
|
||||||
<NavLink
|
<NavLink
|
||||||
+12
-13
@@ -1,7 +1,11 @@
|
|||||||
import React, { useEffect, useState, useRef } from "react";
|
import React, { useEffect, useState, useRef } from "react";
|
||||||
import "../styles/opensigndrive.css";
|
import "../styles/opensigndrive.css";
|
||||||
import { iconColor } from "../constant/const";
|
import {
|
||||||
import { getDrive } from "../constant/Utils";
|
iconColor,
|
||||||
|
} from "../constant/const";
|
||||||
|
import {
|
||||||
|
getDrive
|
||||||
|
} from "../constant/Utils";
|
||||||
import { useNavigate } from "react-router";
|
import { useNavigate } from "react-router";
|
||||||
import Title from "../components/Title";
|
import Title from "../components/Title";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
@@ -25,7 +29,8 @@ const AppLoader = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
function Opensigndrive() {
|
function Opensigndrive() {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -128,7 +133,7 @@ function Opensigndrive() {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
const getDetails = async () => {
|
const getDetails = async () => {
|
||||||
getPdfDocumentList();
|
getPdfDocumentList();
|
||||||
};
|
};
|
||||||
//function for get all pdf document list
|
//function for get all pdf document list
|
||||||
const getPdfDocumentList = async (disbaleLoading) => {
|
const getPdfDocumentList = async (disbaleLoading) => {
|
||||||
@@ -669,9 +674,7 @@ function Opensigndrive() {
|
|||||||
</button>
|
</button>
|
||||||
<div
|
<div
|
||||||
id="folder-menu"
|
id="folder-menu"
|
||||||
className={`${
|
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} hidden md:block cursor-pointer hover:bg-gray-200 p-2 rounded-md`}
|
||||||
isOptions ? "dropdown show dropDownStyle" : "dropdown"
|
|
||||||
} hidden md:block cursor-pointer hover:bg-gray-200 p-2 rounded-md`}
|
|
||||||
onClick={() => setIsOptions(!isOptions)}
|
onClick={() => setIsOptions(!isOptions)}
|
||||||
>
|
>
|
||||||
<div data-tut="reactourSecond">
|
<div data-tut="reactourSecond">
|
||||||
@@ -789,18 +792,14 @@ function Opensigndrive() {
|
|||||||
onClick={() => setIsList(!isList)}
|
onClick={() => setIsList(!isList)}
|
||||||
>
|
>
|
||||||
<i
|
<i
|
||||||
className={`${
|
className={`${isList ? "fa-light fa-th-large" : "fa-light fa-list"} text-[20px]`}
|
||||||
isList ? "fa-light fa-th-large" : "fa-light fa-list"
|
|
||||||
} text-[20px]`}
|
|
||||||
style={{ color: `${iconColor}` }}
|
style={{ color: `${iconColor}` }}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
></i>
|
></i>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
id="folder-menu"
|
id="folder-menu"
|
||||||
className={`${
|
className={`${isOptions ? "dropdown show dropDownStyle" : "dropdown"} md:hidden`}
|
||||||
isOptions ? "dropdown show dropDownStyle" : "dropdown"
|
|
||||||
} md:hidden`}
|
|
||||||
onClick={() => setIsOptions(!isOptions)}
|
onClick={() => setIsOptions(!isOptions)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
+666
-599
File diff suppressed because it is too large
Load Diff
+83
-45
@@ -3,7 +3,9 @@ import axios from "axios";
|
|||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import "../styles/signature.css";
|
import "../styles/signature.css";
|
||||||
import { PDFDocument } from "pdf-lib";
|
import { PDFDocument } from "pdf-lib";
|
||||||
import { maxTitleLength } from "../constant/const";
|
import {
|
||||||
|
maxTitleLength
|
||||||
|
} from "../constant/const";
|
||||||
import { DndProvider } from "react-dnd";
|
import { DndProvider } from "react-dnd";
|
||||||
import { HTML5Backend } from "react-dnd-html5-backend";
|
import { HTML5Backend } from "react-dnd-html5-backend";
|
||||||
import { useDrop } from "react-dnd";
|
import { useDrop } from "react-dnd";
|
||||||
@@ -70,7 +72,8 @@ import AddContact from "../primitives/AddContact";
|
|||||||
function PlaceHolderSign() {
|
function PlaceHolderSign() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const copyUrlRef = useRef(null);
|
const copyUrlRef = useRef(null);
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const editorRef = useRef();
|
const editorRef = useRef();
|
||||||
const { state } = useLocation();
|
const { state } = useLocation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -869,7 +872,11 @@ function PlaceHolderSign() {
|
|||||||
scale
|
scale
|
||||||
);
|
);
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64, "");
|
const pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64,
|
||||||
|
"",
|
||||||
|
);
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
const buffer = atob(pdfBase64);
|
const buffer = atob(pdfBase64);
|
||||||
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
||||||
@@ -881,7 +888,11 @@ function PlaceHolderSign() {
|
|||||||
} else if (pdfBase64Url) {
|
} else if (pdfBase64Url) {
|
||||||
try {
|
try {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
const pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
return pdfUrl;
|
return pdfUrl;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("error to convertBase64ToFile in placeholder flow", err);
|
console.log("error to convertBase64ToFile in placeholder flow", err);
|
||||||
@@ -987,7 +998,11 @@ function PlaceHolderSign() {
|
|||||||
let pdfUrl;
|
let pdfUrl;
|
||||||
if (isUploadPdf) {
|
if (isUploadPdf) {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const docCls = new Parse.Object("contracts_Document");
|
const docCls = new Parse.Object("contracts_Document");
|
||||||
@@ -1058,9 +1073,7 @@ function PlaceHolderSign() {
|
|||||||
ExpiryDate: { iso: updateExpiryDate, __type: "Date" }
|
ExpiryDate: { iso: updateExpiryDate, __type: "Date" }
|
||||||
};
|
};
|
||||||
await axios.put(
|
await axios.put(
|
||||||
`${localStorage.getItem(
|
`${localStorage.getItem("baseUrl")}classes/contracts_Document/${documentId}`,
|
||||||
"baseUrl"
|
|
||||||
)}classes/contracts_Document/${documentId}`,
|
|
||||||
data,
|
data,
|
||||||
{
|
{
|
||||||
headers: {
|
headers: {
|
||||||
@@ -1152,7 +1165,8 @@ function PlaceHolderSign() {
|
|||||||
year: "numeric"
|
year: "numeric"
|
||||||
});
|
});
|
||||||
|
|
||||||
let senderEmail = pdfDetails?.[0]?.ExtUserPtr?.Email;
|
let senderEmail =
|
||||||
|
pdfDetails?.[0]?.ExtUserPtr?.Email;
|
||||||
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
||||||
let signerMail = signersdata.slice();
|
let signerMail = signersdata.slice();
|
||||||
|
|
||||||
@@ -1178,11 +1192,16 @@ function PlaceHolderSign() {
|
|||||||
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
||||||
? pdfDetails[0].ExtUserPtr.Company
|
? pdfDetails[0].ExtUserPtr.Company
|
||||||
: "";
|
: "";
|
||||||
const senderName = pdfDetails?.[0].ExtUserPtr.Name;
|
const senderName =
|
||||||
|
pdfDetails?.[0].ExtUserPtr.Name;
|
||||||
const documentName = `${pdfDetails?.[0].Name}`;
|
const documentName = `${pdfDetails?.[0].Name}`;
|
||||||
let replaceVar;
|
let replaceVar;
|
||||||
|
|
||||||
if (requestBody && requestSubject && isCustomize) {
|
if (
|
||||||
|
requestBody &&
|
||||||
|
requestSubject &&
|
||||||
|
isCustomize
|
||||||
|
) {
|
||||||
const replacedRequestBody = requestBody.replace(/"/g, "'");
|
const replacedRequestBody = requestBody.replace(/"/g, "'");
|
||||||
htmlReqBody =
|
htmlReqBody =
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
||||||
@@ -1207,7 +1226,10 @@ function PlaceHolderSign() {
|
|||||||
htmlReqBody,
|
htmlReqBody,
|
||||||
variables
|
variables
|
||||||
);
|
);
|
||||||
} else if (tenantMailTemplate?.body && tenantMailTemplate?.subject) {
|
} else if (
|
||||||
|
tenantMailTemplate?.body &&
|
||||||
|
tenantMailTemplate?.subject
|
||||||
|
) {
|
||||||
const mailBody = tenantMailTemplate?.body;
|
const mailBody = tenantMailTemplate?.body;
|
||||||
const mailSubject = tenantMailTemplate?.subject;
|
const mailSubject = tenantMailTemplate?.subject;
|
||||||
const replacedRequestBody = mailBody.replace(/"/g, "'");
|
const replacedRequestBody = mailBody.replace(/"/g, "'");
|
||||||
@@ -1246,7 +1268,8 @@ function PlaceHolderSign() {
|
|||||||
? replaceVar?.subject
|
? replaceVar?.subject
|
||||||
: mailTemplate(mailparam).subject,
|
: mailTemplate(mailparam).subject,
|
||||||
replyto: senderEmail,
|
replyto: senderEmail,
|
||||||
from: senderEmail,
|
from:
|
||||||
|
senderEmail,
|
||||||
html: replaceVar?.body
|
html: replaceVar?.body
|
||||||
? replaceVar?.body
|
? replaceVar?.body
|
||||||
: mailTemplate(mailparam).body
|
: mailTemplate(mailparam).body
|
||||||
@@ -1261,13 +1284,20 @@ function PlaceHolderSign() {
|
|||||||
setMailStatus("success");
|
setMailStatus("success");
|
||||||
try {
|
try {
|
||||||
let data;
|
let data;
|
||||||
if (requestBody && requestSubject && isCustomize) {
|
if (
|
||||||
|
requestBody &&
|
||||||
|
requestSubject &&
|
||||||
|
isCustomize
|
||||||
|
) {
|
||||||
data = {
|
data = {
|
||||||
RequestBody: htmlReqBody,
|
RequestBody: htmlReqBody,
|
||||||
RequestSubject: requestSubject,
|
RequestSubject: requestSubject,
|
||||||
SendMail: true
|
SendMail: true
|
||||||
};
|
};
|
||||||
} else if (tenantMailTemplate?.body && tenantMailTemplate?.subject) {
|
} else if (
|
||||||
|
tenantMailTemplate?.body &&
|
||||||
|
tenantMailTemplate?.subject
|
||||||
|
) {
|
||||||
data = {
|
data = {
|
||||||
RequestBody: tenantMailTemplate?.body,
|
RequestBody: tenantMailTemplate?.body,
|
||||||
RequestSubject: tenantMailTemplate?.subject,
|
RequestSubject: tenantMailTemplate?.subject,
|
||||||
@@ -1305,7 +1335,8 @@ function PlaceHolderSign() {
|
|||||||
setIsSend(true);
|
setIsSend(true);
|
||||||
setIsMailSend(true);
|
setIsMailSend(true);
|
||||||
setIsUiLoading(false);
|
setIsUiLoading(false);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
setMailStatus("failed");
|
setMailStatus("failed");
|
||||||
setIsSend(true);
|
setIsSend(true);
|
||||||
setIsMailSend(true);
|
setIsMailSend(true);
|
||||||
@@ -1546,7 +1577,8 @@ function PlaceHolderSign() {
|
|||||||
status: defaultdata?.status || "required",
|
status: defaultdata?.status || "required",
|
||||||
hint: defaultdata?.hint || "",
|
hint: defaultdata?.hint || "",
|
||||||
defaultValue: defaultdata?.defaultValue || "",
|
defaultValue: defaultdata?.defaultValue || "",
|
||||||
validation: {},
|
validation:
|
||||||
|
{},
|
||||||
fontSize:
|
fontSize:
|
||||||
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
||||||
fontColor:
|
fontColor:
|
||||||
@@ -2029,26 +2061,30 @@ function PlaceHolderSign() {
|
|||||||
{!isCustomize && (
|
{!isCustomize && (
|
||||||
<span>{t("placeholder-alert-3")}</span>
|
<span>{t("placeholder-alert-3")}</span>
|
||||||
)}
|
)}
|
||||||
{isCustomize && (
|
{
|
||||||
<>
|
isCustomize && (
|
||||||
<EmailBody
|
<>
|
||||||
editorRef={editorRef}
|
<EmailBody
|
||||||
requestBody={requestBody}
|
editorRef={editorRef}
|
||||||
requestSubject={requestSubject}
|
requestBody={requestBody}
|
||||||
handleOnchangeRequest={handleOnchangeRequest}
|
requestSubject={requestSubject}
|
||||||
setRequestSubject={setRequestSubject}
|
handleOnchangeRequest={
|
||||||
/>
|
handleOnchangeRequest
|
||||||
<div
|
}
|
||||||
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
|
setRequestSubject={setRequestSubject}
|
||||||
onClick={() => {
|
/>
|
||||||
setRequestBody(defaultBody);
|
<div
|
||||||
setRequestSubject(defaultSubject);
|
className="flex justify-end items-center gap-1 mt-2 op-link op-link-primary"
|
||||||
}}
|
onClick={() => {
|
||||||
>
|
setRequestBody(defaultBody);
|
||||||
<span>{t("reset-to-default")}</span>
|
setRequestSubject(defaultSubject);
|
||||||
</div>
|
}}
|
||||||
</>
|
>
|
||||||
)}
|
<span>{t("reset-to-default")}</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
<div className="flex flex-row items-center gap-2 md:gap-6 mt-2">
|
<div className="flex flex-row items-center gap-2 md:gap-6 mt-2">
|
||||||
<div className="flex flex-row gap-2">
|
<div className="flex flex-row gap-2">
|
||||||
<button
|
<button
|
||||||
@@ -2066,14 +2102,16 @@ function PlaceHolderSign() {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!isCustomize && (
|
{
|
||||||
<span
|
!isCustomize && (
|
||||||
className="op-link op-link-accent text-sm"
|
<span
|
||||||
onClick={() => setIsCustomize(!isCustomize)}
|
className="op-link op-link-accent text-sm"
|
||||||
>
|
onClick={() => setIsCustomize(!isCustomize)}
|
||||||
{t("cutomize-email")}
|
>
|
||||||
</span>
|
{t("cutomize-email")}
|
||||||
)}
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -23,7 +23,8 @@ import EditorToolbar, {
|
|||||||
import DateFormatSelector from "../components/shared/fields/DateFormatSelector";
|
import DateFormatSelector from "../components/shared/fields/DateFormatSelector";
|
||||||
|
|
||||||
const Preferences = () => {
|
const Preferences = () => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const editorRef = useRef();
|
const editorRef = useRef();
|
||||||
const editorRefCom = useRef();
|
const editorRefCom = useRef();
|
||||||
@@ -44,7 +45,11 @@ const Preferences = () => {
|
|||||||
const [isNotifyOnSignatures, setIsNotifyOnSignatures] = useState();
|
const [isNotifyOnSignatures, setIsNotifyOnSignatures] = useState();
|
||||||
const [timezone, setTimezone] = useState(usertimezone);
|
const [timezone, setTimezone] = useState(usertimezone);
|
||||||
const [activeTab, setactiveTab] = useState(0);
|
const [activeTab, setactiveTab] = useState(0);
|
||||||
const generaltab = { title: t("general"), icon: "fa-light fa-gears" };
|
const generaltab = {
|
||||||
|
name: "general",
|
||||||
|
title: t("general"),
|
||||||
|
icon: "fa-light fa-gears"
|
||||||
|
};
|
||||||
const [tab, setTab] = useState([generaltab]);
|
const [tab, setTab] = useState([generaltab]);
|
||||||
const [sendinOrder, setSendinOrder] = useState(true);
|
const [sendinOrder, setSendinOrder] = useState(true);
|
||||||
const [isTourEnabled, setIsTourEnabled] = useState(false);
|
const [isTourEnabled, setIsTourEnabled] = useState(false);
|
||||||
@@ -60,9 +65,12 @@ const Preferences = () => {
|
|||||||
setIsTopLoader(true);
|
setIsTopLoader(true);
|
||||||
const EmailTab =
|
const EmailTab =
|
||||||
extClass?.[0]?.UserRole === "contracts_Admin"
|
extClass?.[0]?.UserRole === "contracts_Admin"
|
||||||
? [{ title: t("email"), icon: "fa-light fa-envelope" }]
|
? [{ name: "email", title: t("email"), icon: "fa-light fa-envelope" }]
|
||||||
: [];
|
: [];
|
||||||
const arr = [generaltab, ...EmailTab];
|
const arr = [
|
||||||
|
generaltab,
|
||||||
|
...EmailTab,
|
||||||
|
];
|
||||||
setTab(arr);
|
setTab(arr);
|
||||||
try {
|
try {
|
||||||
const user = JSON.parse(
|
const user = JSON.parse(
|
||||||
@@ -326,7 +334,7 @@ const Preferences = () => {
|
|||||||
|
|
||||||
const handleTourInput = () => setIsTourEnabled(!isTourEnabled);
|
const handleTourInput = () => setIsTourEnabled(!isTourEnabled);
|
||||||
const handleSendinOrderInput = () => setSendinOrder(!sendinOrder);
|
const handleSendinOrderInput = () => setSendinOrder(!sendinOrder);
|
||||||
|
const tabName = (ind) => tab.find((t, i) => i === ind)?.name;
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Title title={t("Preferences")} />
|
<Title title={t("Preferences")} />
|
||||||
@@ -364,9 +372,7 @@ const Preferences = () => {
|
|||||||
onClick={() => setactiveTab(ind)}
|
onClick={() => setactiveTab(ind)}
|
||||||
key={ind}
|
key={ind}
|
||||||
role="tab"
|
role="tab"
|
||||||
className={`${
|
className={`${activeTab === ind ? "op-tab-active" : ""} op-tab text-xs md:text-base pb-2 md:pb-0 transition-all `}
|
||||||
activeTab === ind ? "op-tab-active" : ""
|
|
||||||
} op-tab text-xs md:text-base pb-2 md:pb-0 transition-all `}
|
|
||||||
aria-selected={activeTab === ind}
|
aria-selected={activeTab === ind}
|
||||||
aria-controls={`panel-${tabData.title}`}
|
aria-controls={`panel-${tabData.title}`}
|
||||||
>
|
>
|
||||||
@@ -382,7 +388,7 @@ const Preferences = () => {
|
|||||||
aria-labelledby="tab-general"
|
aria-labelledby="tab-general"
|
||||||
role="tabpanel"
|
role="tabpanel"
|
||||||
>
|
>
|
||||||
{activeTab === 0 ? (
|
{tabName(activeTab) === "general" && (
|
||||||
<div className="grid grid-cols-1 md:grid-cols-12 md:gap-x-8">
|
<div className="grid grid-cols-1 md:grid-cols-12 md:gap-x-8">
|
||||||
{/* Left Column - Signature Settings */}
|
{/* Left Column - Signature Settings */}
|
||||||
<div className="md:col-span-5 flex flex-col">
|
<div className="md:col-span-5 flex flex-col">
|
||||||
@@ -487,7 +493,11 @@ const Preferences = () => {
|
|||||||
</ReactTooltip>
|
</ReactTooltip>
|
||||||
</label>
|
</label>
|
||||||
<div className="flex flex-row gap-6">
|
<div className="flex flex-row gap-6">
|
||||||
<div className={"flex items-center gap-2"}>
|
<div
|
||||||
|
className={
|
||||||
|
"flex items-center gap-2"
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
id="notify-yes"
|
id="notify-yes"
|
||||||
className="op-radio op-radio-xs"
|
className="op-radio op-radio-xs"
|
||||||
@@ -502,7 +512,11 @@ const Preferences = () => {
|
|||||||
{t("yes")}
|
{t("yes")}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div className={"flex items-center gap-2"}>
|
<div
|
||||||
|
className={
|
||||||
|
"flex items-center gap-2"
|
||||||
|
}
|
||||||
|
>
|
||||||
<input
|
<input
|
||||||
id="notify-no"
|
id="notify-no"
|
||||||
className="op-radio op-radio-xs"
|
className="op-radio op-radio-xs"
|
||||||
@@ -706,7 +720,8 @@ const Preferences = () => {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : activeTab === 1 ? (
|
)}
|
||||||
|
{tabName(activeTab) === "email" && (
|
||||||
<div className="flex flex-col mb-4">
|
<div className="flex flex-col mb-4">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<h1 className="text-[14px] mb-[0.7rem] font-medium">
|
<h1 className="text-[14px] mb-[0.7rem] font-medium">
|
||||||
@@ -722,9 +737,7 @@ const Preferences = () => {
|
|||||||
{t("subject")}{" "}
|
{t("subject")}{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={"request-sub-tooltip"}
|
id={"request-sub-tooltip"}
|
||||||
message={`${t(
|
message={`${t("variables-use")}: {{sender_name}} {{document_title}}`}
|
||||||
"variables-use"
|
|
||||||
)}: {{sender_name}} {{document_title}}`}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -733,9 +746,7 @@ const Preferences = () => {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setRequestSubject(e.target.value)
|
setRequestSubject(e.target.value)
|
||||||
}
|
}
|
||||||
placeholder={`{{sender_name}} ${t(
|
placeholder={`{{sender_name}} ${t("send-to-sign")} {{document_title}}`}
|
||||||
"send-to-sign"
|
|
||||||
)} {{document_title}}`}
|
|
||||||
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -744,9 +755,7 @@ const Preferences = () => {
|
|||||||
{t("body")}{" "}
|
{t("body")}{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={"request-body-tooltip"}
|
id={"request-body-tooltip"}
|
||||||
message={`${t(
|
message={`${t("variables-use")}: {{sender_name}} {{document_title}}`}
|
||||||
"variables-use"
|
|
||||||
)}: {{sender_name}} {{document_title}}`}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<EditorToolbar containerId="toolbar1" />
|
<EditorToolbar containerId="toolbar1" />
|
||||||
@@ -792,9 +801,7 @@ const Preferences = () => {
|
|||||||
{t("subject")}{" "}
|
{t("subject")}{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={"complete-sub-tooltip"}
|
id={"complete-sub-tooltip"}
|
||||||
message={`${t(
|
message={`${t("variables-use")}:{{sender_name}} {{document_title}}`}
|
||||||
"variables-use"
|
|
||||||
)}:{{sender_name}} {{document_title}}`}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
@@ -803,9 +810,7 @@ const Preferences = () => {
|
|||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
setCompletionSubject(e.target.value)
|
setCompletionSubject(e.target.value)
|
||||||
}
|
}
|
||||||
placeholder={`{{sender_name}} ${t(
|
placeholder={`{{sender_name}} ${t("send-to-sign")} {{document_title}}`}
|
||||||
"send-to-sign"
|
|
||||||
)} {{document_title}}`}
|
|
||||||
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
className="w-full op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content text-xs"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -814,9 +819,7 @@ const Preferences = () => {
|
|||||||
{t("body")}{" "}
|
{t("body")}{" "}
|
||||||
<Tooltip
|
<Tooltip
|
||||||
id={"complete-body-tooltip"}
|
id={"complete-body-tooltip"}
|
||||||
message={`${t(
|
message={`${t("variables-use")}:{{sender_name}} {{document_title}} {{signing_url}}`}
|
||||||
"variables-use"
|
|
||||||
)}:{{sender_name}} {{document_title}} {{signing_url}}`}
|
|
||||||
/>
|
/>
|
||||||
</label>
|
</label>
|
||||||
<EditorToolbar containerId="toolbar2" />
|
<EditorToolbar containerId="toolbar2" />
|
||||||
@@ -851,8 +854,10 @@ const Preferences = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
)}
|
||||||
<></>
|
{tabName(activeTab) === "security" && (
|
||||||
|
<>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
+12
-4
@@ -67,7 +67,8 @@ import LoaderWithMsg from "../primitives/LoaderWithMsg";
|
|||||||
function SignYourSelf() {
|
function SignYourSelf() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { docId } = useParams();
|
const { docId } = useParams();
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const divRef = useRef(null);
|
const divRef = useRef(null);
|
||||||
const nodeRef = useRef(null);
|
const nodeRef = useRef(null);
|
||||||
const imageRef = useRef(null);
|
const imageRef = useRef(null);
|
||||||
@@ -520,7 +521,11 @@ function SignYourSelf() {
|
|||||||
let pdfUrl;
|
let pdfUrl;
|
||||||
if (isUploadPdf) {
|
if (isUploadPdf) {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const widgetsType = ["signature", "stamp", "image", "initials"];
|
const widgetsType = ["signature", "stamp", "image", "initials"];
|
||||||
let updatedXYPosition;
|
let updatedXYPosition;
|
||||||
@@ -706,7 +711,10 @@ function SignYourSelf() {
|
|||||||
if (tenantDetails && tenantDetails === "user does not exist!") {
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
alert(t("user-not-exist"));
|
alert(t("user-not-exist"));
|
||||||
} else {
|
} else {
|
||||||
if (tenantDetails?.CompletionBody && tenantDetails?.CompletionSubject) {
|
if (
|
||||||
|
tenantDetails?.CompletionBody &&
|
||||||
|
tenantDetails?.CompletionSubject
|
||||||
|
) {
|
||||||
isCustomCompletionMail = true;
|
isCustomCompletionMail = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -742,7 +750,7 @@ function SignYourSelf() {
|
|||||||
pdfFile: base64Url,
|
pdfFile: base64Url,
|
||||||
docId: documentId,
|
docId: documentId,
|
||||||
isCustomCompletionMail: isCustomCompletionMail,
|
isCustomCompletionMail: isCustomCompletionMail,
|
||||||
signature: suffixbase64
|
signature: suffixbase64,
|
||||||
};
|
};
|
||||||
const resSignPdf = await Parse.Cloud.run("signPdf", params);
|
const resSignPdf = await Parse.Cloud.run("signPdf", params);
|
||||||
if (resSignPdf) {
|
if (resSignPdf) {
|
||||||
+19
-5
@@ -166,6 +166,7 @@ const TemplatePlaceholder = () => {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [divRef.current, isHeader]);
|
}, [divRef.current, isHeader]);
|
||||||
|
|
||||||
|
|
||||||
//function to fetch tenant Details
|
//function to fetch tenant Details
|
||||||
const fetchTenantDetails = async () => {
|
const fetchTenantDetails = async () => {
|
||||||
const user = JSON.parse(
|
const user = JSON.parse(
|
||||||
@@ -777,7 +778,11 @@ const TemplatePlaceholder = () => {
|
|||||||
let pdfUrl;
|
let pdfUrl;
|
||||||
if (isUploadPdf) {
|
if (isUploadPdf) {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (signersdata?.length > 0) {
|
if (signersdata?.length > 0) {
|
||||||
signersdata.forEach((x) => {
|
signersdata.forEach((x) => {
|
||||||
@@ -844,7 +849,11 @@ const TemplatePlaceholder = () => {
|
|||||||
scale
|
scale
|
||||||
);
|
);
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64, "");
|
const pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64,
|
||||||
|
"",
|
||||||
|
);
|
||||||
const tenantId = localStorage.getItem("TenantId");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
const buffer = atob(pdfBase64);
|
const buffer = atob(pdfBase64);
|
||||||
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
SaveFileSize(buffer.length, pdfUrl, tenantId);
|
||||||
@@ -856,7 +865,11 @@ const TemplatePlaceholder = () => {
|
|||||||
} else if (pdfBase64Url) {
|
} else if (pdfBase64Url) {
|
||||||
try {
|
try {
|
||||||
const pdfName = generatePdfName(16);
|
const pdfName = generatePdfName(16);
|
||||||
const pdfUrl = await convertBase64ToFile(pdfName, pdfBase64Url, "");
|
const pdfUrl = await convertBase64ToFile(
|
||||||
|
pdfName,
|
||||||
|
pdfBase64Url,
|
||||||
|
"",
|
||||||
|
);
|
||||||
return pdfUrl;
|
return pdfUrl;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("error to convertBase64ToFile in placeholder flow", err);
|
console.log("error to convertBase64ToFile in placeholder flow", err);
|
||||||
@@ -1280,7 +1293,6 @@ const TemplatePlaceholder = () => {
|
|||||||
const handleCloseRoleModal = () => {
|
const handleCloseRoleModal = () => {
|
||||||
setIsModalRole(false);
|
setIsModalRole(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSaveWidgetsOptions = (
|
const handleSaveWidgetsOptions = (
|
||||||
dropdownName,
|
dropdownName,
|
||||||
dropdownOptions,
|
dropdownOptions,
|
||||||
@@ -1457,7 +1469,9 @@ const TemplatePlaceholder = () => {
|
|||||||
status: defaultdata?.status || "required",
|
status: defaultdata?.status || "required",
|
||||||
hint: defaultdata?.hint || "",
|
hint: defaultdata?.hint || "",
|
||||||
defaultValue: defaultdata?.defaultValue || "",
|
defaultValue: defaultdata?.defaultValue || "",
|
||||||
validation: {},
|
isReadOnly: defaultdata?.isReadOnly || false,
|
||||||
|
validation:
|
||||||
|
{},
|
||||||
fontSize:
|
fontSize:
|
||||||
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
fontSize || currWidgetsDetails?.options?.fontSize || 12,
|
||||||
fontColor:
|
fontColor:
|
||||||
+2
-1
@@ -7,7 +7,8 @@ import Title from "../components/Title";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { emailRegex } from "../constant/const";
|
import { emailRegex } from "../constant/const";
|
||||||
const UpdateExistUserAdmin = () => {
|
const UpdateExistUserAdmin = () => {
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const [formdata, setFormdata] = useState({ email: "", masterkey: "" });
|
const [formdata, setFormdata] = useState({ email: "", masterkey: "" });
|
||||||
@@ -1,394 +0,0 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
|
||||||
import Parse from "parse";
|
|
||||||
import Alert from "../primitives/Alert";
|
|
||||||
import Loader from "../primitives/Loader";
|
|
||||||
import { useLocation } from "react-router";
|
|
||||||
import ModalUi from "../primitives/ModalUi";
|
|
||||||
import pad from "../assets/images/pad.svg";
|
|
||||||
import Tooltip from "../primitives/Tooltip";
|
|
||||||
import AddUser from "../components/AddUser";
|
|
||||||
import Title from "../components/Title";
|
|
||||||
import { useTranslation } from "react-i18next";
|
|
||||||
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
|
||||||
const UserList = () => {
|
|
||||||
const { t } = useTranslation();
|
|
||||||
const [userList, setUserList] = useState([]);
|
|
||||||
const [isLoader, setIsLoader] = useState(false);
|
|
||||||
const [isModal, setIsModal] = useState({
|
|
||||||
form: false,
|
|
||||||
addseats: false,
|
|
||||||
options: false
|
|
||||||
});
|
|
||||||
const location = useLocation();
|
|
||||||
const isDashboard =
|
|
||||||
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
|
|
||||||
const [currentPage, setCurrentPage] = useState(1);
|
|
||||||
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
|
||||||
const [isActiveModal, setIsActiveModal] = useState({});
|
|
||||||
const [isActLoader, setIsActLoader] = useState({});
|
|
||||||
const [isAdmin, setIsAdmin] = useState(false);
|
|
||||||
const [formHeader, setFormHeader] = useState(t("add-user"));
|
|
||||||
const recordperPage = 10;
|
|
||||||
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
|
||||||
|
|
||||||
const getPaginationRange = () => {
|
|
||||||
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
|
|
||||||
const pages = [];
|
|
||||||
const totalPages = Math.ceil(userList.length / recordperPage);
|
|
||||||
if (totalPages <= totalPageNumbers) {
|
|
||||||
for (let i = 1; i <= totalPages; i++) {
|
|
||||||
pages.push(i);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const leftSiblingIndex = Math.max(currentPage - 1, 1);
|
|
||||||
const rightSiblingIndex = Math.min(currentPage + 1, totalPages);
|
|
||||||
|
|
||||||
const showLeftDots = leftSiblingIndex > 2;
|
|
||||||
const showRightDots = rightSiblingIndex < totalPages - 2;
|
|
||||||
|
|
||||||
const firstPageIndex = 1;
|
|
||||||
const lastPageIndex = totalPages;
|
|
||||||
|
|
||||||
if (!showLeftDots && showRightDots) {
|
|
||||||
let leftItemCount = 3;
|
|
||||||
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
|
||||||
|
|
||||||
pages.push(...leftRange);
|
|
||||||
pages.push("...");
|
|
||||||
pages.push(totalPages);
|
|
||||||
} else if (showLeftDots && !showRightDots) {
|
|
||||||
let rightItemCount = 3;
|
|
||||||
let rightRange = Array.from(
|
|
||||||
{ length: rightItemCount },
|
|
||||||
(_, i) => totalPages - rightItemCount + i + 1
|
|
||||||
);
|
|
||||||
|
|
||||||
pages.push(firstPageIndex);
|
|
||||||
pages.push("...");
|
|
||||||
pages.push(...rightRange);
|
|
||||||
} else if (showLeftDots && showRightDots) {
|
|
||||||
let middleRange = Array.from(
|
|
||||||
{ length: 3 },
|
|
||||||
(_, i) => leftSiblingIndex + i
|
|
||||||
);
|
|
||||||
|
|
||||||
pages.push(firstPageIndex);
|
|
||||||
pages.push("...");
|
|
||||||
pages.push(...middleRange);
|
|
||||||
pages.push("...");
|
|
||||||
pages.push(lastPageIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pages;
|
|
||||||
};
|
|
||||||
const pageNumbers = getPaginationRange();
|
|
||||||
// to slice out 10 objects from array for current page
|
|
||||||
const indexOfLastDoc = currentPage * recordperPage;
|
|
||||||
const indexOfFirstDoc = indexOfLastDoc - recordperPage;
|
|
||||||
const currentList = userList?.slice(indexOfFirstDoc, indexOfLastDoc);
|
|
||||||
useEffect(() => {
|
|
||||||
fetchUserList();
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
async function fetchUserList() {
|
|
||||||
try {
|
|
||||||
setIsLoader(true);
|
|
||||||
const extUser =
|
|
||||||
localStorage.getItem("Extand_Class") &&
|
|
||||||
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
|
||||||
|
|
||||||
if (extUser) {
|
|
||||||
const admin =
|
|
||||||
extUser?.UserRole &&
|
|
||||||
(extUser?.UserRole === "contracts_Admin" ||
|
|
||||||
extUser?.UserRole === "contracts_OrgAdmin")
|
|
||||||
? true
|
|
||||||
: false;
|
|
||||||
setIsAdmin(admin);
|
|
||||||
}
|
|
||||||
const res = await Parse.Cloud.run("getuserlistbyorg", {
|
|
||||||
organizationId: extUser.OrganizationId.objectId
|
|
||||||
});
|
|
||||||
const _userRes = JSON.parse(JSON.stringify(res));
|
|
||||||
setUserList(_userRes);
|
|
||||||
} catch (err) {
|
|
||||||
console.log("Err in fetch userlist", err);
|
|
||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
|
||||||
} finally {
|
|
||||||
setIsLoader(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const handleModal = (modalName) => {
|
|
||||||
setIsModal((obj) => ({ ...obj, [modalName]: !obj[modalName] }));
|
|
||||||
};
|
|
||||||
|
|
||||||
// Change page
|
|
||||||
const paginateFront = () => {
|
|
||||||
const lastValue = pageNumbers?.[pageNumbers?.length - 1];
|
|
||||||
if (currentPage < lastValue) {
|
|
||||||
setCurrentPage(currentPage + 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const paginateBack = () => {
|
|
||||||
if (startIndex > 0) {
|
|
||||||
setCurrentPage(currentPage - 1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleUserData = (userData) => {
|
|
||||||
if (userData) {
|
|
||||||
setUserList((prev) => [userData, ...prev]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// `formatRow` is used to show data in poper manner like
|
|
||||||
// if data is of array type then it will join array items with ","
|
|
||||||
// if data is of object type then it Name values will be show in row
|
|
||||||
// if no data available it will show hyphen "-"
|
|
||||||
const formatRow = (row) => {
|
|
||||||
if (Array.isArray(row)) {
|
|
||||||
let updateArr = row.map((x) => x.Name);
|
|
||||||
return updateArr.join(", ");
|
|
||||||
} else if (typeof row === "object" && row !== null) {
|
|
||||||
return row?.Name || "-";
|
|
||||||
} else {
|
|
||||||
return "-";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleClose = () => setIsActiveModal({});
|
|
||||||
|
|
||||||
const handleToggleSubmit = async (user) => {
|
|
||||||
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
|
|
||||||
if (index !== -1) {
|
|
||||||
setIsActiveModal({});
|
|
||||||
setIsActLoader({ [user.objectId]: true });
|
|
||||||
const newArray = [...userList];
|
|
||||||
const IsDisabled = newArray[index]?.IsDisabled;
|
|
||||||
newArray[index] = { ...newArray[index], IsDisabled: !IsDisabled };
|
|
||||||
setUserList(newArray);
|
|
||||||
try {
|
|
||||||
const extUser = new Parse.Object("contracts_Users");
|
|
||||||
extUser.id = user.objectId;
|
|
||||||
extUser.set("IsDisabled", !IsDisabled);
|
|
||||||
await extUser.save();
|
|
||||||
showAlert(
|
|
||||||
!IsDisabled === true ? "danger" : "success",
|
|
||||||
!IsDisabled === true ? t("user-deactivated") : t("user-activated")
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
|
||||||
console.log("err in disable team", err);
|
|
||||||
} finally {
|
|
||||||
setIsActLoader({});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const handleToggleBtn = (user) => {
|
|
||||||
setIsActiveModal({ [user.objectId]: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
// `showAlert` handle show/hide alert
|
|
||||||
const showAlert = (type, msg) => {
|
|
||||||
setIsAlert({ type, msg });
|
|
||||||
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
|
||||||
};
|
|
||||||
return (
|
|
||||||
<div className="relative">
|
|
||||||
<Title title={isAdmin ? "Users" : "Page not found"} />
|
|
||||||
{isLoader && (
|
|
||||||
<div className="absolute w-full h-[300px] md:h-[400px] flex justify-center items-center z-30 rounded-box">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{Object.keys(isActLoader)?.length > 0 && (
|
|
||||||
<div className="absolute w-full h-full flex justify-center items-center bg-black/30 z-30 rounded-box">
|
|
||||||
<Loader />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{!isLoader && (
|
|
||||||
<>
|
|
||||||
{isAdmin ? (
|
|
||||||
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
|
||||||
{isAlert.msg && <Alert type={isAlert.type}>{isAlert.msg}</Alert>}
|
|
||||||
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
|
||||||
<div className="font-light">
|
|
||||||
{t("report-name.Users")}{" "}
|
|
||||||
<span className="text-xs md:text-[13px] font-normal">
|
|
||||||
<Tooltip message={t("users-from-teams")} />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row gap-2 items-center">
|
|
||||||
<div
|
|
||||||
className="cursor-pointer"
|
|
||||||
onClick={() => handleModal("form")}
|
|
||||||
>
|
|
||||||
<i className="fa-light fa-square-plus text-accent text-[30px] md:text-[40px]"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="w-full overflow-x-auto">
|
|
||||||
<table className="op-table border-collapse w-full mb-[50px]">
|
|
||||||
<thead className="text-[14px]">
|
|
||||||
<tr className="border-y-[1px]">
|
|
||||||
{heading?.map((item, index) => (
|
|
||||||
<th key={index} className="px-4 py-2">
|
|
||||||
{t(`report-heading.${item}`)}
|
|
||||||
</th>
|
|
||||||
))}
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
{userList?.length > 0 && (
|
|
||||||
<tbody className="text-[12px]">
|
|
||||||
{currentList.map((item, index) => (
|
|
||||||
<tr className="border-y-[1px]" key={index}>
|
|
||||||
{heading.includes("Sr.No") && (
|
|
||||||
<th className="px-4 py-2">
|
|
||||||
{startIndex + index + 1}
|
|
||||||
</th>
|
|
||||||
)}
|
|
||||||
<td className="px-4 py-2 font-semibold">
|
|
||||||
{item?.Name}{" "}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2 ">{item?.Email || "-"}</td>
|
|
||||||
<td className="px-4 py-2">{item?.Phone || "-"}</td>
|
|
||||||
<td className="px-4 py-2">
|
|
||||||
{item?.UserRole?.split("_").pop() || "-"}
|
|
||||||
</td>
|
|
||||||
<td className="px-4 py-2">
|
|
||||||
{formatRow(item.TeamIds)}
|
|
||||||
</td>
|
|
||||||
{item.UserRole !== "contracts_Admin" ? (
|
|
||||||
<td className="px-4 py-2 font-semibold">
|
|
||||||
<label className="cursor-pointer relative block items-center mb-0">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
className="op-toggle transition-all op-toggle-secondary"
|
|
||||||
checked={item?.IsDisabled !== true}
|
|
||||||
onChange={() => handleToggleBtn(item)}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
{isActiveModal[item.objectId] && (
|
|
||||||
<ModalUi
|
|
||||||
isOpen
|
|
||||||
title={t("user-status")}
|
|
||||||
handleClose={handleClose}
|
|
||||||
>
|
|
||||||
<div className="m-[20px]">
|
|
||||||
<div className="text-lg font-normal text-black">
|
|
||||||
{t("are-you-sure")}{" "}
|
|
||||||
{item?.IsDisabled
|
|
||||||
? t("activate")
|
|
||||||
: t("deactivate")}{" "}
|
|
||||||
{t("this-user")}?
|
|
||||||
</div>
|
|
||||||
<hr className="bg-[#ccc] mt-4 " />
|
|
||||||
<div className="flex items-center mt-3 gap-2 text-white">
|
|
||||||
<button
|
|
||||||
onClick={() => handleToggleSubmit(item)}
|
|
||||||
className="op-btn op-btn-primary"
|
|
||||||
>
|
|
||||||
{t("yes")}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
onClick={handleClose}
|
|
||||||
className="op-btn op-btn-secondary"
|
|
||||||
>
|
|
||||||
{t("no")}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</ModalUi>
|
|
||||||
)}
|
|
||||||
</td>
|
|
||||||
) : (
|
|
||||||
<td className="px-4 py-2 font-semibold"></td>
|
|
||||||
)}
|
|
||||||
</tr>
|
|
||||||
))}
|
|
||||||
</tbody>
|
|
||||||
)}
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row justify-between items-center text-xs font-medium">
|
|
||||||
<div className="op-join flex flex-wrap items-center p-2">
|
|
||||||
{userList.length > recordperPage && (
|
|
||||||
<button
|
|
||||||
onClick={() => paginateBack()}
|
|
||||||
className="op-join-item op-btn op-btn-sm"
|
|
||||||
>
|
|
||||||
{t("prev")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
{pageNumbers.map((x, i) => (
|
|
||||||
<button
|
|
||||||
key={i}
|
|
||||||
onClick={() => setCurrentPage(x)}
|
|
||||||
disabled={x === "..."}
|
|
||||||
className={`${
|
|
||||||
x === currentPage ? "op-btn-active" : ""
|
|
||||||
} op-join-item op-btn op-btn-sm`}
|
|
||||||
>
|
|
||||||
{x}
|
|
||||||
</button>
|
|
||||||
))}
|
|
||||||
{userList.length > recordperPage && (
|
|
||||||
<button
|
|
||||||
onClick={() => paginateFront()}
|
|
||||||
className="op-join-item op-btn op-btn-sm"
|
|
||||||
>
|
|
||||||
{t("next")}
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{userList?.length <= 0 && (
|
|
||||||
<div
|
|
||||||
className={`${
|
|
||||||
isDashboard ? "h-[317px]" : ""
|
|
||||||
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
|
||||||
>
|
|
||||||
<div className="w-[60px] h-[60px] overflow-hidden">
|
|
||||||
<img
|
|
||||||
className="w-full h-full object-contain"
|
|
||||||
src={pad}
|
|
||||||
alt="img"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="text-sm font-semibold">
|
|
||||||
{t("no-data-avaliable")}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<ModalUi
|
|
||||||
isOpen={isModal.form}
|
|
||||||
title={formHeader}
|
|
||||||
handleClose={() => handleModal("form")}
|
|
||||||
>
|
|
||||||
<AddUser
|
|
||||||
showAlert={showAlert}
|
|
||||||
handleUserData={handleUserData}
|
|
||||||
closePopup={() => handleModal("form")}
|
|
||||||
setFormHeader={setFormHeader}
|
|
||||||
/>
|
|
||||||
</ModalUi>
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
|
||||||
<div className="text-center">
|
|
||||||
<h1 className="text-[60px] lg:text-[120px] font-semibold">
|
|
||||||
404
|
|
||||||
</h1>
|
|
||||||
<p className="text-[30px] lg:text-[50px]">
|
|
||||||
{t("page-not-found")}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UserList;
|
|
||||||
@@ -0,0 +1,406 @@
|
|||||||
|
import React, { useEffect, useState } from "react";
|
||||||
|
import Parse from "parse";
|
||||||
|
import Alert from "../primitives/Alert";
|
||||||
|
import Loader from "../primitives/Loader";
|
||||||
|
import { useLocation } from "react-router";
|
||||||
|
import ModalUi from "../primitives/ModalUi";
|
||||||
|
import pad from "../assets/images/pad.svg";
|
||||||
|
import Tooltip from "../primitives/Tooltip";
|
||||||
|
import AddUser from "../components/AddUser";
|
||||||
|
import Title from "../components/Title";
|
||||||
|
import {
|
||||||
|
useTranslation
|
||||||
|
} from "react-i18next";
|
||||||
|
const heading = ["Sr.No", "Name", "Email", "Phone", "Role", "Team", "Active"];
|
||||||
|
const UserList = () => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const [userList, setUserList] = useState([]);
|
||||||
|
const [isLoader, setIsLoader] = useState(false);
|
||||||
|
const [isModal, setIsModal] = useState({
|
||||||
|
form: false,
|
||||||
|
addseats: false,
|
||||||
|
options: false
|
||||||
|
});
|
||||||
|
const location = useLocation();
|
||||||
|
const isDashboard =
|
||||||
|
location?.pathname === "/dashboard/35KBoSgoAK" ? true : false;
|
||||||
|
const [currentPage, setCurrentPage] = useState(1);
|
||||||
|
const [isAlert, setIsAlert] = useState({ type: "success", msg: "" });
|
||||||
|
const [isActiveModal, setIsActiveModal] = useState({});
|
||||||
|
const [isActLoader, setIsActLoader] = useState({});
|
||||||
|
const [isAdmin, setIsAdmin] = useState(false);
|
||||||
|
const [formHeader, setFormHeader] = useState(t("add-user"));
|
||||||
|
const recordperPage = 10;
|
||||||
|
const startIndex = (currentPage - 1) * recordperPage; // user per page
|
||||||
|
|
||||||
|
const getPaginationRange = () => {
|
||||||
|
const totalPageNumbers = 7; // Adjust this value to show more/less page numbers
|
||||||
|
const pages = [];
|
||||||
|
const totalPages = Math.ceil(userList.length / recordperPage);
|
||||||
|
if (totalPages <= totalPageNumbers) {
|
||||||
|
for (let i = 1; i <= totalPages; i++) {
|
||||||
|
pages.push(i);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const leftSiblingIndex = Math.max(currentPage - 1, 1);
|
||||||
|
const rightSiblingIndex = Math.min(currentPage + 1, totalPages);
|
||||||
|
|
||||||
|
const showLeftDots = leftSiblingIndex > 2;
|
||||||
|
const showRightDots = rightSiblingIndex < totalPages - 2;
|
||||||
|
|
||||||
|
const firstPageIndex = 1;
|
||||||
|
const lastPageIndex = totalPages;
|
||||||
|
|
||||||
|
if (!showLeftDots && showRightDots) {
|
||||||
|
let leftItemCount = 3;
|
||||||
|
let leftRange = Array.from({ length: leftItemCount }, (_, i) => i + 1);
|
||||||
|
|
||||||
|
pages.push(...leftRange);
|
||||||
|
pages.push("...");
|
||||||
|
pages.push(totalPages);
|
||||||
|
} else if (showLeftDots && !showRightDots) {
|
||||||
|
let rightItemCount = 3;
|
||||||
|
let rightRange = Array.from(
|
||||||
|
{ length: rightItemCount },
|
||||||
|
(_, i) => totalPages - rightItemCount + i + 1
|
||||||
|
);
|
||||||
|
|
||||||
|
pages.push(firstPageIndex);
|
||||||
|
pages.push("...");
|
||||||
|
pages.push(...rightRange);
|
||||||
|
} else if (showLeftDots && showRightDots) {
|
||||||
|
let middleRange = Array.from(
|
||||||
|
{ length: 3 },
|
||||||
|
(_, i) => leftSiblingIndex + i
|
||||||
|
);
|
||||||
|
|
||||||
|
pages.push(firstPageIndex);
|
||||||
|
pages.push("...");
|
||||||
|
pages.push(...middleRange);
|
||||||
|
pages.push("...");
|
||||||
|
pages.push(lastPageIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pages;
|
||||||
|
};
|
||||||
|
const pageNumbers = getPaginationRange();
|
||||||
|
// to slice out 10 objects from array for current page
|
||||||
|
const indexOfLastDoc = currentPage * recordperPage;
|
||||||
|
const indexOfFirstDoc = indexOfLastDoc - recordperPage;
|
||||||
|
const currentList = userList?.slice(indexOfFirstDoc, indexOfLastDoc);
|
||||||
|
useEffect(() => {
|
||||||
|
fetchUserList();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, []);
|
||||||
|
async function fetchUserList() {
|
||||||
|
try {
|
||||||
|
setIsLoader(true);
|
||||||
|
const extUser =
|
||||||
|
localStorage.getItem("Extand_Class") &&
|
||||||
|
JSON.parse(localStorage.getItem("Extand_Class"))?.[0];
|
||||||
|
|
||||||
|
if (extUser) {
|
||||||
|
const admin =
|
||||||
|
extUser?.UserRole &&
|
||||||
|
(extUser?.UserRole === "contracts_Admin" ||
|
||||||
|
extUser?.UserRole === "contracts_OrgAdmin")
|
||||||
|
? true
|
||||||
|
: false;
|
||||||
|
setIsAdmin(admin);
|
||||||
|
}
|
||||||
|
const res = await Parse.Cloud.run("getuserlistbyorg", {
|
||||||
|
organizationId: extUser.OrganizationId.objectId
|
||||||
|
});
|
||||||
|
const _userRes = JSON.parse(JSON.stringify(res));
|
||||||
|
setUserList(_userRes);
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err in fetch userlist", err);
|
||||||
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
|
} finally {
|
||||||
|
setIsLoader(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const handleModal = (modalName) => {
|
||||||
|
setIsModal((obj) => ({ ...obj, [modalName]: !obj[modalName] }));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Change page
|
||||||
|
const paginateFront = () => {
|
||||||
|
const lastValue = pageNumbers?.[pageNumbers?.length - 1];
|
||||||
|
if (currentPage < lastValue) {
|
||||||
|
setCurrentPage(currentPage + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const paginateBack = () => {
|
||||||
|
if (startIndex > 0) {
|
||||||
|
setCurrentPage(currentPage - 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleUserData = (userData) => {
|
||||||
|
if (userData) {
|
||||||
|
setUserList((prev) => [userData, ...prev]);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// `formatRow` is used to show data in poper manner like
|
||||||
|
// if data is of array type then it will join array items with ","
|
||||||
|
// if data is of object type then it Name values will be show in row
|
||||||
|
// if no data available it will show hyphen "-"
|
||||||
|
const formatRow = (row) => {
|
||||||
|
if (Array.isArray(row)) {
|
||||||
|
let updateArr = row.map((x) => x.Name);
|
||||||
|
return updateArr.join(", ");
|
||||||
|
} else if (typeof row === "object" && row !== null) {
|
||||||
|
return row?.Name || "-";
|
||||||
|
} else {
|
||||||
|
return "-";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleClose = () => setIsActiveModal({});
|
||||||
|
|
||||||
|
const handleToggleSubmit = async (user) => {
|
||||||
|
const index = userList.findIndex((obj) => obj.objectId === user.objectId);
|
||||||
|
if (index !== -1) {
|
||||||
|
setIsActiveModal({});
|
||||||
|
setIsActLoader({ [user.objectId]: true });
|
||||||
|
const newArray = [...userList];
|
||||||
|
const IsDisabled = newArray[index]?.IsDisabled;
|
||||||
|
newArray[index] = { ...newArray[index], IsDisabled: !IsDisabled };
|
||||||
|
setUserList(newArray);
|
||||||
|
try {
|
||||||
|
const extUser = new Parse.Object("contracts_Users");
|
||||||
|
extUser.id = user.objectId;
|
||||||
|
extUser.set("IsDisabled", !IsDisabled);
|
||||||
|
await extUser.save();
|
||||||
|
showAlert(
|
||||||
|
!IsDisabled === true ? "danger" : "success",
|
||||||
|
!IsDisabled === true ? t("user-deactivated") : t("user-activated")
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
|
console.log("err in disable team", err);
|
||||||
|
} finally {
|
||||||
|
setIsActLoader({});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleToggleBtn = (user) => {
|
||||||
|
setIsActiveModal({ [user.objectId]: true });
|
||||||
|
};
|
||||||
|
|
||||||
|
// `showAlert` handle show/hide alert
|
||||||
|
const showAlert = (type, msg) => {
|
||||||
|
setIsAlert({ type, msg });
|
||||||
|
setTimeout(() => setIsAlert({ type: "success", msg: "" }), 1500);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div className="relative">
|
||||||
|
<Title title={isAdmin ? "Users" : "Page not found"} />
|
||||||
|
{isLoader && (
|
||||||
|
<div className="absolute w-full h-[300px] md:h-[400px] flex justify-center items-center z-30 rounded-box">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{Object.keys(isActLoader)?.length > 0 && (
|
||||||
|
<div className="absolute w-full h-full flex justify-center items-center bg-black/30 z-30 rounded-box">
|
||||||
|
<Loader />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{
|
||||||
|
!isLoader && (
|
||||||
|
<>
|
||||||
|
{isAdmin ? (
|
||||||
|
<div className="p-2 w-full bg-base-100 text-base-content op-card shadow-lg">
|
||||||
|
{isAlert.msg && (
|
||||||
|
<Alert type={isAlert.type}>{isAlert.msg}</Alert>
|
||||||
|
)}
|
||||||
|
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
||||||
|
<div className="font-light">
|
||||||
|
{t("report-name.Users")}{" "}
|
||||||
|
<span className="text-xs md:text-[13px] font-normal">
|
||||||
|
<Tooltip message={t("users-from-teams")} />
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row gap-2 items-center">
|
||||||
|
<div
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={() => handleModal("form")}
|
||||||
|
>
|
||||||
|
<i className="fa-light fa-square-plus text-accent text-[30px] md:text-[40px]"></i>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full overflow-x-auto">
|
||||||
|
<table className="op-table border-collapse w-full mb-[50px]">
|
||||||
|
<thead className="text-[14px]">
|
||||||
|
<tr className="border-y-[1px]">
|
||||||
|
{heading?.map((item, index) => (
|
||||||
|
<th key={index} className="px-4 py-2">
|
||||||
|
{t(`report-heading.${item}`)}
|
||||||
|
</th>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
{userList?.length > 0 && (
|
||||||
|
<tbody className="text-[12px]">
|
||||||
|
{currentList.map((item, index) => (
|
||||||
|
<tr className="border-y-[1px]" key={index}>
|
||||||
|
{heading.includes("Sr.No") && (
|
||||||
|
<th className="px-4 py-2">
|
||||||
|
{startIndex + index + 1}
|
||||||
|
</th>
|
||||||
|
)}
|
||||||
|
<td className="px-4 py-2 font-semibold">
|
||||||
|
{item?.Name}{" "}
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-2 ">
|
||||||
|
{item?.Email || "-"}
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-2">
|
||||||
|
{item?.Phone || "-"}
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-2">
|
||||||
|
{item?.UserRole?.split("_").pop() || "-"}
|
||||||
|
</td>
|
||||||
|
<td className="px-4 py-2">
|
||||||
|
{formatRow(item.TeamIds)}
|
||||||
|
</td>
|
||||||
|
{item.UserRole !== "contracts_Admin" ? (
|
||||||
|
<td className="px-4 py-2 font-semibold">
|
||||||
|
<label className="cursor-pointer relative block items-center mb-0">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="op-toggle transition-all op-toggle-secondary"
|
||||||
|
checked={item?.IsDisabled !== true}
|
||||||
|
onChange={() => handleToggleBtn(item)}
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
|
{isActiveModal[item.objectId] && (
|
||||||
|
<ModalUi
|
||||||
|
isOpen
|
||||||
|
title={t("user-status")}
|
||||||
|
handleClose={handleClose}
|
||||||
|
>
|
||||||
|
<div className="m-[20px]">
|
||||||
|
<div className="text-lg font-normal text-black">
|
||||||
|
{t("are-you-sure")}{" "}
|
||||||
|
{item?.IsDisabled
|
||||||
|
? t("activate")
|
||||||
|
: t("deactivate")}{" "}
|
||||||
|
{t("this-user")}?
|
||||||
|
</div>
|
||||||
|
<hr className="bg-[#ccc] mt-4 " />
|
||||||
|
<div className="flex items-center mt-3 gap-2 text-white">
|
||||||
|
<button
|
||||||
|
onClick={() =>
|
||||||
|
handleToggleSubmit(item)
|
||||||
|
}
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
>
|
||||||
|
{t("yes")}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleClose}
|
||||||
|
className="op-btn op-btn-secondary"
|
||||||
|
>
|
||||||
|
{t("no")}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ModalUi>
|
||||||
|
)}
|
||||||
|
</td>
|
||||||
|
) : (
|
||||||
|
<td className="px-4 py-2 font-semibold"></td>
|
||||||
|
)}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
)}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-row justify-between items-center text-xs font-medium">
|
||||||
|
<div className="op-join flex flex-wrap items-center p-2">
|
||||||
|
{userList.length > recordperPage && (
|
||||||
|
<button
|
||||||
|
onClick={() => paginateBack()}
|
||||||
|
className="op-join-item op-btn op-btn-sm"
|
||||||
|
>
|
||||||
|
{t("prev")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{pageNumbers.map((x, i) => (
|
||||||
|
<button
|
||||||
|
key={i}
|
||||||
|
onClick={() => setCurrentPage(x)}
|
||||||
|
disabled={x === "..."}
|
||||||
|
className={`${
|
||||||
|
x === currentPage ? "op-btn-active" : ""
|
||||||
|
} op-join-item op-btn op-btn-sm`}
|
||||||
|
>
|
||||||
|
{x}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
{userList.length > recordperPage && (
|
||||||
|
<button
|
||||||
|
onClick={() => paginateFront()}
|
||||||
|
className="op-join-item op-btn op-btn-sm"
|
||||||
|
>
|
||||||
|
{t("next")}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{userList?.length <= 0 && (
|
||||||
|
<div
|
||||||
|
className={`${
|
||||||
|
isDashboard ? "h-[317px]" : ""
|
||||||
|
} flex flex-col items-center justify-center w-ful bg-base-100 text-base-content rounded-xl py-4`}
|
||||||
|
>
|
||||||
|
<div className="w-[60px] h-[60px] overflow-hidden">
|
||||||
|
<img
|
||||||
|
className="w-full h-full object-contain"
|
||||||
|
src={pad}
|
||||||
|
alt="img"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="text-sm font-semibold">
|
||||||
|
{t("no-data-avaliable")}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<ModalUi
|
||||||
|
isOpen={isModal.form}
|
||||||
|
title={formHeader}
|
||||||
|
handleClose={() => handleModal("form")}
|
||||||
|
>
|
||||||
|
<AddUser
|
||||||
|
showAlert={showAlert}
|
||||||
|
handleUserData={handleUserData}
|
||||||
|
closePopup={() => handleModal("form")}
|
||||||
|
setFormHeader={setFormHeader}
|
||||||
|
/>
|
||||||
|
</ModalUi>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center justify-center h-screen w-full bg-base-100 text-base-content rounded-box">
|
||||||
|
<div className="text-center">
|
||||||
|
<h1 className="text-[60px] lg:text-[120px] font-semibold">
|
||||||
|
404
|
||||||
|
</h1>
|
||||||
|
<p className="text-[30px] lg:text-[50px]">
|
||||||
|
{t("page-not-found")}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default UserList;
|
||||||
@@ -1,4 +1,7 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, {
|
||||||
|
useState,
|
||||||
|
useEffect,
|
||||||
|
} from "react";
|
||||||
import { Navigate, useNavigate } from "react-router";
|
import { Navigate, useNavigate } from "react-router";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { SaveFileSize } from "../constant/saveFileSize";
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
@@ -7,7 +10,10 @@ import Title from "../components/Title";
|
|||||||
import sanitizeFileName from "../primitives/sanitizeFileName";
|
import sanitizeFileName from "../primitives/sanitizeFileName";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Tooltip from "../primitives/Tooltip";
|
import Tooltip from "../primitives/Tooltip";
|
||||||
import { getSecureUrl, handleSendOTP } from "../constant/Utils";
|
import {
|
||||||
|
getSecureUrl,
|
||||||
|
handleSendOTP,
|
||||||
|
} from "../constant/Utils";
|
||||||
import ModalUi from "../primitives/ModalUi";
|
import ModalUi from "../primitives/ModalUi";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@@ -121,7 +127,7 @@ function UserProfile() {
|
|||||||
Name: obj.Name,
|
Name: obj.Name,
|
||||||
JobTitle: jobTitle,
|
JobTitle: jobTitle,
|
||||||
Company: company,
|
Company: company,
|
||||||
Language: obj?.language || ""
|
Language: obj?.language || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
await axios.put(
|
await axios.put(
|
||||||
@@ -406,7 +412,7 @@ function UserProfile() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
editmode ? handleSubmit(e) : setEditMode(true);
|
editmode ? handleSubmit(e) : setEditMode(true);
|
||||||
}}
|
}}
|
||||||
className="op-btn op-btn-primary w-[100px]"
|
className="op-btn op-btn-primary w-[100px]"
|
||||||
>
|
>
|
||||||
+9
-7
@@ -33,9 +33,8 @@ const AddContact = (props) => {
|
|||||||
try {
|
try {
|
||||||
const baseURL = localStorage.getItem("baseUrl");
|
const baseURL = localStorage.getItem("baseUrl");
|
||||||
const url = `${baseURL}functions/isuserincontactbook`;
|
const url = `${baseURL}functions/isuserincontactbook`;
|
||||||
const token = {
|
const token =
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
{ "X-Parse-Session-Token": localStorage.getItem("accesstoken") };
|
||||||
};
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId"),
|
||||||
@@ -64,15 +63,18 @@ const AddContact = (props) => {
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
const userId = user?.objectId || "";
|
const userId = user?.objectId || "";
|
||||||
const tenantDetails = await getTenantDetails(userId);
|
const tenantDetails = await getTenantDetails(
|
||||||
|
userId,
|
||||||
|
);
|
||||||
const tenantId = tenantDetails?.objectId || "";
|
const tenantId = tenantDetails?.objectId || "";
|
||||||
if (tenantId) {
|
if (tenantId) {
|
||||||
try {
|
try {
|
||||||
const baseURL = localStorage.getItem("baseUrl");
|
const baseURL = localStorage.getItem("baseUrl");
|
||||||
const url = `${baseURL}functions/savecontact`;
|
const url = `${baseURL}functions/savecontact`;
|
||||||
const token = {
|
const token =
|
||||||
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
{
|
||||||
};
|
"X-Parse-Session-Token": localStorage.getItem("accesstoken")
|
||||||
|
};
|
||||||
const data = { name, email, phone, tenantId };
|
const data = { name, email, phone, tenantId };
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
+170
-143
@@ -5,7 +5,9 @@ import { Link, useLocation, useNavigate } from "react-router";
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import ModalUi from "./ModalUi";
|
import ModalUi from "./ModalUi";
|
||||||
import AddSigner from "../components/AddSigner";
|
import AddSigner from "../components/AddSigner";
|
||||||
import { emailRegex } from "../constant/const";
|
import {
|
||||||
|
emailRegex,
|
||||||
|
} from "../constant/const";
|
||||||
import Alert from "./Alert";
|
import Alert from "./Alert";
|
||||||
import Tooltip from "./Tooltip";
|
import Tooltip from "./Tooltip";
|
||||||
import { RWebShare } from "react-web-share";
|
import { RWebShare } from "react-web-share";
|
||||||
@@ -39,7 +41,8 @@ import EditContactForm from "../components/EditContactForm";
|
|||||||
|
|
||||||
const ReportTable = (props) => {
|
const ReportTable = (props) => {
|
||||||
const copyUrlRef = useRef(null);
|
const copyUrlRef = useRef(null);
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
const drivename = appName === "OpenSign™" ? "OpenSign™" : "";
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -162,14 +165,14 @@ const ReportTable = (props) => {
|
|||||||
const teamtRes = await Parse.Cloud.run("getteams", { active: true });
|
const teamtRes = await Parse.Cloud.run("getteams", { active: true });
|
||||||
if (teamtRes.length > 0) {
|
if (teamtRes.length > 0) {
|
||||||
const _teamRes = JSON.parse(JSON.stringify(teamtRes));
|
const _teamRes = JSON.parse(JSON.stringify(teamtRes));
|
||||||
const selected = _teamRes.map(
|
const selected = _teamRes.map(
|
||||||
(x) =>
|
(x) =>
|
||||||
x.Name === "All Users" && {
|
x.Name === "All Users" && {
|
||||||
label: x.Name,
|
label: x.Name,
|
||||||
value: x.objectId
|
value: x.objectId
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
setSelectedTeam(selected);
|
setSelectedTeam(selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -230,7 +233,7 @@ const ReportTable = (props) => {
|
|||||||
const handleURL = async (item, act) => {
|
const handleURL = async (item, act) => {
|
||||||
if (isTemplateReport) {
|
if (isTemplateReport) {
|
||||||
if (act.hoverLabel === "Edit") {
|
if (act.hoverLabel === "Edit") {
|
||||||
navigate(`/${act.redirectUrl}/${item.objectId}`);
|
navigate(`/${act.redirectUrl}/${item.objectId}`);
|
||||||
} else {
|
} else {
|
||||||
setActLoader({ [`${item.objectId}_${act.btnId}`]: true });
|
setActLoader({ [`${item.objectId}_${act.btnId}`]: true });
|
||||||
handleUseTemplate(item.objectId, act.redirectUrl);
|
handleUseTemplate(item.objectId, act.redirectUrl);
|
||||||
@@ -405,7 +408,8 @@ const ReportTable = (props) => {
|
|||||||
setSelectedTeam(formatedList);
|
setSelectedTeam(formatedList);
|
||||||
}
|
}
|
||||||
setIsShareWith({ [item.objectId]: true });
|
setIsShareWith({ [item.objectId]: true });
|
||||||
} else if (act.action === "duplicate") {
|
}
|
||||||
|
else if (act.action === "duplicate") {
|
||||||
setIsModal({ [`duplicate_${item.objectId}`]: true });
|
setIsModal({ [`duplicate_${item.objectId}`]: true });
|
||||||
} else if (act.action === "rename") {
|
} else if (act.action === "rename") {
|
||||||
setIsModal({ [`rename_${item.objectId}`]: true });
|
setIsModal({ [`rename_${item.objectId}`]: true });
|
||||||
@@ -483,7 +487,8 @@ const ReportTable = (props) => {
|
|||||||
setActLoader({});
|
setActLoader({});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleClose = () => {
|
const handleClose = (
|
||||||
|
) => {
|
||||||
setIsRevoke({});
|
setIsRevoke({});
|
||||||
setIsDeleteModal({});
|
setIsDeleteModal({});
|
||||||
setReason("");
|
setReason("");
|
||||||
@@ -632,7 +637,11 @@ const ReportTable = (props) => {
|
|||||||
if (isCompleted) {
|
if (isCompleted) {
|
||||||
setIsDownloadModal({ [item.objectId]: true });
|
setIsDownloadModal({ [item.objectId]: true });
|
||||||
} else {
|
} else {
|
||||||
const signedUrl = await getSignedUrl(url, docId, templateId);
|
const signedUrl = await getSignedUrl(
|
||||||
|
url,
|
||||||
|
docId,
|
||||||
|
templateId
|
||||||
|
);
|
||||||
await fetchUrl(signedUrl, pdfName);
|
await fetchUrl(signedUrl, pdfName);
|
||||||
}
|
}
|
||||||
setActLoader({});
|
setActLoader({});
|
||||||
@@ -660,8 +669,10 @@ const ReportTable = (props) => {
|
|||||||
const variables = {
|
const variables = {
|
||||||
document_title: doc.Name,
|
document_title: doc.Name,
|
||||||
note: doc?.Note || "",
|
note: doc?.Note || "",
|
||||||
sender_name: doc.ExtUserPtr.Name,
|
sender_name:
|
||||||
sender_mail: doc.ExtUserPtr.Email,
|
doc.ExtUserPtr.Name,
|
||||||
|
sender_mail:
|
||||||
|
doc.ExtUserPtr.Email,
|
||||||
sender_phone: doc.ExtUserPtr?.Phone || "",
|
sender_phone: doc.ExtUserPtr?.Phone || "",
|
||||||
receiver_name: userDetails?.Name || "",
|
receiver_name: userDetails?.Name || "",
|
||||||
receiver_email: userDetails?.Email,
|
receiver_email: userDetails?.Email,
|
||||||
@@ -689,8 +700,10 @@ const ReportTable = (props) => {
|
|||||||
const variables = {
|
const variables = {
|
||||||
document_title: doc.Name,
|
document_title: doc.Name,
|
||||||
note: doc?.Note || "",
|
note: doc?.Note || "",
|
||||||
sender_name: doc.ExtUserPtr.Name,
|
sender_name:
|
||||||
sender_mail: doc.ExtUserPtr.Email,
|
doc.ExtUserPtr.Name,
|
||||||
|
sender_mail:
|
||||||
|
doc.ExtUserPtr.Email,
|
||||||
sender_phone: doc.ExtUserPtr?.Phone || "",
|
sender_phone: doc.ExtUserPtr?.Phone || "",
|
||||||
receiver_name: userDetails?.Name || "",
|
receiver_name: userDetails?.Name || "",
|
||||||
receiver_email: userDetails?.Email || "",
|
receiver_email: userDetails?.Email || "",
|
||||||
@@ -731,8 +744,10 @@ const ReportTable = (props) => {
|
|||||||
const variables = {
|
const variables = {
|
||||||
document_title: doc.Name,
|
document_title: doc.Name,
|
||||||
note: doc?.Note || "",
|
note: doc?.Note || "",
|
||||||
sender_name: doc.ExtUserPtr.Name,
|
sender_name:
|
||||||
sender_mail: doc.ExtUserPtr.Email,
|
doc.ExtUserPtr.Name,
|
||||||
|
sender_mail:
|
||||||
|
doc.ExtUserPtr.Email,
|
||||||
sender_phone: doc.ExtUserPtr?.Phone || "",
|
sender_phone: doc.ExtUserPtr?.Phone || "",
|
||||||
receiver_name: user?.signerPtr?.Name || "",
|
receiver_name: user?.signerPtr?.Name || "",
|
||||||
receiver_email: user?.email ? user?.email : user?.signerPtr?.Email,
|
receiver_email: user?.email ? user?.email : user?.signerPtr?.Email,
|
||||||
@@ -763,11 +778,14 @@ const ReportTable = (props) => {
|
|||||||
sessionToken: localStorage.getItem("accesstoken")
|
sessionToken: localStorage.getItem("accesstoken")
|
||||||
};
|
};
|
||||||
let params = {
|
let params = {
|
||||||
replyto: doc?.ExtUserPtr?.Email || "",
|
replyto:
|
||||||
|
doc?.ExtUserPtr?.Email ||
|
||||||
|
"",
|
||||||
extUserId: doc?.ExtUserPtr?.objectId,
|
extUserId: doc?.ExtUserPtr?.objectId,
|
||||||
recipient: userDetails?.Email,
|
recipient: userDetails?.Email,
|
||||||
subject: mail.subject,
|
subject: mail.subject,
|
||||||
from: doc?.ExtUserPtr?.Email,
|
from:
|
||||||
|
doc?.ExtUserPtr?.Email,
|
||||||
html: mail.body
|
html: mail.body
|
||||||
};
|
};
|
||||||
try {
|
try {
|
||||||
@@ -775,7 +793,8 @@ const ReportTable = (props) => {
|
|||||||
if (res?.data?.result?.status === "success") {
|
if (res?.data?.result?.status === "success") {
|
||||||
showAlert("success", t("mail-sent-alert"));
|
showAlert("success", t("mail-sent-alert"));
|
||||||
setIsResendMail({});
|
setIsResendMail({});
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
showAlert("danger", t("something-went-wrong-mssg"));
|
showAlert("danger", t("something-went-wrong-mssg"));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -1718,7 +1737,9 @@ const ReportTable = (props) => {
|
|||||||
<i className={act.btnIcon}></i>
|
<i className={act.btnIcon}></i>
|
||||||
{act.btnLabel && (
|
{act.btnLabel && (
|
||||||
<span className="uppercase font-medium">
|
<span className="uppercase font-medium">
|
||||||
{`${t(`btnLabel.${act.btnLabel}`)}`}
|
{
|
||||||
|
`${t(`btnLabel.${act.btnLabel}`)}`
|
||||||
|
}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{/* template report */}
|
{/* template report */}
|
||||||
@@ -1802,9 +1823,7 @@ const ReportTable = (props) => {
|
|||||||
title={t(`btnLabel.${act.hoverLabel}`)}
|
title={t(`btnLabel.${act.hoverLabel}`)}
|
||||||
className={
|
className={
|
||||||
act.action !== "option"
|
act.action !== "option"
|
||||||
? `${
|
? `${act?.btnColor || ""} op-btn op-btn-sm mr-1`
|
||||||
act?.btnColor || ""
|
|
||||||
} op-btn op-btn-sm mr-1`
|
|
||||||
: "text-base-content focus:outline-none text-lg mr-2 relative"
|
: "text-base-content focus:outline-none text-lg mr-2 relative"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -1930,7 +1949,9 @@ const ReportTable = (props) => {
|
|||||||
}
|
}
|
||||||
>
|
>
|
||||||
<i className="fa-light fa-plus"></i>{" "}
|
<i className="fa-light fa-plus"></i>{" "}
|
||||||
{`${t(`btnLabel.Quick send`)}`}
|
{
|
||||||
|
`${t(`btnLabel.Quick send`)}`
|
||||||
|
}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
className="op-btn-secondary op-btn op-btn-sm focus:outline-none text-sm relative"
|
className="op-btn-secondary op-btn op-btn-sm focus:outline-none text-sm relative"
|
||||||
@@ -2011,26 +2032,28 @@ const ReportTable = (props) => {
|
|||||||
{isShareWith[item.objectId] && (
|
{isShareWith[item.objectId] && (
|
||||||
<div className="op-modal op-modal-open">
|
<div className="op-modal op-modal-open">
|
||||||
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
<div className="max-h-90 bg-base-100 w-[95%] md:max-w-[500px] rounded-box relative">
|
||||||
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
<h3 className="text-base-content font-bold text-lg pt-[15px] px-[20px]">
|
||||||
{t("share-with")}
|
{t("share-with")}
|
||||||
</h3>
|
</h3>
|
||||||
<div
|
<div
|
||||||
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
className="op-btn op-btn-sm op-btn-circle op-btn-ghost text-base-content absolute right-2 top-2 z-40"
|
||||||
onClick={() => setIsShareWith({})}
|
onClick={() => setIsShareWith({})}
|
||||||
>
|
>
|
||||||
✕
|
✕
|
||||||
</div>
|
</div>
|
||||||
<div className="px-2 mt-3 w-full h-full">
|
<div className="px-2 mt-3 w-full h-full">
|
||||||
<div className="op-input op-input-bordered op-input-sm w-full h-full text-[13px] break-all">
|
<div className="op-input op-input-bordered op-input-sm w-full h-full text-[13px] break-all">
|
||||||
{selectedTeam?.[0]?.label}
|
{selectedTeam?.[0]?.label}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => handleShareWith(e, item)}
|
onClick={(e) =>
|
||||||
className="op-btn op-btn-primary ml-[10px] my-3"
|
handleShareWith(e, item)
|
||||||
>
|
}
|
||||||
{t("submit")}
|
className="op-btn op-btn-primary ml-[10px] my-3"
|
||||||
</button>
|
>
|
||||||
|
{t("submit")}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -2121,7 +2144,9 @@ const ReportTable = (props) => {
|
|||||||
{isBulkSend[item.objectId] && (
|
{isBulkSend[item.objectId] && (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen
|
isOpen
|
||||||
title={t("quick-send")}
|
title={
|
||||||
|
t("quick-send")
|
||||||
|
}
|
||||||
handleClose={() => setIsBulkSend({})}
|
handleClose={() => setIsBulkSend({})}
|
||||||
>
|
>
|
||||||
{isLoader[item.objectId] ? (
|
{isLoader[item.objectId] ? (
|
||||||
@@ -2228,104 +2253,106 @@ const ReportTable = (props) => {
|
|||||||
{isResendMail[item.objectId] && (
|
{isResendMail[item.objectId] && (
|
||||||
<ModalUi
|
<ModalUi
|
||||||
isOpen
|
isOpen
|
||||||
title={t("resend-mail")}
|
title={
|
||||||
|
t("resend-mail")
|
||||||
|
}
|
||||||
handleClose={handleResendClose}
|
handleClose={handleResendClose}
|
||||||
>
|
>
|
||||||
<div className="overflow-y-auto max-h-[340px] md:max-h-[400px]">
|
<div className="overflow-y-auto max-h-[340px] md:max-h-[400px]">
|
||||||
{item?.Placeholders?.map((user) => (
|
{item?.Placeholders?.map((user) => (
|
||||||
<React.Fragment key={user.Id}>
|
<React.Fragment key={user.Id}>
|
||||||
{isNextStep[user.Id] && (
|
{isNextStep[user.Id] && (
|
||||||
<div className="relative ">
|
<div className="relative ">
|
||||||
{actLoader[user.Id] && (
|
{actLoader[user.Id] && (
|
||||||
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30">
|
<div className="absolute w-full h-full flex justify-center items-center bg-black bg-opacity-30 z-30">
|
||||||
<Loader />
|
<Loader />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) =>
|
onSubmit={(e) =>
|
||||||
handleResendMail(e, item, user)
|
handleResendMail(e, item, user)
|
||||||
}
|
}
|
||||||
className="w-full flex flex-col gap-2 p-3 text-base-content relative"
|
className="w-full flex flex-col gap-2 p-3 text-base-content relative"
|
||||||
>
|
|
||||||
<div className="absolute right-5 text-xs z-40">
|
|
||||||
<Tooltip
|
|
||||||
id={`${user.Id}_help`}
|
|
||||||
message={t("resend-mail-help")}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="text-xs ml-1"
|
|
||||||
htmlFor="mailsubject"
|
|
||||||
>
|
|
||||||
{t("subject")}{" "}
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="mailsubject"
|
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
|
||||||
value={mail.subject}
|
|
||||||
onChange={(e) =>
|
|
||||||
handleSubjectChange(
|
|
||||||
e.target.value,
|
|
||||||
item
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onInvalid={(e) =>
|
|
||||||
e.target.setCustomValidity(
|
|
||||||
t("input-required")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
onInput={(e) =>
|
|
||||||
e.target.setCustomValidity("")
|
|
||||||
}
|
|
||||||
required
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label
|
|
||||||
className="text-xs ml-1"
|
|
||||||
htmlFor="mailbody"
|
|
||||||
>
|
|
||||||
{t("body")}{" "}
|
|
||||||
</label>
|
|
||||||
<EditorToolbar containerId="toolbar1" />
|
|
||||||
<ReactQuill
|
|
||||||
id="mailbody"
|
|
||||||
theme="snow"
|
|
||||||
value={mail.body || ""}
|
|
||||||
placeholder="add body of email "
|
|
||||||
modules={module1}
|
|
||||||
formats={formats}
|
|
||||||
onChange={(value) =>
|
|
||||||
handlebodyChange(value, item)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="op-btn op-btn-primary"
|
|
||||||
>
|
>
|
||||||
{t("resend")}
|
<div className="absolute right-5 text-xs z-40">
|
||||||
</button>
|
<Tooltip
|
||||||
</form>
|
id={`${user.Id}_help`}
|
||||||
</div>
|
message={t("resend-mail-help")}
|
||||||
)}
|
/>
|
||||||
{Object?.keys(isNextStep) <= 0 && (
|
</div>
|
||||||
<div className="flex justify-between items-center gap-2 my-2 px-3">
|
<div>
|
||||||
<div className="text-black">
|
<label
|
||||||
{user?.signerPtr?.Name || "-"}{" "}
|
className="text-xs ml-1"
|
||||||
{`<${
|
htmlFor="mailsubject"
|
||||||
user?.email
|
>
|
||||||
? user.email
|
{t("subject")}{" "}
|
||||||
: user.signerPtr.Email
|
</label>
|
||||||
}>`}
|
<input
|
||||||
|
id="mailsubject"
|
||||||
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
|
value={mail.subject}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleSubjectChange(
|
||||||
|
e.target.value,
|
||||||
|
item
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onInvalid={(e) =>
|
||||||
|
e.target.setCustomValidity(
|
||||||
|
t("input-required")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onInput={(e) =>
|
||||||
|
e.target.setCustomValidity("")
|
||||||
|
}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label
|
||||||
|
className="text-xs ml-1"
|
||||||
|
htmlFor="mailbody"
|
||||||
|
>
|
||||||
|
{t("body")}{" "}
|
||||||
|
</label>
|
||||||
|
<EditorToolbar containerId="toolbar1" />
|
||||||
|
<ReactQuill
|
||||||
|
id="mailbody"
|
||||||
|
theme="snow"
|
||||||
|
value={mail.body || ""}
|
||||||
|
placeholder="add body of email "
|
||||||
|
modules={module1}
|
||||||
|
formats={formats}
|
||||||
|
onChange={(value) =>
|
||||||
|
handlebodyChange(value, item)
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="op-btn op-btn-primary"
|
||||||
|
>
|
||||||
|
{t("resend")}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<>{fetchUserStatus(user, item)}</>
|
)}
|
||||||
</div>
|
{Object?.keys(isNextStep) <= 0 && (
|
||||||
)}
|
<div className="flex justify-between items-center gap-2 my-2 px-3">
|
||||||
</React.Fragment>
|
<div className="text-black">
|
||||||
))}
|
{user?.signerPtr?.Name || "-"}{" "}
|
||||||
</div>
|
{`<${
|
||||||
|
user?.email
|
||||||
|
? user.email
|
||||||
|
: user.signerPtr.Email
|
||||||
|
}>`}
|
||||||
|
</div>
|
||||||
|
<>{fetchUserStatus(user, item)}</>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</React.Fragment>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
)}
|
)}
|
||||||
<ModalUi
|
<ModalUi
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user