mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-05 09:17:39 +02:00
Compare commits
27
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
879279a382 | ||
|
|
74df84e449 | ||
|
|
2862ae3302 | ||
|
|
7d0dfe480c | ||
|
|
c47748ed4d | ||
|
|
396504138c | ||
|
|
6e067a160c | ||
|
|
63b2693fe0 | ||
|
|
76a69d8f3b | ||
|
|
5cd0f55cb2 | ||
|
|
db640b04a6 | ||
|
|
0665bcf30a | ||
|
|
7e8ed42f46 | ||
|
|
8d7b1a5b9b | ||
|
|
c6829a7d5e | ||
|
|
bef8fbf183 | ||
|
|
fca95f09cc | ||
|
|
4d6cdf8823 | ||
|
|
e34f52dcc5 | ||
|
|
91cc4e6f3d | ||
|
|
429b7dcb0e | ||
|
|
5ffa681a80 | ||
|
|
91364db608 | ||
|
|
2433c68f27 | ||
|
|
6ea254d9ac | ||
|
|
a4d1df8324 | ||
|
|
ba15611903 |
Generated
+15
-15
@@ -28,7 +28,7 @@
|
|||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"radix-ui": "^1.0.1",
|
"radix-ui": "^1.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-bootstrap": "^2.10.4",
|
"react-bootstrap": "^2.10.5",
|
||||||
"react-confetti": "^6.1.0",
|
"react-confetti": "^6.1.0",
|
||||||
"react-cookie": "^7.2.0",
|
"react-cookie": "^7.2.0",
|
||||||
"react-datepicker": "^7.4.0",
|
"react-datepicker": "^7.4.0",
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"babel-loader": "^9.2.1",
|
"babel-loader": "^9.2.1",
|
||||||
"clean-webpack-plugin": "^4.0.0",
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.1",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"daisyui": "^4.12.10",
|
"daisyui": "^4.12.10",
|
||||||
@@ -78,7 +78,7 @@
|
|||||||
"dotenv-webpack": "^8.1.0",
|
"dotenv-webpack": "^8.1.0",
|
||||||
"eslint": "^9.11.1",
|
"eslint": "^9.11.1",
|
||||||
"eslint-plugin-prettier": "^5.2.1",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"eslint-plugin-react": "^7.36.1",
|
"eslint-plugin-react": "^7.37.0",
|
||||||
"lint-staged": "^15.2.10",
|
"lint-staged": "^15.2.10",
|
||||||
"mini-css-extract-plugin": "^2.9.1",
|
"mini-css-extract-plugin": "^2.9.1",
|
||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.47",
|
||||||
@@ -8750,9 +8750,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/commitizen": {
|
"node_modules/commitizen": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/commitizen/-/commitizen-4.3.1.tgz",
|
||||||
"integrity": "sha512-H0iNtClNEhT0fotHvGV3E9tDejDeS04sN1veIebsKYGMuGscFaswRoYJKmT3eW85eIJAs0F28bG2+a/9wCOfPw==",
|
"integrity": "sha512-gwAPAVTy/j5YcOOebcCRIijn+mSjWJC+IYKivTu6aG8Ei/scoXgfsMRnuAk6b0GRste2J4NGxVdMN3ZpfNaVaw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cachedir": "2.3.0",
|
"cachedir": "2.3.0",
|
||||||
@@ -10856,9 +10856,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint-plugin-react": {
|
"node_modules/eslint-plugin-react": {
|
||||||
"version": "7.36.1",
|
"version": "7.37.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.36.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.0.tgz",
|
||||||
"integrity": "sha512-/qwbqNXZoq+VP30s1d4Nc1C5GTxjJQjk4Jzs4Wq2qzxFM7dSmuG2UkIjg2USMLh3A/aVcUNrK7v0J5U1XEGGwA==",
|
"integrity": "sha512-IHBePmfWH5lKhJnJ7WB1V+v/GolbB0rjS8XYVCSQCZKaQCAUhMoVoOEn1Ef8Z8Wf0a7l8KTJvuZg5/e4qrZ6nA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"array-includes": "^3.1.8",
|
"array-includes": "^3.1.8",
|
||||||
"array.prototype.findlast": "^1.2.5",
|
"array.prototype.findlast": "^1.2.5",
|
||||||
@@ -20271,9 +20271,9 @@
|
|||||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||||
},
|
},
|
||||||
"node_modules/react-bootstrap": {
|
"node_modules/react-bootstrap": {
|
||||||
"version": "2.10.4",
|
"version": "2.10.5",
|
||||||
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-2.10.5.tgz",
|
||||||
"integrity": "sha512-W3398nBM2CBfmGP2evneEO3ZZwEMPtHs72q++eNw60uDGDAdiGn0f9yNys91eo7/y8CTF5Ke1C0QO8JFVPU40Q==",
|
"integrity": "sha512-XueAOEn64RRkZ0s6yzUTdpFtdUXs5L5491QU//8ZcODKJNDLt/r01tNyriZccjgRImH1REynUc9pqjiRMpDLWQ==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.24.7",
|
"@babel/runtime": "^7.24.7",
|
||||||
"@restart/hooks": "^0.4.9",
|
"@restart/hooks": "^0.4.9",
|
||||||
@@ -22508,9 +22508,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/rollup": {
|
"node_modules/rollup": {
|
||||||
"version": "2.79.1",
|
"version": "2.79.2",
|
||||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
|
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
||||||
"integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
|
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
||||||
"bin": {
|
"bin": {
|
||||||
"rollup": "dist/bin/rollup"
|
"rollup": "dist/bin/rollup"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
"print-js": "^1.6.0",
|
"print-js": "^1.6.0",
|
||||||
"radix-ui": "^1.0.1",
|
"radix-ui": "^1.0.1",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-bootstrap": "^2.10.4",
|
"react-bootstrap": "^2.10.5",
|
||||||
"react-confetti": "^6.1.0",
|
"react-confetti": "^6.1.0",
|
||||||
"react-cookie": "^7.2.0",
|
"react-cookie": "^7.2.0",
|
||||||
"react-datepicker": "^7.4.0",
|
"react-datepicker": "^7.4.0",
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
"autoprefixer": "^10.4.20",
|
"autoprefixer": "^10.4.20",
|
||||||
"babel-loader": "^9.2.1",
|
"babel-loader": "^9.2.1",
|
||||||
"clean-webpack-plugin": "^4.0.0",
|
"clean-webpack-plugin": "^4.0.0",
|
||||||
"commitizen": "^4.3.0",
|
"commitizen": "^4.3.1",
|
||||||
"concurrently": "^9.0.1",
|
"concurrently": "^9.0.1",
|
||||||
"css-loader": "^7.1.2",
|
"css-loader": "^7.1.2",
|
||||||
"daisyui": "^4.12.10",
|
"daisyui": "^4.12.10",
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
"dotenv-webpack": "^8.1.0",
|
"dotenv-webpack": "^8.1.0",
|
||||||
"eslint": "^9.11.1",
|
"eslint": "^9.11.1",
|
||||||
"eslint-plugin-prettier": "^5.2.1",
|
"eslint-plugin-prettier": "^5.2.1",
|
||||||
"eslint-plugin-react": "^7.36.1",
|
"eslint-plugin-react": "^7.37.0",
|
||||||
"lint-staged": "^15.2.10",
|
"lint-staged": "^15.2.10",
|
||||||
"mini-css-extract-plugin": "^2.9.1",
|
"mini-css-extract-plugin": "^2.9.1",
|
||||||
"postcss": "^8.4.47",
|
"postcss": "^8.4.47",
|
||||||
|
|||||||
@@ -132,7 +132,8 @@
|
|||||||
"View": "View",
|
"View": "View",
|
||||||
"option": "Option",
|
"option": "Option",
|
||||||
"Embed": "Embed",
|
"Embed": "Embed",
|
||||||
"Copy TemplateId":"Copy TemplateId"
|
"Copy TemplateId":"Copy TemplateId",
|
||||||
|
"Copy Public URL":"Copy Public URL"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Sr.No",
|
"Sr.No": "Sr.No",
|
||||||
@@ -639,7 +640,7 @@
|
|||||||
"public-template-mssg-3" :"Need more details or examples?",
|
"public-template-mssg-3" :"Need more details or examples?",
|
||||||
"public-template-mssg-4": "Visit the",
|
"public-template-mssg-4": "Visit the",
|
||||||
"public-template-mssg-5": " npm for the latest updates, detailed documentation, and version history.",
|
"public-template-mssg-5": " npm for the latest updates, detailed documentation, and version history.",
|
||||||
"public-template-mssg-6" :"You need to set this template as public before you can utilize this code snippet.",
|
"public-template-mssg-6" :"Before you can use this code snippet, you must make this template public.",
|
||||||
"copy-code":"COPY",
|
"copy-code":"COPY",
|
||||||
"copied-code":"COPIED",
|
"copied-code":"COPIED",
|
||||||
"Installation":"Installation",
|
"Installation":"Installation",
|
||||||
@@ -668,6 +669,9 @@
|
|||||||
"download-files":"Download files",
|
"download-files":"Download files",
|
||||||
"download-pdf":"Download Pdf",
|
"download-pdf":"Download Pdf",
|
||||||
"pdf-certificate":"Download Pdf + Certificate",
|
"pdf-certificate":"Download Pdf + Certificate",
|
||||||
"document-logs":"Document logs"
|
"document-logs":"Document logs",
|
||||||
|
"server-down": "Unable to connect to the OpenSign server. If you are self-hosting OpenSign, please ensure that all the steps in the documentation have been followed correctly. If you're running OpenSign locally, you might be accessing it through an incorrect port number.",
|
||||||
|
"admin-exists": "Admin already exists. Please login to the application using admin credentials in order to manage users.",
|
||||||
|
"public-tour-message":"Please make template public to copy public URL"
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,8 @@
|
|||||||
"View": "Voir",
|
"View": "Voir",
|
||||||
"option": "Option",
|
"option": "Option",
|
||||||
"Embed": "Intégrer",
|
"Embed": "Intégrer",
|
||||||
"Copy TemplateId": "Copier l'ID du modèle"
|
"Copy TemplateId": "Copier l'ID du modèle",
|
||||||
|
"Copy Public URL":"Copier l'URL publique"
|
||||||
},
|
},
|
||||||
"report-help": {
|
"report-help": {
|
||||||
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
||||||
@@ -638,7 +639,7 @@
|
|||||||
"public-template-mssg-3" :"Besoin de plus de détails ou d'exemples ?",
|
"public-template-mssg-3" :"Besoin de plus de détails ou d'exemples ?",
|
||||||
"public-template-mssg-4": "Visitez le",
|
"public-template-mssg-4": "Visitez le",
|
||||||
"public-template-mssg-5": "npm pour les dernières mises à jour, une documentation détaillée et l'historique des versions.",
|
"public-template-mssg-5": "npm pour les dernières mises à jour, une documentation détaillée et l'historique des versions.",
|
||||||
"public-template-mssg-6":"Vous devez définir ce modèle comme public avant de pouvoir utiliser cet extrait de code.",
|
"public-template-mssg-6":"Avant de pouvoir utiliser cet extrait de code, vous devez rendre ce modèle public.",
|
||||||
"copy-code":"COPIE",
|
"copy-code":"COPIE",
|
||||||
"copied-code":"COPIÉ",
|
"copied-code":"COPIÉ",
|
||||||
"Installation":"Installation",
|
"Installation":"Installation",
|
||||||
@@ -667,6 +668,10 @@
|
|||||||
"download-files" :"Télécharger des fichiers",
|
"download-files" :"Télécharger des fichiers",
|
||||||
"download-pdf" :"Télécharger le PDF",
|
"download-pdf" :"Télécharger le PDF",
|
||||||
"pdf-certificate" :"Télécharger Pdf + Certificat",
|
"pdf-certificate" :"Télécharger Pdf + Certificat",
|
||||||
"document-logs":"Journaux de documents"
|
"document-logs":"Journaux de documents",
|
||||||
|
"server-down": "Impossible de se connecter au serveur OpenSign. Si vous hébergez vous-même OpenSign, veuillez vous assurer que toutes les étapes de la documentation ont été correctement suivies. Si vous exécutez OpenSign localement, vous y accédez peut-être via un numéro de port incorrect.",
|
||||||
|
"admin-exists": "L'administrateur existe déjà. Veuillez vous connecter à l'application en utilisant les informations d'identification de l'administrateur afin de gérer les utilisateurs.",
|
||||||
|
"public-tour-message":"Veuillez rendre le modèle public pour copier l'URL publique"
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
@@ -2,7 +2,6 @@ import React, { useState, useEffect, useRef } from "react";
|
|||||||
import "../../styles/opensigndrive.css";
|
import "../../styles/opensigndrive.css";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import * as ContextMenu from "@radix-ui/react-context-menu";
|
import * as ContextMenu from "@radix-ui/react-context-menu";
|
||||||
import { saveAs } from "file-saver";
|
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
import Table from "react-bootstrap/Table";
|
import Table from "react-bootstrap/Table";
|
||||||
import * as HoverCard from "@radix-ui/react-hover-card";
|
import * as HoverCard from "@radix-ui/react-hover-card";
|
||||||
@@ -264,12 +263,6 @@ function DriveBody(props) {
|
|||||||
setIsOpenMoveModal(false);
|
setIsOpenMoveModal(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const sanitizeFileName = (pdfName) => {
|
|
||||||
// Replace spaces with underscore
|
|
||||||
return pdfName.replace(/ /g, "_");
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleEnterPress = (e, data) => {
|
const handleEnterPress = (e, data) => {
|
||||||
if (e.key === "Enter") {
|
if (e.key === "Enter") {
|
||||||
handledRenameDoc(data);
|
handledRenameDoc(data);
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ export function App() {
|
|||||||
<Opensign
|
<Opensign
|
||||||
onLoad={() => console.log("success")}
|
onLoad={() => console.log("success")}
|
||||||
onLoadError={(error) => console.log(error)}
|
onLoadError={(error) => console.log(error)}
|
||||||
templateId= {"${props.templateId}"}
|
templateId= "${props.templateId}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -63,10 +63,10 @@ import {OpensignComponent} from "@opensign/angular"
|
|||||||
selector:'app-root',
|
selector:'app-root',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [OpensignComponent],
|
imports: [OpensignComponent],
|
||||||
template: '<opensign templateId={"${props.templateId}"}
|
template:\`<opensign templateId="${props.templateId}"
|
||||||
(onLoad)="handleLoad()"
|
(onLoad)="handleLoad()"
|
||||||
(onLoadError)="handleError($event)"
|
(onLoadError)="handleError($event)"
|
||||||
></opensign>',
|
></opensign>\`,
|
||||||
})
|
})
|
||||||
export class AppComponent{
|
export class AppComponent{
|
||||||
handleLoad() {
|
handleLoad() {
|
||||||
@@ -129,9 +129,11 @@ export class AppComponent{
|
|||||||
<p className="font-medium text-[18px]">
|
<p className="font-medium text-[18px]">
|
||||||
{t(`${data.title}`)}
|
{t(`${data.title}`)}
|
||||||
</p>
|
</p>
|
||||||
|
{ind === 0 && (
|
||||||
<p className="text-[13px] mt-2">
|
<p className="text-[13px] mt-2">
|
||||||
{t("public-template-mssg-1")}
|
{t("public-template-mssg-1")}
|
||||||
</p>
|
</p>
|
||||||
|
)}
|
||||||
<div className="relative p-1">
|
<div className="relative p-1">
|
||||||
<div
|
<div
|
||||||
onClick={() => handleCopy(data.codeString, ind)}
|
onClick={() => handleCopy(data.codeString, ind)}
|
||||||
@@ -210,11 +212,11 @@ export class AppComponent{
|
|||||||
<p className="font-medium text-[18px]">
|
<p className="font-medium text-[18px]">
|
||||||
{t(`${data.title}`)}
|
{t(`${data.title}`)}
|
||||||
</p>
|
</p>
|
||||||
|
{ind === 0 && (
|
||||||
<p className="text-[13px] mt-2">
|
<p className="text-[13px] mt-2">
|
||||||
{t("angular-npm-mssg-1")}
|
{t("angular-npm-mssg-1")}
|
||||||
</p>
|
</p>
|
||||||
|
)}
|
||||||
<div className="relative p-1">
|
<div className="relative p-1">
|
||||||
<div
|
<div
|
||||||
onClick={() => handleCopy(data.codeString, ind)}
|
onClick={() => handleCopy(data.codeString, ind)}
|
||||||
|
|||||||
@@ -725,7 +725,9 @@ function Placeholder(props) {
|
|||||||
: props?.pos?.zIndex
|
: props?.pos?.zIndex
|
||||||
? props.pos.zIndex
|
? props.pos.zIndex
|
||||||
: "5",
|
: "5",
|
||||||
background: props.data ? props.data.blockColor : "rgb(203 233 237)"
|
background: props.data
|
||||||
|
? props.data?.blockColor + "b0"
|
||||||
|
: "rgba(203, 233, 237, 0.69)"
|
||||||
}}
|
}}
|
||||||
onDrag={() => {
|
onDrag={() => {
|
||||||
setDraggingEnabled(true);
|
setDraggingEnabled(true);
|
||||||
|
|||||||
@@ -596,7 +596,7 @@ function SignPad({
|
|||||||
borderRadius: "2px"
|
borderRadius: "2px"
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
backgroundColor="rgb(255, 255, 255)"
|
// backgroundColor="rgb(255, 255, 255)"
|
||||||
onEnd={() =>
|
onEnd={() =>
|
||||||
handleSignatureChange(canvasRef.current?.toDataURL())
|
handleSignatureChange(canvasRef.current?.toDataURL())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1350,11 +1350,6 @@ export const multiSignEmbed = async (
|
|||||||
widgetsPositionArr.map(async (url) => {
|
widgetsPositionArr.map(async (url) => {
|
||||||
let signUrl = url.SignUrl && url.SignUrl;
|
let signUrl = url.SignUrl && url.SignUrl;
|
||||||
if (signUrl) {
|
if (signUrl) {
|
||||||
if (url.ImageType === "image/png") {
|
|
||||||
//function for convert signature png base64 url to jpeg base64
|
|
||||||
const newUrl = await convertPNGtoJPEG(signUrl);
|
|
||||||
signUrl = newUrl;
|
|
||||||
}
|
|
||||||
const res = await fetch(signUrl);
|
const res = await fetch(signUrl);
|
||||||
return res.arrayBuffer();
|
return res.arrayBuffer();
|
||||||
}
|
}
|
||||||
@@ -1364,19 +1359,14 @@ export const multiSignEmbed = async (
|
|||||||
widgetsPositionArr.forEach(async (position, id) => {
|
widgetsPositionArr.forEach(async (position, id) => {
|
||||||
let img;
|
let img;
|
||||||
if (["signature", "stamp", "initials", "image"].includes(position.type)) {
|
if (["signature", "stamp", "initials", "image"].includes(position.type)) {
|
||||||
if (
|
if (position.ImageType && position.ImageType === "image/jpeg") {
|
||||||
(position.ImageType && position.ImageType === "image/png") ||
|
|
||||||
position.ImageType === "image/jpeg"
|
|
||||||
) {
|
|
||||||
img = await pdfDoc.embedJpg(images[id]);
|
img = await pdfDoc.embedJpg(images[id]);
|
||||||
} else {
|
} else {
|
||||||
img = await pdfDoc.embedPng(images[id]);
|
img = await pdfDoc.embedPng(images[id]);
|
||||||
}
|
}
|
||||||
} else if (!position.type) {
|
} else if (!position.type) {
|
||||||
if (
|
// to handle old widget when only stamp and signature are exists
|
||||||
(position.ImageType && position.ImageType === "image/png") ||
|
if (position.ImageType && position.ImageType === "image/jpeg") {
|
||||||
position.ImageType === "image/jpeg"
|
|
||||||
) {
|
|
||||||
img = await pdfDoc.embedJpg(images[id]);
|
img = await pdfDoc.embedJpg(images[id]);
|
||||||
} else {
|
} else {
|
||||||
img = await pdfDoc.embedPng(images[id]);
|
img = await pdfDoc.embedPng(images[id]);
|
||||||
@@ -1936,9 +1926,13 @@ export const getAppLogo = async () => {
|
|||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("err in getlogo ", err);
|
console.log("err in getlogo ", err);
|
||||||
|
if (err?.message?.includes("valid JSON")) {
|
||||||
|
return { logo: appInfo.applogo, user: "exist", error: "invalid_json" };
|
||||||
|
} else {
|
||||||
return { logo: appInfo.applogo, user: "exist" };
|
return { logo: appInfo.applogo, user: "exist" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getTenantDetails = async (objectId) => {
|
export const getTenantDetails = async (objectId) => {
|
||||||
|
|||||||
@@ -39,6 +39,13 @@ export default function reportJson(id) {
|
|||||||
hoverLabel: "Copy TemplateId",
|
hoverLabel: "Copy TemplateId",
|
||||||
btnIcon: "fa-light fa-copy",
|
btnIcon: "fa-light fa-copy",
|
||||||
action: "CopyTemplateId"
|
action: "CopyTemplateId"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
btnId: "2434",
|
||||||
|
btnLabel: "Copy Public URL",
|
||||||
|
hoverLabel: "Copy Public URL",
|
||||||
|
btnIcon: "fa-light fa-copy",
|
||||||
|
action: "CopyPublicURL"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
: [];
|
: [];
|
||||||
@@ -405,18 +412,15 @@ export default function reportJson(id) {
|
|||||||
if (item.action === "option") {
|
if (item.action === "option") {
|
||||||
// Make a shallow copy of the item
|
// Make a shallow copy of the item
|
||||||
const newItem = { ...item };
|
const newItem = { ...item };
|
||||||
newItem.subaction = [
|
//splice method used to add `Share with team` option on second index of list
|
||||||
{
|
newItem.subaction.splice(1, 0, {
|
||||||
btnId: "1873",
|
btnId: "1873",
|
||||||
btnLabel: "Share with team",
|
btnLabel: "Share with team",
|
||||||
hoverLabel: "Share with team",
|
hoverLabel: "Share with team",
|
||||||
btnIcon: "fa-light fa-share-nodes",
|
btnIcon: "fa-light fa-share-nodes",
|
||||||
redirectUrl: "",
|
redirectUrl: "",
|
||||||
action: "sharewith"
|
action: "sharewith"
|
||||||
},
|
});
|
||||||
...newItem.subaction
|
|
||||||
];
|
|
||||||
|
|
||||||
return newItem;
|
return newItem;
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ const AddAdmin = () => {
|
|||||||
try {
|
try {
|
||||||
const app = await getAppLogo();
|
const app = await getAppLogo();
|
||||||
if (app?.user === "exist") {
|
if (app?.user === "exist") {
|
||||||
setErrMsg(t("admin-already-exist"));
|
setErrMsg(t("admin-exists"));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setErrMsg(t("something-went-wrong-mssg"));
|
setErrMsg(t("something-went-wrong-mssg"));
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ function Login() {
|
|||||||
const [isModal, setIsModal] = useState(false);
|
const [isModal, setIsModal] = useState(false);
|
||||||
const [image, setImage] = useState();
|
const [image, setImage] = useState();
|
||||||
const [isLoginSSO, setIsLoginSSO] = useState(false);
|
const [isLoginSSO, setIsLoginSSO] = useState(false);
|
||||||
|
const [errMsg, setErrMsg] = useState();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkUserExt();
|
checkUserExt();
|
||||||
@@ -59,7 +60,9 @@ function Login() {
|
|||||||
|
|
||||||
const checkUserExt = async () => {
|
const checkUserExt = async () => {
|
||||||
const app = await getAppLogo();
|
const app = await getAppLogo();
|
||||||
if (!isEnableSubscription && app?.user === "not_exist") {
|
if (app?.error === "invalid_json") {
|
||||||
|
setErrMsg(t("server-down"));
|
||||||
|
} else if (!isEnableSubscription && app?.user === "not_exist") {
|
||||||
navigate("/addadmin");
|
navigate("/addadmin");
|
||||||
}
|
}
|
||||||
if (app?.logo) {
|
if (app?.logo) {
|
||||||
@@ -620,7 +623,11 @@ function Login() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return errMsg ? (
|
||||||
|
<div className="h-screen flex justify-center text-center items-center p-4 text-gray-500 text-base">
|
||||||
|
{errMsg}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<Title title={"Login Page"} />
|
<Title title={"Login Page"} />
|
||||||
{state.loading && (
|
{state.loading && (
|
||||||
|
|||||||
@@ -2,12 +2,13 @@ import React, { useState, useRef, useEffect } from "react";
|
|||||||
import SignatureCanvas from "react-signature-canvas";
|
import SignatureCanvas from "react-signature-canvas";
|
||||||
import "../styles/managesign.css";
|
import "../styles/managesign.css";
|
||||||
import "../styles/signature.css";
|
import "../styles/signature.css";
|
||||||
import { toDataUrl } from "../constant/Utils";
|
import { generateTitleFromFilename, toDataUrl } from "../constant/Utils";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
import { SaveFileSize } from "../constant/saveFileSize";
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
import Alert from "../primitives/Alert";
|
import Alert from "../primitives/Alert";
|
||||||
import Loader from "../primitives/Loader";
|
import Loader from "../primitives/Loader";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
|
import sanitizeFileName from "../primitives/sanitizeFileName";
|
||||||
const ManageSign = () => {
|
const ManageSign = () => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [penColor, setPenColor] = useState("blue");
|
const [penColor, setPenColor] = useState("blue");
|
||||||
@@ -23,9 +24,11 @@ const ManageSign = () => {
|
|||||||
const [Initials, setInitials] = useState("");
|
const [Initials, setInitials] = useState("");
|
||||||
const [isInitials, setIsInitials] = useState(false);
|
const [isInitials, setIsInitials] = useState(false);
|
||||||
const [id, setId] = useState("");
|
const [id, setId] = useState("");
|
||||||
|
const [imgInitials, setImgInitials] = useState("");
|
||||||
const canvasRef = useRef(null);
|
const canvasRef = useRef(null);
|
||||||
const imageRef = useRef(null);
|
const imageRef = useRef(null);
|
||||||
const initailsRef = useRef(null);
|
const initailsRef = useRef(null);
|
||||||
|
const imgInitialsRef = useRef(null);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchUserSign();
|
fetchUserSign();
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
@@ -46,14 +49,23 @@ const ManageSign = () => {
|
|||||||
if (signRes) {
|
if (signRes) {
|
||||||
const res = signRes.toJSON();
|
const res = signRes.toJSON();
|
||||||
setId(res.objectId);
|
setId(res.objectId);
|
||||||
setSignName(res?.SignatureName);
|
if (res?.SignatureName) {
|
||||||
setImage(res.ImageURL);
|
const sanitizename = generateTitleFromFilename(res?.SignatureName);
|
||||||
|
const replaceSpace = sanitizeFileName(sanitizename);
|
||||||
|
setSignName(replaceSpace);
|
||||||
|
}
|
||||||
|
setImage(res?.ImageURL);
|
||||||
if (res && res.Initials) {
|
if (res && res.Initials) {
|
||||||
setInitials(res.Initials);
|
// setInitials(res.Initials);
|
||||||
setIsInitials(true);
|
setIsInitials(true);
|
||||||
|
setImgInitials(res?.Initials);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setSignName(User?.get("name") || "");
|
if (User?.get("name")) {
|
||||||
|
const sanitizename = generateTitleFromFilename(User?.get("name"));
|
||||||
|
const replaceSpace = sanitizeFileName(sanitizename);
|
||||||
|
setSignName(replaceSpace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -86,8 +98,14 @@ const ManageSign = () => {
|
|||||||
if (initailsRef.current) {
|
if (initailsRef.current) {
|
||||||
initailsRef.current.clear();
|
initailsRef.current.clear();
|
||||||
}
|
}
|
||||||
|
if (imgInitialsRef.current) {
|
||||||
|
imgInitialsRef.current.value = "";
|
||||||
|
}
|
||||||
|
setImgInitials("");
|
||||||
setInitials("");
|
setInitials("");
|
||||||
|
if (image) {
|
||||||
setIsValue(true);
|
setIsValue(true);
|
||||||
|
}
|
||||||
setIsInitials(false);
|
setIsInitials(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -101,40 +119,54 @@ const ManageSign = () => {
|
|||||||
const base64Img = await toDataUrl(file);
|
const base64Img = await toDataUrl(file);
|
||||||
setImage(base64Img);
|
setImage(base64Img);
|
||||||
setIsValue(true);
|
setIsValue(true);
|
||||||
|
} else {
|
||||||
|
setImage("");
|
||||||
|
setIsValue(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
const isUrl = image.includes("https");
|
const isUrl = image?.includes("https") || image?.includes("http");
|
||||||
|
|
||||||
if (!isvalue) {
|
if (!isvalue) {
|
||||||
setWarning(true);
|
setWarning(true);
|
||||||
setTimeout(() => setWarning(false), 1000);
|
setTimeout(() => setWarning(false), 1000);
|
||||||
} else {
|
} else {
|
||||||
setIsLoader(true);
|
setIsLoader(true);
|
||||||
const replaceSpace = signName.replace(/ /g, "_");
|
const sanitizename = generateTitleFromFilename(signName);
|
||||||
|
const replaceSpace = sanitizeFileName(sanitizename);
|
||||||
let file;
|
let file;
|
||||||
if (signature) {
|
if (signature) {
|
||||||
file = base64StringtoFile(signature, `${replaceSpace}_sign.png`);
|
file = base64StringtoFile(signature, `${replaceSpace}_sign.png`);
|
||||||
} else {
|
} else {
|
||||||
if (!isUrl) {
|
if (image && !isUrl) {
|
||||||
file = base64StringtoFile(image, `${replaceSpace}__sign.png`);
|
file = base64StringtoFile(image, `${replaceSpace}__sign.png`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let imgUrl;
|
let imgUrl;
|
||||||
if (!isUrl) {
|
if (file && !isUrl) {
|
||||||
imgUrl = await uploadFile(file);
|
imgUrl = await uploadFile(file);
|
||||||
} else {
|
} else {
|
||||||
imgUrl = image;
|
imgUrl = image;
|
||||||
}
|
}
|
||||||
let initialsUrl = "";
|
const isInitialsUrl =
|
||||||
const isInitialsUrl = Initials.includes("https");
|
imgInitials?.includes("https") || imgInitials?.includes("http");
|
||||||
if (!isInitialsUrl && Initials) {
|
|
||||||
const initialsImg = base64StringtoFile(
|
let initialFile;
|
||||||
Initials,
|
if (Initials) {
|
||||||
`${replaceSpace}_initials.png`
|
initialFile = base64StringtoFile(Initials, `${replaceSpace}_sign.png`);
|
||||||
|
} else {
|
||||||
|
if (imgInitials && !isInitialsUrl) {
|
||||||
|
initialFile = base64StringtoFile(
|
||||||
|
imgInitials,
|
||||||
|
`${replaceSpace}__sign.png`
|
||||||
);
|
);
|
||||||
initialsUrl = await uploadFile(initialsImg);
|
}
|
||||||
|
}
|
||||||
|
let initialsUrl;
|
||||||
|
if (initialFile && !isInitialsUrl) {
|
||||||
|
initialsUrl = await uploadFile(initialFile);
|
||||||
|
} else {
|
||||||
|
initialsUrl = imgInitials;
|
||||||
}
|
}
|
||||||
if (imgUrl) {
|
if (imgUrl) {
|
||||||
await saveEntry({
|
await saveEntry({
|
||||||
@@ -146,7 +178,7 @@ const ManageSign = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
function base64StringtoFile(base64String, filename) {
|
function base64StringtoFile(base64String, filename) {
|
||||||
var arr = base64String.split(","),
|
let arr = base64String.split(","),
|
||||||
mime = arr[0].match(/:(.*?);/)[1],
|
mime = arr[0].match(/:(.*?);/)[1],
|
||||||
bstr = atob(arr[1]),
|
bstr = atob(arr[1]),
|
||||||
n = bstr.length,
|
n = bstr.length,
|
||||||
@@ -175,31 +207,24 @@ const ManageSign = () => {
|
|||||||
|
|
||||||
const saveEntry = async (obj) => {
|
const saveEntry = async (obj) => {
|
||||||
const signCls = "contracts_Signature";
|
const signCls = "contracts_Signature";
|
||||||
const User = Parse.User.current().id;
|
const User = Parse?.User?.current()?.id;
|
||||||
const userId = { __type: "Pointer", className: "_User", objectId: User };
|
const userId = { __type: "Pointer", className: "_User", objectId: User };
|
||||||
if (id) {
|
if (id) {
|
||||||
try {
|
try {
|
||||||
const updateSign = new Parse.Object(signCls);
|
const updateSign = new Parse.Object(signCls);
|
||||||
updateSign.id = id;
|
updateSign.id = id;
|
||||||
updateSign.set("Initials", obj.initialsUrl ? obj.initialsUrl : "");
|
updateSign.set("Initials", obj.initialsUrl ? obj.initialsUrl : "");
|
||||||
updateSign.set("ImageURL", obj.url);
|
updateSign.set("ImageURL", obj.url ? obj.url : "");
|
||||||
updateSign.set("SignatureName", obj.name);
|
updateSign.set("SignatureName", obj.name);
|
||||||
updateSign.set("UserId", userId);
|
updateSign.set("UserId", userId);
|
||||||
const res = await updateSign.save();
|
const res = await updateSign.save();
|
||||||
setIsLoader(false);
|
setIsAlert({ type: "success", message: t("signature-saved-alert") });
|
||||||
setIsAlert({
|
|
||||||
type: "success",
|
|
||||||
message: t("signature-saved-alert")
|
|
||||||
});
|
|
||||||
setTimeout(() => setIsAlert({}), 2000);
|
|
||||||
return res;
|
return res;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
setIsAlert({ type: "danger", message: `${err.message}` });
|
||||||
|
} finally {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
setIsAlert({
|
|
||||||
type: "danger",
|
|
||||||
message: `${err.message}`
|
|
||||||
});
|
|
||||||
setTimeout(() => setIsAlert({}), 2000);
|
setTimeout(() => setIsAlert({}), 2000);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -210,20 +235,13 @@ const ManageSign = () => {
|
|||||||
updateSign.set("SignatureName", obj.name);
|
updateSign.set("SignatureName", obj.name);
|
||||||
updateSign.set("UserId", userId);
|
updateSign.set("UserId", userId);
|
||||||
const res = await updateSign.save();
|
const res = await updateSign.save();
|
||||||
setIsLoader(false);
|
setIsAlert({ type: "success", message: t("signature-saved-alert") });
|
||||||
setIsAlert({
|
|
||||||
type: "success",
|
|
||||||
message: t("signature-saved-alert")
|
|
||||||
});
|
|
||||||
setTimeout(() => setIsAlert({}), 2000);
|
|
||||||
return res;
|
return res;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
setIsAlert({ type: "success", message: `${err.message}` });
|
||||||
|
} finally {
|
||||||
setIsLoader(false);
|
setIsLoader(false);
|
||||||
setIsAlert({
|
|
||||||
type: "success",
|
|
||||||
message: `${err.message}`
|
|
||||||
});
|
|
||||||
setTimeout(() => setIsAlert({}), 2000);
|
setTimeout(() => setIsAlert({}), 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -234,7 +252,29 @@ const ManageSign = () => {
|
|||||||
};
|
};
|
||||||
const handleInitialsChange = () => {
|
const handleInitialsChange = () => {
|
||||||
setInitials(initailsRef.current.toDataURL());
|
setInitials(initailsRef.current.toDataURL());
|
||||||
|
if (image || signature) {
|
||||||
setIsValue(true);
|
setIsValue(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const handleUploadInitials = () => {
|
||||||
|
imgInitialsRef.current.click();
|
||||||
|
};
|
||||||
|
const onImgInitialsChange = async (event) => {
|
||||||
|
if (initailsRef.current) {
|
||||||
|
initailsRef.current.clear();
|
||||||
|
}
|
||||||
|
setInitials("");
|
||||||
|
if (event.target.files && event.target.files[0]) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
const base64Img = await toDataUrl(file);
|
||||||
|
setImgInitials(base64Img);
|
||||||
|
if (image || signature) {
|
||||||
|
setIsValue(true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setImgInitials("");
|
||||||
|
setIsValue(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
<div className="relative h-full bg-base-100 text-base-content flex shadow-md rounded-box overflow-auto">
|
<div className="relative h-full bg-base-100 text-base-content flex shadow-md rounded-box overflow-auto">
|
||||||
@@ -281,7 +321,7 @@ const ManageSign = () => {
|
|||||||
height: "180px",
|
height: "180px",
|
||||||
className: "signatureCanvas rounded-box"
|
className: "signatureCanvas rounded-box"
|
||||||
}}
|
}}
|
||||||
backgroundColor="rgb(255, 255, 255)"
|
// backgroundColor="rgb(255, 255, 255)"
|
||||||
onEnd={() =>
|
onEnd={() =>
|
||||||
handleSignatureChange(canvasRef.current.toDataURL())
|
handleSignatureChange(canvasRef.current.toDataURL())
|
||||||
}
|
}
|
||||||
@@ -332,7 +372,7 @@ const ManageSign = () => {
|
|||||||
className="op-link"
|
className="op-link"
|
||||||
onClick={() => handleUploadBtn()}
|
onClick={() => handleUploadBtn()}
|
||||||
>
|
>
|
||||||
{t("upload-image")}
|
{t("upload")}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
type="button"
|
type="button"
|
||||||
@@ -356,17 +396,21 @@ const ManageSign = () => {
|
|||||||
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
<span className="font-medium select-none flex mb-[10px] pl-[10px]">
|
||||||
{t("initials")}
|
{t("initials")}
|
||||||
</span>
|
</span>
|
||||||
|
<input
|
||||||
|
type="file"
|
||||||
|
onChange={onImgInitialsChange}
|
||||||
|
className="filetype"
|
||||||
|
accept="image/*"
|
||||||
|
ref={imgInitialsRef}
|
||||||
|
hidden
|
||||||
|
/>
|
||||||
<div>
|
<div>
|
||||||
{isInitials ? (
|
{imgInitials ? (
|
||||||
<div className="intialSignature relative border-[1px] border-[#888] rounded-box overflow-hidden">
|
<div className="intialSignature relative border-[1px] border-[#888] rounded-box overflow-hidden">
|
||||||
<img
|
<img
|
||||||
alt="inititals"
|
alt="inititals"
|
||||||
src={Initials}
|
src={imgInitials}
|
||||||
style={{
|
className="w-[100%] h-[100%] object-contain"
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
objectFit: "contain"
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
@@ -376,10 +420,8 @@ const ManageSign = () => {
|
|||||||
canvasProps={{
|
canvasProps={{
|
||||||
className: "intialSignature rounded-box"
|
className: "intialSignature rounded-box"
|
||||||
}}
|
}}
|
||||||
backgroundColor="rgb(255, 255, 255)"
|
// backgroundColor="rgb(255, 255, 255)"
|
||||||
onEnd={() =>
|
onEnd={() => handleInitialsChange()}
|
||||||
handleInitialsChange(initailsRef.current.toDataURL())
|
|
||||||
}
|
|
||||||
dotSize={1}
|
dotSize={1}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@@ -402,6 +444,7 @@ const ManageSign = () => {
|
|||||||
? "2px solid black"
|
? "2px solid black"
|
||||||
: "2px solid white"
|
: "2px solid white"
|
||||||
}}
|
}}
|
||||||
|
className="fa-light fa-pen-nib"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (key === 0) {
|
if (key === 0) {
|
||||||
setInitialPen("blue");
|
setInitialPen("blue");
|
||||||
@@ -412,7 +455,6 @@ const ManageSign = () => {
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
key={key}
|
key={key}
|
||||||
className="fa-light fa-pen-nib"
|
|
||||||
width={20}
|
width={20}
|
||||||
height={20}
|
height={20}
|
||||||
></i>
|
></i>
|
||||||
@@ -421,6 +463,14 @@ const ManageSign = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="flex flex-row gap-1">
|
||||||
|
<div
|
||||||
|
type="button"
|
||||||
|
className="op-link text-sm md:text-base mr-1"
|
||||||
|
onClick={() => handleUploadInitials()}
|
||||||
|
>
|
||||||
|
{t("upload")}
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div
|
<div
|
||||||
type="button"
|
type="button"
|
||||||
@@ -434,6 +484,7 @@ const ManageSign = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<div className="pt-3 ml-2 md:ml-0">
|
<div className="pt-3 ml-2 md:ml-0">
|
||||||
<button
|
<button
|
||||||
className="op-btn op-btn-primary"
|
className="op-btn op-btn-primary"
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ function PdfRequestFiles(props) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//function for get document details for perticular signer with signer'object id
|
//function for get document details for perticular signer with signer'object id
|
||||||
|
//whenever change anything in this function check react/angular packages also in plan js
|
||||||
const getTemplateDetails = async () => {
|
const getTemplateDetails = async () => {
|
||||||
try {
|
try {
|
||||||
const params = { templateId: props.templateId, ispublic: true };
|
const params = { templateId: props.templateId, ispublic: true };
|
||||||
@@ -309,6 +310,7 @@ function PdfRequestFiles(props) {
|
|||||||
throw new Error("error: Invalid TemplateId");
|
throw new Error("error: Invalid TemplateId");
|
||||||
} else if (documentData && documentData.length > 0) {
|
} else if (documentData && documentData.length > 0) {
|
||||||
if (documentData[0]?.IsPublic) {
|
if (documentData[0]?.IsPublic) {
|
||||||
|
//handle condition when someone use plan js then setTemplateStatus is not supporting
|
||||||
props?.setTemplateStatus &&
|
props?.setTemplateStatus &&
|
||||||
props?.setTemplateStatus({
|
props?.setTemplateStatus({
|
||||||
status: "Success"
|
status: "Success"
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const UpdateExistUserAdmin = () => {
|
|||||||
const [isAlert, setIsAlert] = useState({ type: "danger", msg: "" });
|
const [isAlert, setIsAlert] = useState({ type: "danger", msg: "" });
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
checkIsAdminExist();
|
checkIsAdminExist();
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const checkIsAdminExist = async () => {
|
const checkIsAdminExist = async () => {
|
||||||
@@ -22,7 +23,7 @@ const UpdateExistUserAdmin = () => {
|
|||||||
const isAdminExist = await Parse.Cloud.run("checkadminexist");
|
const isAdminExist = await Parse.Cloud.run("checkadminexist");
|
||||||
if (isAdminExist !== "not_exist") {
|
if (isAdminExist !== "not_exist") {
|
||||||
// console.log("isAdminExist ", isAdminExist);
|
// console.log("isAdminExist ", isAdminExist);
|
||||||
setErrMsg("Admin already exists.");
|
setErrMsg(t("admin-exists"));
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log("Err in checkadminexist", err);
|
console.log("Err in checkadminexist", err);
|
||||||
@@ -52,7 +53,7 @@ const UpdateExistUserAdmin = () => {
|
|||||||
} else if (err.code === 101) {
|
} else if (err.code === 101) {
|
||||||
setIsAlert((prev) => ({ ...prev, msg: t("user-not-found") }));
|
setIsAlert((prev) => ({ ...prev, msg: t("user-not-found") }));
|
||||||
} else if (err.code === 137) {
|
} else if (err.code === 137) {
|
||||||
setIsAlert((prev) => ({ ...prev, msg: t("admin-already-exist") }));
|
setIsAlert((prev) => ({ ...prev, msg: t("admin-exists") }));
|
||||||
} else {
|
} else {
|
||||||
setErrMsg(t("something-went-wrong-mssg"));
|
setErrMsg(t("something-went-wrong-mssg"));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,7 @@ const ReportTable = (props) => {
|
|||||||
const [reason, setReason] = useState("");
|
const [reason, setReason] = useState("");
|
||||||
const [isDownloadModal, setIsDownloadModal] = useState(false);
|
const [isDownloadModal, setIsDownloadModal] = useState(false);
|
||||||
const [isEmbed, setIsEmbed] = useState(false);
|
const [isEmbed, setIsEmbed] = useState(false);
|
||||||
|
const [isPublicTour, setIsPublicTour] = useState();
|
||||||
const Extand_Class = localStorage.getItem("Extand_Class");
|
const Extand_Class = localStorage.getItem("Extand_Class");
|
||||||
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
const extClass = Extand_Class && JSON.parse(Extand_Class);
|
||||||
const startIndex = (currentPage - 1) * props.docPerPage;
|
const startIndex = (currentPage - 1) * props.docPerPage;
|
||||||
@@ -373,6 +374,19 @@ const ReportTable = (props) => {
|
|||||||
handleEmbedFunction(item);
|
handleEmbedFunction(item);
|
||||||
} else if (act.action === "CopyTemplateId") {
|
} else if (act.action === "CopyTemplateId") {
|
||||||
copyTemplateId(item.objectId);
|
copyTemplateId(item.objectId);
|
||||||
|
} else if (act.action === "CopyPublicURL") {
|
||||||
|
const isPublic = item?.IsPublic;
|
||||||
|
if (isPublic) {
|
||||||
|
let publicUrl = "";
|
||||||
|
if (isStaging) {
|
||||||
|
publicUrl = `https://staging.opensign.me/publicsign?templateid=${item.objectId}`;
|
||||||
|
} else {
|
||||||
|
publicUrl = `https://opensign.me/publicsign?templateid=${item.objectId}`;
|
||||||
|
}
|
||||||
|
copyTemplateId(publicUrl);
|
||||||
|
} else {
|
||||||
|
setIsPublicTour({ [item.objectId]: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Get current list
|
// Get current list
|
||||||
@@ -1133,6 +1147,17 @@ const ReportTable = (props) => {
|
|||||||
setIsPublicUserName(extendUser[0]?.UserName || "");
|
setIsPublicUserName(extendUser[0]?.UserName || "");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const publicTourConfig = [
|
||||||
|
{
|
||||||
|
selector: '[data-tut="IsPublic"]',
|
||||||
|
content: t("public-tour-message"),
|
||||||
|
position: "top",
|
||||||
|
style: { fontSize: "13px" }
|
||||||
|
}
|
||||||
|
];
|
||||||
|
const closePublicTour = () => {
|
||||||
|
setIsPublicTour();
|
||||||
|
};
|
||||||
return (
|
return (
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{Object.keys(actLoader)?.length > 0 && (
|
{Object.keys(actLoader)?.length > 0 && (
|
||||||
@@ -1153,6 +1178,7 @@ const ReportTable = (props) => {
|
|||||||
)}
|
)}
|
||||||
{isAlert && <Alert type={alertMsg.type}>{alertMsg.message}</Alert>}
|
{isAlert && <Alert type={alertMsg.type}>{alertMsg.message}</Alert>}
|
||||||
{props.tourData && props.ReportName === "Templates" && (
|
{props.tourData && props.ReportName === "Templates" && (
|
||||||
|
<>
|
||||||
<Tour
|
<Tour
|
||||||
onRequestClose={closeTour}
|
onRequestClose={closeTour}
|
||||||
steps={props.tourData}
|
steps={props.tourData}
|
||||||
@@ -1160,6 +1186,19 @@ const ReportTable = (props) => {
|
|||||||
// rounded={5}
|
// rounded={5}
|
||||||
closeWithMask={false}
|
closeWithMask={false}
|
||||||
/>
|
/>
|
||||||
|
{isPublicTour && (
|
||||||
|
<Tour
|
||||||
|
showNumber={false}
|
||||||
|
showNavigation={false}
|
||||||
|
showNavigationNumber={false}
|
||||||
|
onRequestClose={closePublicTour}
|
||||||
|
steps={publicTourConfig}
|
||||||
|
isOpen={true}
|
||||||
|
rounded={5}
|
||||||
|
closeWithMask={false}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
<div className="flex flex-row items-center justify-between my-2 mx-3 text-[20px] md:text-[23px]">
|
||||||
<div className="font-light">
|
<div className="font-light">
|
||||||
@@ -1375,13 +1414,17 @@ const ReportTable = (props) => {
|
|||||||
isEnableSubscription && (
|
isEnableSubscription && (
|
||||||
<td className=" pl-[20px] py-2">
|
<td className=" pl-[20px] py-2">
|
||||||
{props.ReportName === "Templates" && (
|
{props.ReportName === "Templates" && (
|
||||||
<div className="flex flex-row">
|
<div
|
||||||
|
className="flex flex-row "
|
||||||
|
data-tut="IsPublic"
|
||||||
|
>
|
||||||
<label className="cursor-pointer relative inline-flex items-center mb-0">
|
<label className="cursor-pointer relative inline-flex items-center mb-0">
|
||||||
<input
|
<input
|
||||||
checked={props.isPublic?.[item.objectId]}
|
checked={props.isPublic?.[item.objectId]}
|
||||||
onChange={(e) =>
|
onChange={(e) => {
|
||||||
handlePublicChange(e, item)
|
setIsPublicTour();
|
||||||
}
|
handlePublicChange(e, item);
|
||||||
|
}}
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
value=""
|
value=""
|
||||||
className="sr-only peer"
|
className="sr-only peer"
|
||||||
|
|||||||
@@ -132,7 +132,8 @@
|
|||||||
"View": "View",
|
"View": "View",
|
||||||
"option": "Option",
|
"option": "Option",
|
||||||
"Embed": "Embed",
|
"Embed": "Embed",
|
||||||
"Copy TemplateId":"Copy TemplateId"
|
"Copy TemplateId": "Copy TemplateId",
|
||||||
|
"Copy Public URL": "Copy Public URL"
|
||||||
},
|
},
|
||||||
"report-heading": {
|
"report-heading": {
|
||||||
"Sr.No": "Sr.No",
|
"Sr.No": "Sr.No",
|
||||||
@@ -639,7 +640,7 @@
|
|||||||
"public-template-mssg-3": "Need more details or examples?",
|
"public-template-mssg-3": "Need more details or examples?",
|
||||||
"public-template-mssg-4": "Visit the",
|
"public-template-mssg-4": "Visit the",
|
||||||
"public-template-mssg-5": " npm for the latest updates, detailed documentation, and version history.",
|
"public-template-mssg-5": " npm for the latest updates, detailed documentation, and version history.",
|
||||||
"public-template-mssg-6" :"You need to set this template as public before you can utilize this code snippet.",
|
"public-template-mssg-6": "Before you can use this code snippet, you must make this template public.",
|
||||||
"copy-code": "COPY",
|
"copy-code": "COPY",
|
||||||
"copied-code": "COPIED",
|
"copied-code": "COPIED",
|
||||||
"Installation": "Installation",
|
"Installation": "Installation",
|
||||||
@@ -668,5 +669,8 @@
|
|||||||
"download-files": "Download files",
|
"download-files": "Download files",
|
||||||
"download-pdf": "Download Pdf",
|
"download-pdf": "Download Pdf",
|
||||||
"pdf-certificate": "Download Pdf + Certificate",
|
"pdf-certificate": "Download Pdf + Certificate",
|
||||||
"document-logs":"Document logs"
|
"document-logs": "Document logs",
|
||||||
|
"server-down": "Unable to connect to the OpenSign server. If you are self-hosting OpenSign, please ensure that all the steps in the documentation have been followed correctly. If you're running OpenSign locally, you might be accessing it through an incorrect port number.",
|
||||||
|
"admin-exists": "Admin already exists. Please login to the application using admin credentials in order to manage users.",
|
||||||
|
"public-tour-message": "Please make template public to copy public URL"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,7 +152,8 @@
|
|||||||
"View": "Voir",
|
"View": "Voir",
|
||||||
"option": "Option",
|
"option": "Option",
|
||||||
"Embed": "Intégrer",
|
"Embed": "Intégrer",
|
||||||
"Copy TemplateId": "Copier l'ID du modèle"
|
"Copy TemplateId": "Copier l'ID du modèle",
|
||||||
|
"Copy Public URL": "Copier l'URL publique"
|
||||||
},
|
},
|
||||||
"report-help": {
|
"report-help": {
|
||||||
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
"Draft Documents": "Il s'agit de documents que vous avez commencés mais que vous n'avez pas finalisés pour envoi.",
|
||||||
@@ -638,7 +639,7 @@
|
|||||||
"public-template-mssg-3": "Besoin de plus de détails ou d'exemples ?",
|
"public-template-mssg-3": "Besoin de plus de détails ou d'exemples ?",
|
||||||
"public-template-mssg-4": "Visitez le",
|
"public-template-mssg-4": "Visitez le",
|
||||||
"public-template-mssg-5": "npm pour les dernières mises à jour, une documentation détaillée et l'historique des versions.",
|
"public-template-mssg-5": "npm pour les dernières mises à jour, une documentation détaillée et l'historique des versions.",
|
||||||
"public-template-mssg-6":"Vous devez définir ce modèle comme public avant de pouvoir utiliser cet extrait de code.",
|
"public-template-mssg-6": "Avant de pouvoir utiliser cet extrait de code, vous devez rendre ce modèle public.",
|
||||||
"copy-code": "COPIE",
|
"copy-code": "COPIE",
|
||||||
"copied-code": "COPIÉ",
|
"copied-code": "COPIÉ",
|
||||||
"Installation": "Installation",
|
"Installation": "Installation",
|
||||||
@@ -667,6 +668,8 @@
|
|||||||
"download-files": "Télécharger des fichiers",
|
"download-files": "Télécharger des fichiers",
|
||||||
"download-pdf": "Télécharger le PDF",
|
"download-pdf": "Télécharger le PDF",
|
||||||
"pdf-certificate": "Télécharger Pdf + Certificat",
|
"pdf-certificate": "Télécharger Pdf + Certificat",
|
||||||
"document-logs":"Journaux de documents"
|
"document-logs": "Journaux de documents",
|
||||||
|
"server-down": "Impossible de se connecter au serveur OpenSign. Si vous hébergez vous-même OpenSign, veuillez vous assurer que toutes les étapes de la documentation ont été correctement suivies. Si vous exécutez OpenSign localement, vous y accédez peut-être via un numéro de port incorrect.",
|
||||||
|
"admin-exists": "L'administrateur existe déjà. Veuillez vous connecter à l'application en utilisant les informations d'identification de l'administrateur afin de gérer les utilisateurs.",
|
||||||
|
"public-tour-message": "Veuillez rendre le modèle public pour copier l'URL publique"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
background: white;
|
background: white;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
animation: inAnimation 2s ease-in-out;
|
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -196,8 +196,9 @@ export default async function createDocumentWithTemplate(request, response) {
|
|||||||
if (TimeToCompleteDays) {
|
if (TimeToCompleteDays) {
|
||||||
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
object.set('TimeToCompleteDays', TimeToCompleteDays);
|
||||||
}
|
}
|
||||||
const enableOTP = request.body?.enableOTP === true ? true : false;
|
const enableOTP = request.body?.enableOTP;
|
||||||
const IsEnableOTP = enableOTP || template?.IsEnableOTP || false;
|
const IsEnableOTP =
|
||||||
|
enableOTP !== undefined ? enableOTP : template?.IsEnableOTP || false;
|
||||||
object.set('IsEnableOTP', IsEnableOTP);
|
object.set('IsEnableOTP', IsEnableOTP);
|
||||||
object.set('CreatedBy', template.CreatedBy);
|
object.set('CreatedBy', template.CreatedBy);
|
||||||
object.set('ExtUserPtr', {
|
object.set('ExtUserPtr', {
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ export default async function updateDocument(request, response) {
|
|||||||
objectId: request?.body?.folderId,
|
objectId: request?.body?.folderId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (request.body?.enableOTP !== undefined) {
|
||||||
if (request.body?.enableOTP) {
|
|
||||||
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
|
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
|
||||||
}
|
}
|
||||||
|
|
||||||
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
||||||
if (updatedRes) {
|
if (updatedRes) {
|
||||||
if (request.posthog) {
|
if (request.posthog) {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export default async function updateTemplate(request, response) {
|
|||||||
objectId: request?.body?.folderId,
|
objectId: request?.body?.folderId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (request.body?.enableOTP) {
|
if (request.body?.enableOTP !== undefined) {
|
||||||
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
|
updateQuery.set('IsEnableOTP', request.body?.enableOTP);
|
||||||
}
|
}
|
||||||
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
const updatedRes = await updateQuery.save(null, { useMasterKey: true });
|
||||||
|
|||||||
@@ -51,7 +51,10 @@ export default async function UpdateExistUserAsAdmin(request) {
|
|||||||
extClsQuery.notEqualTo('IsDisabled', true);
|
extClsQuery.notEqualTo('IsDisabled', true);
|
||||||
const extAdminRes = await extClsQuery.find({ useMasterKey: true });
|
const extAdminRes = await extClsQuery.find({ useMasterKey: true });
|
||||||
if (extAdminRes && extAdminRes.length === 1 && extAdminRes?.[0]?.get('OrganizationId')) {
|
if (extAdminRes && extAdminRes.length === 1 && extAdminRes?.[0]?.get('OrganizationId')) {
|
||||||
throw new Parse.Error(Parse.Error.DUPLICATE_VALUE, 'Admin already exist.');
|
throw new Parse.Error(
|
||||||
|
Parse.Error.DUPLICATE_VALUE,
|
||||||
|
'Admin already exists. Please login to the application using admin credentials in order to manage users.'
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
const extCls = new Parse.Query('contracts_Users');
|
const extCls = new Parse.Query('contracts_Users');
|
||||||
extCls.equalTo('Email', email);
|
extCls.equalTo('Email', email);
|
||||||
|
|||||||
Generated
+8
-8
@@ -25,7 +25,7 @@
|
|||||||
"googleapis": "^144.0.0",
|
"googleapis": "^144.0.0",
|
||||||
"jsonschema": "^1.4.1",
|
"jsonschema": "^1.4.1",
|
||||||
"mailgun.js": "^10.2.3",
|
"mailgun.js": "^10.2.3",
|
||||||
"mongoose": "^8.6.3",
|
"mongoose": "^8.7.0",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"multer-s3": "^3.0.1",
|
"multer-s3": "^3.0.1",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
@@ -8247,13 +8247,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mongoose": {
|
"node_modules/mongoose": {
|
||||||
"version": "8.6.3",
|
"version": "8.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.7.0.tgz",
|
||||||
"integrity": "sha512-++yRmm7hjMbqVA/8WeiygTnEfrFbiy+OBjQi49GFJIvCQuSYE56myyQWo4j5hbpcHjhHQU8NukMNGTwAWFWjIw==",
|
"integrity": "sha512-rUCSF1mMYQXjXYdqEQLLlMD3xbcj2j1/hRn+9VnVj7ipzru/UoUZxlj/hWmteKMAh4EFnDZ+BIrmma9l/0Hi1g==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bson": "^6.7.0",
|
"bson": "^6.7.0",
|
||||||
"kareem": "2.6.3",
|
"kareem": "2.6.3",
|
||||||
"mongodb": "6.8.0",
|
"mongodb": "6.9.0",
|
||||||
"mpath": "0.9.0",
|
"mpath": "0.9.0",
|
||||||
"mquery": "5.0.0",
|
"mquery": "5.0.0",
|
||||||
"ms": "2.1.3",
|
"ms": "2.1.3",
|
||||||
@@ -8325,9 +8325,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mongoose/node_modules/mongodb": {
|
"node_modules/mongoose/node_modules/mongodb": {
|
||||||
"version": "6.8.0",
|
"version": "6.9.0",
|
||||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz",
|
||||||
"integrity": "sha512-HGQ9NWDle5WvwMnrvUxsFYPd3JEbqD3RgABHBQRuoCEND0qzhsd0iH5ypHsf1eJ+sXmvmyKpP+FLOKY8Il7jMw==",
|
"integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mongodb-js/saslprep": "^1.1.5",
|
"@mongodb-js/saslprep": "^1.1.5",
|
||||||
"bson": "^6.7.0",
|
"bson": "^6.7.0",
|
||||||
|
|||||||
@@ -34,7 +34,7 @@
|
|||||||
"googleapis": "^144.0.0",
|
"googleapis": "^144.0.0",
|
||||||
"jsonschema": "^1.4.1",
|
"jsonschema": "^1.4.1",
|
||||||
"mailgun.js": "^10.2.3",
|
"mailgun.js": "^10.2.3",
|
||||||
"mongoose": "^8.6.3",
|
"mongoose": "^8.7.0",
|
||||||
"multer": "^1.4.5-lts.1",
|
"multer": "^1.4.5-lts.1",
|
||||||
"multer-s3": "^3.0.1",
|
"multer-s3": "^3.0.1",
|
||||||
"node-forge": "^1.3.1",
|
"node-forge": "^1.3.1",
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ services:
|
|||||||
server:
|
server:
|
||||||
image: opensign/opensignserver:main
|
image: opensign/opensignserver:main
|
||||||
container_name: OpenSignServer-container
|
container_name: OpenSignServer-container
|
||||||
|
volumes:
|
||||||
|
- opensign-files:/usr/src/app/files
|
||||||
ports:
|
ports:
|
||||||
- "8080:8080"
|
- "8080:8080"
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -56,3 +58,4 @@ volumes:
|
|||||||
web-root:
|
web-root:
|
||||||
caddy_data:
|
caddy_data:
|
||||||
caddy_config:
|
caddy_config:
|
||||||
|
opensign-files:
|
||||||
|
|||||||
Reference in New Issue
Block a user