mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-10 19:57:40 +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;
|
||||||
+9
-6
@@ -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([]);
|
||||||
@@ -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);
|
||||||
@@ -159,16 +162,15 @@ const BulkSendUi = (props) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
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,6 +32,7 @@ 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) {
|
||||||
+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={() =>
|
||||||
+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,8 +1022,7 @@ 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;
|
||||||
@@ -1023,7 +1035,8 @@ export const addInitialData = (signerPos, setXyPosition, value, userId) => {
|
|||||||
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: {
|
||||||
@@ -2132,13 +2153,18 @@ export const getAppLogo = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
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,7 +2714,10 @@ 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 });
|
||||||
@@ -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();
|
||||||
@@ -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";
|
||||||
+3
-1
@@ -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";
|
||||||
|
|
||||||
@@ -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);
|
||||||
@@ -239,7 +240,9 @@ const Forms = (props) => {
|
|||||||
if (fileRes.url) {
|
if (fileRes.url) {
|
||||||
setFileUpload(fileRes.url);
|
setFileUpload(fileRes.url);
|
||||||
removeFile();
|
removeFile();
|
||||||
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");
|
const tenantId = localStorage.getItem("TenantId");
|
||||||
SaveFileSize(size, fileRes.url, tenantId);
|
SaveFileSize(size, fileRes.url, tenantId);
|
||||||
@@ -451,7 +454,8 @@ const Forms = (props) => {
|
|||||||
setSigners([]);
|
setSigners([]);
|
||||||
setBcc([]);
|
setBcc([]);
|
||||||
setFolder({ ObjectId: "", Name: "" });
|
setFolder({ ObjectId: "", Name: "" });
|
||||||
const notifySign = extUserData?.NotifyOnSignatures
|
const notifySign =
|
||||||
|
extUserData?.NotifyOnSignatures
|
||||||
? extUserData?.NotifyOnSignatures
|
? extUserData?.NotifyOnSignatures
|
||||||
: true;
|
: true;
|
||||||
setFormData({
|
setFormData({
|
||||||
@@ -529,7 +533,8 @@ const Forms = (props) => {
|
|||||||
setSigners([]);
|
setSigners([]);
|
||||||
setBcc([]);
|
setBcc([]);
|
||||||
setFolder({ ObjectId: "", Name: "" });
|
setFolder({ ObjectId: "", Name: "" });
|
||||||
const notifySign = extUserData?.NotifyOnSignatures
|
const notifySign =
|
||||||
|
extUserData?.NotifyOnSignatures
|
||||||
? extUserData?.NotifyOnSignatures
|
? extUserData?.NotifyOnSignatures
|
||||||
: true;
|
: true;
|
||||||
let obj = {
|
let obj = {
|
||||||
@@ -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, ""))) {
|
||||||
@@ -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,37 +151,25 @@ 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 &&
|
userRole && userSettings.find((menu) => menu.role === userRole);
|
||||||
userSettings.find((menu) => menu.role === userRole);
|
|
||||||
if (menu) {
|
if (menu) {
|
||||||
const _currentRole = userRole;
|
const _currentRole = userRole;
|
||||||
const redirectUrl =
|
const redirectUrl =
|
||||||
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
location?.state?.from || `/${menu.pageType}/${menu.pageId}`;
|
||||||
const _role = _currentRole.replace("contracts_", "");
|
const _role = _currentRole.replace("contracts_", "");
|
||||||
localStorage.setItem("_user_role", _role);
|
|
||||||
const results = [extUser];
|
|
||||||
const extUser_stringify = JSON.stringify(results);
|
|
||||||
localStorage.setItem("Extand_Class", extUser_stringify);
|
|
||||||
const extInfo = JSON.parse(JSON.stringify(extUser));
|
const extInfo = JSON.parse(JSON.stringify(extUser));
|
||||||
|
localStorage.setItem("_user_role", _role);
|
||||||
|
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) {
|
||||||
@@ -206,16 +197,11 @@ function Login() {
|
|||||||
showToast("danger", t("user-not-found"));
|
showToast("danger", t("user-not-found"));
|
||||||
logOutUser();
|
logOutUser();
|
||||||
}
|
}
|
||||||
})
|
} catch (error) {
|
||||||
.catch((err) => {
|
|
||||||
console.error("err in fetching extUser", err);
|
console.error("err in fetching extUser", err);
|
||||||
showToast("danger", `${err.message}`);
|
showToast("danger", `${err.message}`);
|
||||||
const payload = { sessionToken: sessionToken };
|
const payload = { sessionToken: _user.sessionToken };
|
||||||
handleSubmitbtn(payload);
|
handleSubmitbtn(payload);
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
showToast("danger", `${error.message}`);
|
|
||||||
console.log(error);
|
|
||||||
} 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,7 +244,6 @@ 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 });
|
||||||
@@ -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,7 +376,6 @@ 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 {
|
||||||
@@ -489,14 +461,18 @@ function Login() {
|
|||||||
<div className="relative">
|
<div className="relative">
|
||||||
<input
|
<input
|
||||||
id="password"
|
id="password"
|
||||||
type={state.passwordVisible ? "text" : "password"}
|
type={
|
||||||
|
state.passwordVisible ? "text" : "password"
|
||||||
|
}
|
||||||
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
className="op-input op-input-bordered op-input-sm focus:outline-none hover:border-base-content w-full text-xs"
|
||||||
name="password"
|
name="password"
|
||||||
value={state.password}
|
value={state.password}
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onInvalid={(e) =>
|
onInvalid={(e) =>
|
||||||
e.target.setCustomValidity(t("input-required"))
|
e.target.setCustomValidity(
|
||||||
|
t("input-required")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
onInput={(e) => e.target.setCustomValidity("")}
|
onInput={(e) => e.target.setCustomValidity("")}
|
||||||
required
|
required
|
||||||
+11
-12
@@ -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();
|
||||||
@@ -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
|
||||||
+122
-55
@@ -42,7 +42,8 @@ import {
|
|||||||
textWidget,
|
textWidget,
|
||||||
compressedFileSize,
|
compressedFileSize,
|
||||||
mailTemplate,
|
mailTemplate,
|
||||||
updateDateWidgetsRes
|
updateDateWidgetsRes,
|
||||||
|
widgetDataValue
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import Header from "../components/pdf/PdfHeader";
|
import Header from "../components/pdf/PdfHeader";
|
||||||
import RenderPdf from "../components/pdf/RenderPdf";
|
import RenderPdf from "../components/pdf/RenderPdf";
|
||||||
@@ -65,9 +66,11 @@ import WidgetComponent from "../components/pdf/WidgetComponent";
|
|||||||
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
import PlaceholderCopy from "../components/pdf/PlaceholderCopy";
|
||||||
import TextFontSetting from "../components/pdf/TextFontSetting";
|
import TextFontSetting from "../components/pdf/TextFontSetting";
|
||||||
|
|
||||||
function PdfRequestFiles() {
|
function PdfRequestFiles(
|
||||||
|
) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const appName = "OpenSign™";
|
const appName =
|
||||||
|
"OpenSign™";
|
||||||
const [pdfDetails, setPdfDetails] = useState([]);
|
const [pdfDetails, setPdfDetails] = useState([]);
|
||||||
const [signedSigners, setSignedSigners] = useState([]);
|
const [signedSigners, setSignedSigners] = useState([]);
|
||||||
const [unsignedSigners, setUnSignedSigners] = useState([]);
|
const [unsignedSigners, setUnSignedSigners] = useState([]);
|
||||||
@@ -171,8 +174,10 @@ function PdfRequestFiles() {
|
|||||||
let sendmail;
|
let sendmail;
|
||||||
let getDocId = "";
|
let getDocId = "";
|
||||||
let contactBookId = "";
|
let contactBookId = "";
|
||||||
const route = window.location.pathname;
|
const route =
|
||||||
const getQuery = window.location?.search?.split("?"); //['','sendmail=false']
|
window.location.pathname;
|
||||||
|
const getQuery =
|
||||||
|
window.location?.search?.split("?"); //['','sendmail=false']
|
||||||
if (getQuery) {
|
if (getQuery) {
|
||||||
sendmail = getQuery?.[1]?.split("=")[1]; //false
|
sendmail = getQuery?.[1]?.split("=")[1]; //false
|
||||||
}
|
}
|
||||||
@@ -195,7 +200,9 @@ function PdfRequestFiles() {
|
|||||||
getDocumentDetails(getDocumentId);
|
getDocumentDetails(getDocumentId);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [getDocumentId]);
|
}, [
|
||||||
|
getDocumentId
|
||||||
|
]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const updateSize = () => {
|
const updateSize = () => {
|
||||||
if (divRef.current) {
|
if (divRef.current) {
|
||||||
@@ -252,21 +259,22 @@ function PdfRequestFiles() {
|
|||||||
alert(t("user-not-exist"));
|
alert(t("user-not-exist"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//function for get document details for perticular signer with signer'object id
|
//function for get document details for perticular signer with signer'object id
|
||||||
const getDocumentDetails = async (
|
const getDocumentDetails = async (
|
||||||
docId,
|
docId,
|
||||||
isNextUser,
|
isNextUser,
|
||||||
isSuccessPage = false
|
isSuccessPage = false,
|
||||||
|
publiccontactId
|
||||||
) => {
|
) => {
|
||||||
try {
|
try {
|
||||||
|
let isUpdatedSubscribe;
|
||||||
const senderUser = localStorage.getItem(
|
const senderUser = localStorage.getItem(
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
);
|
);
|
||||||
const jsonSender = JSON.parse(senderUser);
|
const jsonSender = JSON.parse(senderUser);
|
||||||
const contactId = jsonSender?.objectId
|
const contactId = jsonSender?.objectId
|
||||||
? ""
|
? ""
|
||||||
: contactBookId || signerObjectId || "";
|
: contactBookId || publiccontactId || signerObjectId || "";
|
||||||
const tenantSignTypes = await fetchTenantDetails(contactId);
|
const tenantSignTypes = await fetchTenantDetails(contactId);
|
||||||
// `currUserId` will be contactId or extUserId
|
// `currUserId` will be contactId or extUserId
|
||||||
let currUserId;
|
let currUserId;
|
||||||
@@ -314,7 +322,7 @@ function PdfRequestFiles() {
|
|||||||
|
|
||||||
currUserId = getCurrentSigner?.objectId
|
currUserId = getCurrentSigner?.objectId
|
||||||
? getCurrentSigner.objectId
|
? getCurrentSigner.objectId
|
||||||
: contactBookId || signerObjectId || ""; //signerObjectId is contactBookId refer from public template flow
|
: contactBookId || publiccontactId || signerObjectId || ""; //signerObjectId is contactBookId refer from public template flow
|
||||||
if (currUserId) {
|
if (currUserId) {
|
||||||
setSignerObjectId(currUserId);
|
setSignerObjectId(currUserId);
|
||||||
}
|
}
|
||||||
@@ -434,9 +442,7 @@ function PdfRequestFiles() {
|
|||||||
//in unsignedsigners array
|
//in unsignedsigners array
|
||||||
setUnSignedSigners(placeholdersOrSigners);
|
setUnSignedSigners(placeholdersOrSigners);
|
||||||
}
|
}
|
||||||
setSignerPos(
|
setSignerPos(updateDateWidgetsRes(documentData[0], currUserId));
|
||||||
updateDateWidgetsRes(documentData[0].Placeholders, currUserId)
|
|
||||||
);
|
|
||||||
setPdfDetails(documentData);
|
setPdfDetails(documentData);
|
||||||
//checking if condition current user already sign or owner does not exist as a signer or document has been declined by someone or document has been expired
|
//checking if condition current user already sign or owner does not exist as a signer or document has been declined by someone or document has been expired
|
||||||
//then stop to display tour message
|
//then stop to display tour message
|
||||||
@@ -548,7 +554,9 @@ function PdfRequestFiles() {
|
|||||||
}
|
}
|
||||||
setIsUiLoading(false);
|
setIsUiLoading(false);
|
||||||
setIsLoading({ isLoad: false });
|
setIsLoading({ isLoad: false });
|
||||||
return updatedPdfDetails;
|
return {
|
||||||
|
updatedPdfDetails,
|
||||||
|
};
|
||||||
} else if (
|
} else if (
|
||||||
documentData === "Error: Something went wrong!" ||
|
documentData === "Error: Something went wrong!" ||
|
||||||
(documentData.result && documentData.result.error)
|
(documentData.result && documentData.result.error)
|
||||||
@@ -573,7 +581,16 @@ function PdfRequestFiles() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
//function for embed signature or image url in pdf
|
//function for embed signature or image url in pdf
|
||||||
async function embedWidgetsData() {
|
async function embedWidgetsData(publiccontactId, publicDocId) {
|
||||||
|
let contactId = publiccontactId || signerObjectId;
|
||||||
|
let docId = publicDocId || documentId;
|
||||||
|
const addExtraDays = pdfDetails[0]?.TimeToCompleteDays
|
||||||
|
? pdfDetails[0].TimeToCompleteDays
|
||||||
|
: 15;
|
||||||
|
let updateExpiryDate;
|
||||||
|
updateExpiryDate = new Date();
|
||||||
|
updateExpiryDate.setDate(updateExpiryDate.getDate() + addExtraDays);
|
||||||
|
const expiry = updateExpiryDate || pdfDetails?.[0].ExpiryDate.iso;
|
||||||
//for emailVerified data checking first in localstorage
|
//for emailVerified data checking first in localstorage
|
||||||
const localuser = localStorage.getItem(
|
const localuser = localStorage.getItem(
|
||||||
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
@@ -759,7 +776,7 @@ function PdfRequestFiles() {
|
|||||||
let pdfArrBuffer;
|
let pdfArrBuffer;
|
||||||
//`contractDocument` function used to get updated SignedUrl
|
//`contractDocument` function used to get updated SignedUrl
|
||||||
// to resolve issue of widgets get remove automatically when more than 1 signers try to sign doc at a time
|
// to resolve issue of widgets get remove automatically when more than 1 signers try to sign doc at a time
|
||||||
const documentData = await contractDocument(documentId);
|
const documentData = await contractDocument(docId);
|
||||||
if (documentData && documentData.length > 0) {
|
if (documentData && documentData.length > 0) {
|
||||||
const url = documentData[0]?.SignedUrl || documentData[0]?.URL;
|
const url = documentData[0]?.SignedUrl || documentData[0]?.URL;
|
||||||
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
//convert document url in array buffer format to use embed widgets in pdf using pdf-lib
|
||||||
@@ -791,7 +808,7 @@ function PdfRequestFiles() {
|
|||||||
//embed document's object id to all pages in pdf document
|
//embed document's object id to all pages in pdf document
|
||||||
if (!HeaderDocId) {
|
if (!HeaderDocId) {
|
||||||
if (!isDocId) {
|
if (!isDocId) {
|
||||||
await embedDocId(pdfDoc, documentId, allPages);
|
await embedDocId(pdfDoc, docId, allPages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//embed multi signature in pdf
|
//embed multi signature in pdf
|
||||||
@@ -808,8 +825,8 @@ function PdfRequestFiles() {
|
|||||||
//function for call to embed signature in pdf and get digital signature pdf
|
//function for call to embed signature in pdf and get digital signature pdf
|
||||||
const resSign = await signPdfFun(
|
const resSign = await signPdfFun(
|
||||||
pdfBytes,
|
pdfBytes,
|
||||||
documentId,
|
docId,
|
||||||
signerObjectId,
|
contactId,
|
||||||
objectId,
|
objectId,
|
||||||
widgets
|
widgets
|
||||||
);
|
);
|
||||||
@@ -821,10 +838,11 @@ function PdfRequestFiles() {
|
|||||||
const isSuccessRoute = pdfDetails?.[0]?.RedirectUrl
|
const isSuccessRoute = pdfDetails?.[0]?.RedirectUrl
|
||||||
? false
|
? false
|
||||||
: window.location?.pathname?.includes("load");
|
: window.location?.pathname?.includes("load");
|
||||||
const updateDoc = await getDocumentDetails(
|
const updatedDoc = await getDocumentDetails(
|
||||||
documentId,
|
docId,
|
||||||
true,
|
true,
|
||||||
isSuccessRoute
|
isSuccessRoute,
|
||||||
|
contactId
|
||||||
);
|
);
|
||||||
const index = pdfDetails?.[0]?.Signers.findIndex(
|
const index = pdfDetails?.[0]?.Signers.findIndex(
|
||||||
(x) => x.objectId === signerObjectId
|
(x) => x.objectId === signerObjectId
|
||||||
@@ -837,23 +855,25 @@ function PdfRequestFiles() {
|
|||||||
? usermail
|
? usermail
|
||||||
: pdfDetails?.[0]?.Signers[newIndex];
|
: pdfDetails?.[0]?.Signers[newIndex];
|
||||||
if (sendmail !== "false" && sendInOrder) {
|
if (sendmail !== "false" && sendInOrder) {
|
||||||
const requestBody = pdfDetails?.[0]?.RequestBody;
|
const requestBody =
|
||||||
const requestSubject = pdfDetails?.[0]?.RequestSubject;
|
updatedDoc.updatedPdfDetails?.[0]?.RequestBody;
|
||||||
|
const requestSubject =
|
||||||
|
updatedDoc.updatedPdfDetails?.[0]?.RequestSubject;
|
||||||
if (user) {
|
if (user) {
|
||||||
const expireDate = pdfDetails?.[0].ExpiryDate.iso;
|
const expireDate = expiry;
|
||||||
const newDate = new Date(expireDate);
|
const newDate = new Date(expireDate);
|
||||||
const localExpireDate = newDate.toLocaleDateString(
|
const localExpireDate = newDate.toLocaleDateString(
|
||||||
"en-US",
|
"en-US",
|
||||||
{ day: "numeric", month: "long", year: "numeric" }
|
{ day: "numeric", month: "long", 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;
|
||||||
const senderName = pdfDetails?.[0].ExtUserPtr.Name;
|
const senderName =
|
||||||
|
pdfDetails?.[0].ExtUserPtr.Name;
|
||||||
const documentName = pdfDetails?.[0].Name;
|
const documentName = pdfDetails?.[0].Name;
|
||||||
try {
|
try {
|
||||||
let url = `${localStorage.getItem(
|
let url = `${localStorage.getItem("baseUrl")}functions/sendmailv3`;
|
||||||
"baseUrl"
|
|
||||||
)}functions/sendmailv3`;
|
|
||||||
const headers = {
|
const headers = {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
"X-Parse-Application-Id":
|
"X-Parse-Application-Id":
|
||||||
@@ -866,19 +886,21 @@ function PdfRequestFiles() {
|
|||||||
let encodeBase64;
|
let encodeBase64;
|
||||||
if (objectId) {
|
if (objectId) {
|
||||||
encodeBase64 = btoa(
|
encodeBase64 = btoa(
|
||||||
`${pdfDetails?.[0].objectId}/${user.Email}/${objectId}`
|
`${docId}/${user.Email}/${objectId}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
encodeBase64 = btoa(
|
encodeBase64 = btoa(`${docId}/${user.Email}`);
|
||||||
`${pdfDetails?.[0].objectId}/${user.Email}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
let signPdf = `${hostUrl}/login/${encodeBase64}`;
|
let signPdf =
|
||||||
|
`${hostUrl}/login/${encodeBase64}`;
|
||||||
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
const orgName = pdfDetails[0]?.ExtUserPtr.Company
|
||||||
? pdfDetails[0].ExtUserPtr.Company
|
? pdfDetails[0].ExtUserPtr.Company
|
||||||
: "";
|
: "";
|
||||||
let replaceVar;
|
let replaceVar;
|
||||||
if (requestBody && requestSubject) {
|
if (
|
||||||
|
requestBody &&
|
||||||
|
requestSubject
|
||||||
|
) {
|
||||||
const replacedRequestBody = requestBody.replace(
|
const replacedRequestBody = requestBody.replace(
|
||||||
/"/g,
|
/"/g,
|
||||||
"'"
|
"'"
|
||||||
@@ -923,7 +945,8 @@ function PdfRequestFiles() {
|
|||||||
subject: replaceVar?.subject
|
subject: replaceVar?.subject
|
||||||
? replaceVar?.subject
|
? replaceVar?.subject
|
||||||
: mailTemplate(mailparam).subject,
|
: mailTemplate(mailparam).subject,
|
||||||
from: senderEmail,
|
from:
|
||||||
|
senderEmail,
|
||||||
html: replaceVar?.body
|
html: replaceVar?.body
|
||||||
? replaceVar?.body
|
? replaceVar?.body
|
||||||
: mailTemplate(mailparam).body
|
: mailTemplate(mailparam).body
|
||||||
@@ -938,16 +961,15 @@ function PdfRequestFiles() {
|
|||||||
setIsredirectCanceled(false);
|
setIsredirectCanceled(false);
|
||||||
} else {
|
} else {
|
||||||
const url =
|
const url =
|
||||||
updateDoc?.[0]?.SignedUrl || updateDoc?.[0]?.URL;
|
updatedDoc.updatedPdfDetails?.[0]?.SignedUrl ||
|
||||||
const fileAdapter = "";
|
updatedDoc.updatedPdfDetails?.[0]?.URL;
|
||||||
const isCompleted = updateDoc?.[0]?.IsCompleted
|
const fileAdapter =
|
||||||
|
"";
|
||||||
|
const isCompleted = updatedDoc.updatedPdfDetails?.[0]
|
||||||
|
?.IsCompleted
|
||||||
? `&completed=true`
|
? `&completed=true`
|
||||||
: "";
|
: "";
|
||||||
const params = `docid=${
|
const params = `docid=${updatedDoc.updatedPdfDetails[0].objectId}&docurl=${encodeURIComponent(url)}${isCompleted}${fileAdapter}`;
|
||||||
updateDoc[0].objectId
|
|
||||||
}&docurl=${encodeURIComponent(
|
|
||||||
url
|
|
||||||
)}${isCompleted}${fileAdapter}`;
|
|
||||||
window.location.href = `/success?${params}`;
|
window.location.href = `/success?${params}`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1000,6 +1022,32 @@ function PdfRequestFiles() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSignPdf = async () => {
|
||||||
|
if (props.templateId) {
|
||||||
|
const params = {
|
||||||
|
...contact,
|
||||||
|
templateid: pdfDetails[0]?.objectId,
|
||||||
|
role: pdfDetails[0]?.PublicRole[0]
|
||||||
|
};
|
||||||
|
const linkRes = await axios.post(
|
||||||
|
`${localStorage.getItem(
|
||||||
|
"baseUrl"
|
||||||
|
)}/functions/publicuserlinkcontacttodoc`,
|
||||||
|
params,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"X-Parse-Application-Id": localStorage.getItem("parseAppId")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const contactId = linkRes.data.result?.contactId;
|
||||||
|
const docId = linkRes.data?.result?.docId;
|
||||||
|
await embedWidgetsData(contactId, docId);
|
||||||
|
} else {
|
||||||
|
await embedWidgetsData();
|
||||||
|
}
|
||||||
|
};
|
||||||
//function for save x and y position and show signature tab on that position
|
//function for save x and y position and show signature tab on that position
|
||||||
const handleTabDrag = (key) => {
|
const handleTabDrag = (key) => {
|
||||||
setDragKey(key);
|
setDragKey(key);
|
||||||
@@ -1528,6 +1576,7 @@ function PdfRequestFiles() {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
const clickOnZoomIn = () => {
|
const clickOnZoomIn = () => {
|
||||||
onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent);
|
onClickZoomIn(scale, zoomPercent, setScale, setZoomPercent);
|
||||||
};
|
};
|
||||||
@@ -1650,6 +1699,9 @@ function PdfRequestFiles() {
|
|||||||
defaultWidthHeight(dragTypeValue).width * containerScale;
|
defaultWidthHeight(dragTypeValue).width * containerScale;
|
||||||
const widgetHeight =
|
const widgetHeight =
|
||||||
defaultWidthHeight(dragTypeValue).height * containerScale;
|
defaultWidthHeight(dragTypeValue).height * containerScale;
|
||||||
|
const extUser = localStorage.getItem("Extand_Class");
|
||||||
|
const parseUser = extUser && JSON.parse(extUser)[0];
|
||||||
|
const widgetValue = widgetDataValue(dragTypeValue, parseUser);
|
||||||
//adding and updating drop position in array when user drop signature button in div
|
//adding and updating drop position in array when user drop signature button in div
|
||||||
if (item === "onclick") {
|
if (item === "onclick") {
|
||||||
const divHeight = divRef.current.getBoundingClientRect().height;
|
const divHeight = divRef.current.getBoundingClientRect().height;
|
||||||
@@ -1664,7 +1716,7 @@ function PdfRequestFiles() {
|
|||||||
scale: containerScale,
|
scale: containerScale,
|
||||||
zIndex: posZIndex,
|
zIndex: posZIndex,
|
||||||
type: dragTypeValue,
|
type: dragTypeValue,
|
||||||
options: addWidgetOptions(dragTypeValue, owner),
|
options: addWidgetOptions(dragTypeValue, owner, widgetValue),
|
||||||
Width: widgetWidth / (containerScale * scale),
|
Width: widgetWidth / (containerScale * scale),
|
||||||
Height: widgetHeight / (containerScale * scale)
|
Height: widgetHeight / (containerScale * scale)
|
||||||
};
|
};
|
||||||
@@ -1691,7 +1743,7 @@ function PdfRequestFiles() {
|
|||||||
scale: containerScale,
|
scale: containerScale,
|
||||||
zIndex: posZIndex,
|
zIndex: posZIndex,
|
||||||
type: dragTypeValue,
|
type: dragTypeValue,
|
||||||
options: addWidgetOptions(dragTypeValue, owner),
|
options: addWidgetOptions(dragTypeValue, owner, widgetValue),
|
||||||
Width: widgetWidth / (containerScale * scale),
|
Width: widgetWidth / (containerScale * scale),
|
||||||
Height: widgetHeight / (containerScale * scale)
|
Height: widgetHeight / (containerScale * scale)
|
||||||
};
|
};
|
||||||
@@ -1842,7 +1894,11 @@ function PdfRequestFiles() {
|
|||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<DndProvider backend={HTML5Backend}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<Title title={"Request Sign"} />
|
<Title
|
||||||
|
title={
|
||||||
|
"Request Sign"
|
||||||
|
}
|
||||||
|
/>
|
||||||
{isLoading.isLoad ? (
|
{isLoading.isLoad ? (
|
||||||
<LoaderWithMsg isLoading={isLoading} />
|
<LoaderWithMsg isLoading={isLoading} />
|
||||||
) : handleError ? (
|
) : handleError ? (
|
||||||
@@ -1899,7 +1955,9 @@ function PdfRequestFiles() {
|
|||||||
: "auto"
|
: "auto"
|
||||||
}}
|
}}
|
||||||
className={`${
|
className={`${
|
||||||
isGuestSignFlow ? "border-[0.5px] border-gray-300" : "op-card"
|
isGuestSignFlow
|
||||||
|
? "border-[0.5px] border-gray-300"
|
||||||
|
: "op-card"
|
||||||
} relative overflow-hidden flex flex-col md:flex-row justify-between bg-base-300`}
|
} relative overflow-hidden flex flex-col md:flex-row justify-between bg-base-300`}
|
||||||
>
|
>
|
||||||
{!requestSignTour &&
|
{!requestSignTour &&
|
||||||
@@ -2030,7 +2088,8 @@ function PdfRequestFiles() {
|
|||||||
setIsCompleted((prev) => ({ ...prev, isModal: false }))
|
setIsCompleted((prev) => ({ ...prev, isModal: false }))
|
||||||
}
|
}
|
||||||
reduceWidth={
|
reduceWidth={
|
||||||
!isCompleted?.message && "md:min-w-[440px] md:max-w-[400px]"
|
!isCompleted?.message &&
|
||||||
|
"md:min-w-[440px] md:max-w-[400px]"
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
<div className="h-full p-[20px] text-base-content">
|
<div className="h-full p-[20px] text-base-content">
|
||||||
@@ -2039,7 +2098,9 @@ function PdfRequestFiles() {
|
|||||||
<p>{isCompleted?.message}</p>
|
<p>{isCompleted?.message}</p>
|
||||||
{!isredirectCanceled && redirectUrl && (
|
{!isredirectCanceled && redirectUrl && (
|
||||||
<div className="flex flex-row gap-1 items-center justify-center mb-3 mt-2">
|
<div className="flex flex-row gap-1 items-center justify-center mb-3 mt-2">
|
||||||
<p>Redirecting you in {redirectTimeLeft} sec...</p>
|
<p>
|
||||||
|
Redirecting you in {redirectTimeLeft} sec...
|
||||||
|
</p>
|
||||||
<button
|
<button
|
||||||
onClick={handleRedirectCancel}
|
onClick={handleRedirectCancel}
|
||||||
className="underline cursor-pointer op-text-primary focus:outline-none ml-2"
|
className="underline cursor-pointer op-text-primary focus:outline-none ml-2"
|
||||||
@@ -2058,7 +2119,9 @@ function PdfRequestFiles() {
|
|||||||
<div className="flex flex-col mt-3 gap-1 px-[10px] justify-center items-center">
|
<div className="flex flex-col mt-3 gap-1 px-[10px] justify-center items-center">
|
||||||
{!isredirectCanceled && redirectUrl && (
|
{!isredirectCanceled && redirectUrl && (
|
||||||
<div className="flex flex-row gap-1 items-center justify-center mb-3">
|
<div className="flex flex-row gap-1 items-center justify-center mb-3">
|
||||||
<p>Redirecting you in {redirectTimeLeft} sec...</p>
|
<p>
|
||||||
|
Redirecting you in {redirectTimeLeft} sec...
|
||||||
|
</p>
|
||||||
<button
|
<button
|
||||||
onClick={handleRedirectCancel}
|
onClick={handleRedirectCancel}
|
||||||
className="underline cursor-pointer op-text-primary focus:outline-none ml-2"
|
className="underline cursor-pointer op-text-primary focus:outline-none ml-2"
|
||||||
@@ -2152,7 +2215,7 @@ function PdfRequestFiles() {
|
|||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
{/* this component is used for signature pad modal */}
|
{/* this component is used for signature pad modal */}
|
||||||
{documentId && isSignPad && (
|
{currentSigner && isSignPad && (
|
||||||
<SignPad
|
<SignPad
|
||||||
saveSignCheckbox={saveSignCheckbox}
|
saveSignCheckbox={saveSignCheckbox}
|
||||||
setSaveSignCheckbox={setSaveSignCheckbox}
|
setSaveSignCheckbox={setSaveSignCheckbox}
|
||||||
@@ -2184,7 +2247,9 @@ function PdfRequestFiles() {
|
|||||||
)}
|
)}
|
||||||
{/* pdf header which contain funish back button */}
|
{/* pdf header which contain funish back button */}
|
||||||
<Header
|
<Header
|
||||||
isPdfRequestFiles={true}
|
isPdfRequestFiles={
|
||||||
|
true
|
||||||
|
}
|
||||||
pageNumber={pageNumber}
|
pageNumber={pageNumber}
|
||||||
allPages={allPages}
|
allPages={allPages}
|
||||||
changePage={changePage}
|
changePage={changePage}
|
||||||
@@ -2192,7 +2257,9 @@ function PdfRequestFiles() {
|
|||||||
signerPos={signerPos}
|
signerPos={signerPos}
|
||||||
isSigned={isSigned}
|
isSigned={isSigned}
|
||||||
isCompleted={isCompleted.isCertificate}
|
isCompleted={isCompleted.isCertificate}
|
||||||
embedWidgetsData={embedWidgetsData}
|
embedWidgetsData={
|
||||||
|
handleSignPdf
|
||||||
|
}
|
||||||
isShowHeader={true}
|
isShowHeader={true}
|
||||||
setIsDecline={setIsDecline}
|
setIsDecline={setIsDecline}
|
||||||
decline={true}
|
decline={true}
|
||||||
+60
-22
@@ -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,13 +2061,16 @@ function PlaceHolderSign() {
|
|||||||
{!isCustomize && (
|
{!isCustomize && (
|
||||||
<span>{t("placeholder-alert-3")}</span>
|
<span>{t("placeholder-alert-3")}</span>
|
||||||
)}
|
)}
|
||||||
{isCustomize && (
|
{
|
||||||
|
isCustomize && (
|
||||||
<>
|
<>
|
||||||
<EmailBody
|
<EmailBody
|
||||||
editorRef={editorRef}
|
editorRef={editorRef}
|
||||||
requestBody={requestBody}
|
requestBody={requestBody}
|
||||||
requestSubject={requestSubject}
|
requestSubject={requestSubject}
|
||||||
handleOnchangeRequest={handleOnchangeRequest}
|
handleOnchangeRequest={
|
||||||
|
handleOnchangeRequest
|
||||||
|
}
|
||||||
setRequestSubject={setRequestSubject}
|
setRequestSubject={setRequestSubject}
|
||||||
/>
|
/>
|
||||||
<div
|
<div
|
||||||
@@ -2048,7 +2083,8 @@ function PlaceHolderSign() {
|
|||||||
<span>{t("reset-to-default")}</span>
|
<span>{t("reset-to-default")}</span>
|
||||||
</div>
|
</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 && (
|
{
|
||||||
|
!isCustomize && (
|
||||||
<span
|
<span
|
||||||
className="op-link op-link-accent text-sm"
|
className="op-link op-link-accent text-sm"
|
||||||
onClick={() => setIsCustomize(!isCustomize)}
|
onClick={() => setIsCustomize(!isCustomize)}
|
||||||
>
|
>
|
||||||
{t("cutomize-email")}
|
{t("cutomize-email")}
|
||||||
</span>
|
</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(
|
||||||
+7
-5
@@ -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,13 +63,16 @@ 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 };
|
||||||
+49
-22
@@ -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();
|
||||||
@@ -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"
|
||||||
@@ -2026,7 +2047,9 @@ const ReportTable = (props) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
onClick={(e) => handleShareWith(e, item)}
|
onClick={(e) =>
|
||||||
|
handleShareWith(e, item)
|
||||||
|
}
|
||||||
className="op-btn op-btn-primary ml-[10px] my-3"
|
className="op-btn op-btn-primary ml-[10px] my-3"
|
||||||
>
|
>
|
||||||
{t("submit")}
|
{t("submit")}
|
||||||
@@ -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,7 +2253,9 @@ 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]">
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user