mirror of
https://github.com/OpenSignLabs/OpenSign.git
synced 2026-09-28 04:24:57 +02:00
Merge pull request #568 from OpenSignLabs/custom_logo
feat: implement custom email template of request email and completion email
This commit is contained in:
Generated
+126
@@ -34,6 +34,7 @@
|
|||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-modal": "^3.16.1",
|
"react-modal": "^3.16.1",
|
||||||
"react-pdf": "^7.7.1",
|
"react-pdf": "^7.7.1",
|
||||||
|
"react-quill": "^2.0.0",
|
||||||
"react-redux": "^9.1.0",
|
"react-redux": "^9.1.0",
|
||||||
"react-rnd": "^10.4.1",
|
"react-rnd": "^10.4.1",
|
||||||
"react-router-dom": "^6.22.3",
|
"react-router-dom": "^6.22.3",
|
||||||
@@ -6209,6 +6210,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz",
|
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.8.tgz",
|
||||||
"integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg=="
|
"integrity": "sha512-u95svzDlTysU5xecFNTgfFG5RUWu1A9P0VzgpcIiGZA9iraHOdSzcxMxQ55DyeRaGCSxQi7LxXDI4rzq/MYfdg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/quill": {
|
||||||
|
"version": "1.3.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/quill/-/quill-1.3.10.tgz",
|
||||||
|
"integrity": "sha512-IhW3fPW+bkt9MLNlycw8u8fWb7oO7W5URC9MfZYHBlA24rex9rs23D5DETChu1zvgVdc5ka64ICjJOgQMr6Shw==",
|
||||||
|
"dependencies": {
|
||||||
|
"parchment": "^1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/range-parser": {
|
"node_modules/@types/range-parser": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.5.tgz",
|
||||||
@@ -9432,6 +9441,25 @@
|
|||||||
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
|
||||||
"integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA=="
|
"integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/deep-equal": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==",
|
||||||
|
"dependencies": {
|
||||||
|
"is-arguments": "^1.1.1",
|
||||||
|
"is-date-object": "^1.0.5",
|
||||||
|
"is-regex": "^1.1.4",
|
||||||
|
"object-is": "^1.1.5",
|
||||||
|
"object-keys": "^1.1.1",
|
||||||
|
"regexp.prototype.flags": "^1.5.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/deep-extend": {
|
"node_modules/deep-extend": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||||
@@ -10990,6 +11018,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||||
},
|
},
|
||||||
|
"node_modules/extend": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||||
|
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
|
||||||
|
},
|
||||||
"node_modules/external-editor": {
|
"node_modules/external-editor": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz",
|
||||||
@@ -12616,6 +12649,21 @@
|
|||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-arguments": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.2",
|
||||||
|
"has-tostringtag": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-array-buffer": {
|
"node_modules/is-array-buffer": {
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
|
||||||
@@ -16845,6 +16893,21 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/object-is": {
|
||||||
|
"version": "1.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
|
||||||
|
"integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"call-bind": "^1.0.7",
|
||||||
|
"define-properties": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/object-keys": {
|
"node_modules/object-keys": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||||
@@ -17198,6 +17261,11 @@
|
|||||||
"tslib": "^2.0.3"
|
"tslib": "^2.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/parchment": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/parchment/-/parchment-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-J5FBQt/pM2inLzg4hEWmzQx/8h8D0CiDxaG3vyp9rKrQRSDgBlhjdP5jQGgosEajXPSQouXGHOmVdgo7QmJuOg=="
|
||||||
|
},
|
||||||
"node_modules/parent-module": {
|
"node_modules/parent-module": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
||||||
@@ -19138,6 +19206,50 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/quill": {
|
||||||
|
"version": "1.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/quill/-/quill-1.3.7.tgz",
|
||||||
|
"integrity": "sha512-hG/DVzh/TiknWtE6QmWAF/pxoZKYxfe3J/d/+ShUWkDvvkZQVTPeVmUJVu1uE6DDooC4fWTiCLh84ul89oNz5g==",
|
||||||
|
"dependencies": {
|
||||||
|
"clone": "^2.1.1",
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
|
"eventemitter3": "^2.0.3",
|
||||||
|
"extend": "^3.0.2",
|
||||||
|
"parchment": "^1.1.4",
|
||||||
|
"quill-delta": "^3.6.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quill-delta": {
|
||||||
|
"version": "3.6.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/quill-delta/-/quill-delta-3.6.3.tgz",
|
||||||
|
"integrity": "sha512-wdIGBlcX13tCHOXGMVnnTVFtGRLoP0imqxM696fIPwIf5ODIYUHIvHbZcyvGlZFiFhK5XzDC2lpjbxRhnM05Tg==",
|
||||||
|
"dependencies": {
|
||||||
|
"deep-equal": "^1.0.1",
|
||||||
|
"extend": "^3.0.2",
|
||||||
|
"fast-diff": "1.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quill-delta/node_modules/fast-diff": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-KaJUt+M9t1qaIteSvjc6P3RbMdXsNhK61GRftR6SNxqmhthcd9MGIi4T+o0jD8LUSpSnSKXE20nLtJ3fOHxQig=="
|
||||||
|
},
|
||||||
|
"node_modules/quill/node_modules/clone": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/quill/node_modules/eventemitter3": {
|
||||||
|
"version": "2.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-2.0.3.tgz",
|
||||||
|
"integrity": "sha512-jLN68Dx5kyFHaePoXWPsCGW5qdyZQtLYHkxkg02/Mz6g0kYpDx4FyP6XfArhQdlOC4b8Mv+EMxPo/8La7Tzghg=="
|
||||||
|
},
|
||||||
"node_modules/radix-ui": {
|
"node_modules/radix-ui": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.0.1.tgz",
|
||||||
@@ -19749,6 +19861,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-quill": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-quill/-/react-quill-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-4qQtv1FtCfLgoD3PXAur5RyxuUbPXQGOHgTlFie3jtxp43mXDtzCKaOgQ3mLyZfi1PUlyjycfivKelFhy13QUg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/quill": "^1.3.10",
|
||||||
|
"lodash": "^4.17.4",
|
||||||
|
"quill": "^1.3.7"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16 || ^17 || ^18",
|
||||||
|
"react-dom": "^16 || ^17 || ^18"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-reconciler": {
|
"node_modules/react-reconciler": {
|
||||||
"version": "0.29.0",
|
"version": "0.29.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-reconciler/-/react-reconciler-0.29.0.tgz",
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
"react-konva": "^18.2.10",
|
"react-konva": "^18.2.10",
|
||||||
"react-modal": "^3.16.1",
|
"react-modal": "^3.16.1",
|
||||||
"react-pdf": "^7.7.1",
|
"react-pdf": "^7.7.1",
|
||||||
|
"react-quill": "^2.0.0",
|
||||||
"react-redux": "^9.1.0",
|
"react-redux": "^9.1.0",
|
||||||
"react-rnd": "^10.4.1",
|
"react-rnd": "^10.4.1",
|
||||||
"react-router-dom": "^6.22.3",
|
"react-router-dom": "^6.22.3",
|
||||||
|
|||||||
@@ -28,13 +28,15 @@ const Header = ({ showSidebar }) => {
|
|||||||
}, []);
|
}, []);
|
||||||
async function checkSubscription() {
|
async function checkSubscription() {
|
||||||
if (isEnableSubscription) {
|
if (isEnableSubscription) {
|
||||||
const applogo = await getAppLogo();
|
|
||||||
if (applogo) {
|
|
||||||
setAppLogo(applogo);
|
|
||||||
} else {
|
|
||||||
setAppLogo(localStorage.getItem("appLogo") || "");
|
|
||||||
}
|
|
||||||
const getIsSubscribe = await checkIsSubscribed();
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
if (getIsSubscribe) {
|
||||||
|
const applogo = await getAppLogo();
|
||||||
|
if (applogo) {
|
||||||
|
setAppLogo(applogo);
|
||||||
|
} else {
|
||||||
|
setAppLogo(localStorage.getItem("appLogo") || "");
|
||||||
|
}
|
||||||
|
}
|
||||||
setIsPro(getIsSubscribe);
|
setIsPro(getIsSubscribe);
|
||||||
setIsSubscribe(getIsSubscribe);
|
setIsSubscribe(getIsSubscribe);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,157 @@
|
|||||||
|
import React from "react";
|
||||||
|
import { Quill } from "react-quill";
|
||||||
|
|
||||||
|
// Custom Undo button icon component for Quill editor. You can import it directly
|
||||||
|
// from 'quill/assets/icons/undo.svg' but I found that a number of loaders do not
|
||||||
|
// handle them correctly
|
||||||
|
const CustomUndo = () => (
|
||||||
|
<svg viewBox="0 0 18 18">
|
||||||
|
<polygon className="ql-fill ql-stroke" points="6 10 4 12 2 10 6 10" />
|
||||||
|
<path
|
||||||
|
className="ql-stroke"
|
||||||
|
d="M8.09,13.91A4.6,4.6,0,0,0,9,14,5,5,0,1,0,4,9"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Redo button icon component for Quill editor
|
||||||
|
const CustomRedo = () => (
|
||||||
|
<svg viewBox="0 0 18 18">
|
||||||
|
<polygon className="ql-fill ql-stroke" points="12 10 14 12 16 10 12 10" />
|
||||||
|
<path
|
||||||
|
className="ql-stroke"
|
||||||
|
d="M9.91,13.91A4.6,4.6,0,0,1,9,14a5,5,0,1,1,5-5"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
);
|
||||||
|
|
||||||
|
// Undo and redo functions for Custom Toolbar
|
||||||
|
function undoChange() {
|
||||||
|
this.quill.history.undo();
|
||||||
|
}
|
||||||
|
function redoChange() {
|
||||||
|
this.quill.history.redo();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add sizes to whitelist and register them
|
||||||
|
const Size = Quill.import("formats/size");
|
||||||
|
Size.whitelist = ["extra-small", "small", "medium", "large"];
|
||||||
|
Quill.register(Size, true);
|
||||||
|
|
||||||
|
// Add fonts to whitelist and register them
|
||||||
|
const Font = Quill.import("formats/font");
|
||||||
|
Font.whitelist = [
|
||||||
|
"arial",
|
||||||
|
"comic-sans",
|
||||||
|
"courier-new",
|
||||||
|
"georgia",
|
||||||
|
"helvetica",
|
||||||
|
"lucida"
|
||||||
|
];
|
||||||
|
Quill.register(Font, true);
|
||||||
|
|
||||||
|
// Modules object for setting up the Quill editor
|
||||||
|
export const module1 = {
|
||||||
|
toolbar: {
|
||||||
|
container: "#toolbar1",
|
||||||
|
handlers: {
|
||||||
|
undo: undoChange,
|
||||||
|
redo: redoChange
|
||||||
|
}
|
||||||
|
},
|
||||||
|
history: {
|
||||||
|
delay: 500,
|
||||||
|
maxStack: 100,
|
||||||
|
userOnly: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Formats objects for setting up the Quill editor
|
||||||
|
export const formats = [
|
||||||
|
"header",
|
||||||
|
"font",
|
||||||
|
"size",
|
||||||
|
"bold",
|
||||||
|
"italic",
|
||||||
|
"underline",
|
||||||
|
"align",
|
||||||
|
"strike",
|
||||||
|
"script",
|
||||||
|
"blockquote",
|
||||||
|
"background",
|
||||||
|
"list",
|
||||||
|
"bullet",
|
||||||
|
"indent",
|
||||||
|
"link",
|
||||||
|
"image",
|
||||||
|
"color",
|
||||||
|
"code-block"
|
||||||
|
];
|
||||||
|
// Quill Toolbar component
|
||||||
|
export const QuillToolbar = ({ containerId }) => (
|
||||||
|
<div id={containerId}>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<select className="ql-font" defaultValue="arial">
|
||||||
|
<option value="arial">Arial</option>
|
||||||
|
<option value="comic-sans">Comic Sans</option>
|
||||||
|
<option value="courier-new">Courier New</option>
|
||||||
|
<option value="georgia">Georgia</option>
|
||||||
|
<option value="helvetica">Helvetica</option>
|
||||||
|
<option value="lucida">Lucida</option>
|
||||||
|
</select>
|
||||||
|
<select className="ql-size" defaultValue="medium">
|
||||||
|
<option value="extra-small">Size 1</option>
|
||||||
|
<option value="small">Size 2</option>
|
||||||
|
<option value="medium">Size 3</option>
|
||||||
|
<option value="large">Size 4</option>
|
||||||
|
</select>
|
||||||
|
<select className="ql-header" defaultValue="3">
|
||||||
|
<option value="1">Heading</option>
|
||||||
|
<option value="2">Subheading</option>
|
||||||
|
<option value="3">Normal</option>
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-bold" />
|
||||||
|
<button className="ql-italic" />
|
||||||
|
<button className="ql-underline" />
|
||||||
|
<button className="ql-strike" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-list" value="ordered" />
|
||||||
|
<button className="ql-list" value="bullet" />
|
||||||
|
<button className="ql-indent" value="-1" />
|
||||||
|
<button className="ql-indent" value="+1" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-script" value="super" />
|
||||||
|
<button className="ql-script" value="sub" />
|
||||||
|
<button className="ql-blockquote" />
|
||||||
|
<button className="ql-direction" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<select className="ql-align" />
|
||||||
|
<select className="ql-color" />
|
||||||
|
<select className="ql-background" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-link" />
|
||||||
|
<button className="ql-image" />
|
||||||
|
<button className="ql-video" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-formula" />
|
||||||
|
<button className="ql-code-block" />
|
||||||
|
<button className="ql-clean" />
|
||||||
|
</span>
|
||||||
|
<span className="ql-formats">
|
||||||
|
<button className="ql-undo">
|
||||||
|
<CustomUndo />
|
||||||
|
</button>
|
||||||
|
<button className="ql-redo">
|
||||||
|
<CustomRedo />
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
export default QuillToolbar;
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Tooltip from "../../primitives/Tooltip";
|
||||||
|
|
||||||
|
import ReactQuill from "react-quill";
|
||||||
|
import "react-quill/dist/quill.snow.css";
|
||||||
|
import EditorToolbar, { module1, formats } from "./EditorToolbar";
|
||||||
|
|
||||||
|
export function EmailBody(props) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<div className={`flex justify-center py-1 p-2`}>
|
||||||
|
<div className=" flex flex-col">
|
||||||
|
<form>
|
||||||
|
<div className="text-lg font-normal text-black">
|
||||||
|
<div className=" m-2 md:m-10 p-3 md:p-10 shadow-md hover:shadow-lg border-[1px] border-indigo-800 rounded-md">
|
||||||
|
<label className="text-sm ml-2">
|
||||||
|
Subject <Tooltip message={"email subject"} />
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
required
|
||||||
|
value={props.requestSubject}
|
||||||
|
onChange={(e) => props.setRequestSubject(e.target.value)}
|
||||||
|
placeholder="${senderName} has requested you to sign ${documentName}"
|
||||||
|
className="px-3 py-2 w-full border-[1px] border-gray-300 rounded focus:outline-none text-xs"
|
||||||
|
/>
|
||||||
|
<label className="text-sm ml-2 mt-3">
|
||||||
|
Body <Tooltip message={"email body"} />
|
||||||
|
</label>
|
||||||
|
|
||||||
|
<div className="px-3 py-2 w-full focus:outline-none text-xs">
|
||||||
|
<EditorToolbar containerId="toolbar1" />
|
||||||
|
<ReactQuill
|
||||||
|
theme="snow"
|
||||||
|
value={props.requestBody}
|
||||||
|
// value={typedText}
|
||||||
|
placeholder="add body of email "
|
||||||
|
// readOnly={loading}
|
||||||
|
// onChangeSelection={handleTextSelection} // Listen for text selection
|
||||||
|
ref={props.editorRef}
|
||||||
|
modules={module1}
|
||||||
|
formats={formats}
|
||||||
|
onChange={props.handleOnchangeRequest}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
import { themeColor } from "./const";
|
import { isEnableSubscription, themeColor } from "./const";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { rgb } from "pdf-lib";
|
import { rgb } from "pdf-lib";
|
||||||
import Parse from "parse";
|
import Parse from "parse";
|
||||||
@@ -501,14 +501,32 @@ export const signPdfFun = async (
|
|||||||
base64Url,
|
base64Url,
|
||||||
documentId,
|
documentId,
|
||||||
signerObjectId,
|
signerObjectId,
|
||||||
setIsAlert
|
setIsAlert,
|
||||||
|
objectId,
|
||||||
|
isSubscribed
|
||||||
) => {
|
) => {
|
||||||
let singleSign;
|
let singleSign,
|
||||||
|
isCustomCompletionMail = false;
|
||||||
|
|
||||||
|
//get tenant details
|
||||||
|
const tenantDetails = await getTenantDetails(objectId);
|
||||||
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
|
alert("User does not exist");
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
tenantDetails?.CompletionBody &&
|
||||||
|
tenantDetails?.CompletionSubject &&
|
||||||
|
(!isEnableSubscription || isSubscribed)
|
||||||
|
) {
|
||||||
|
isCustomCompletionMail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
singleSign = {
|
singleSign = {
|
||||||
pdfFile: base64Url,
|
pdfFile: base64Url,
|
||||||
docId: documentId,
|
docId: documentId,
|
||||||
userId: signerObjectId
|
userId: signerObjectId,
|
||||||
|
isCustomCompletionMail: isCustomCompletionMail
|
||||||
};
|
};
|
||||||
|
|
||||||
const response = await axios
|
const response = await axios
|
||||||
@@ -1211,8 +1229,8 @@ export const multiSignEmbed = async (
|
|||||||
position.type === radioButtonWidget
|
position.type === radioButtonWidget
|
||||||
? 10
|
? 10
|
||||||
: position.type === "checkbox"
|
: position.type === "checkbox"
|
||||||
? 10
|
? 10
|
||||||
: newUpdateHeight;
|
: newUpdateHeight;
|
||||||
const newHeight = ind ? (ind > 0 ? widgetHeight : 0) : widgetHeight;
|
const newHeight = ind ? (ind > 0 ? widgetHeight : 0) : widgetHeight;
|
||||||
|
|
||||||
if (signyourself) {
|
if (signyourself) {
|
||||||
@@ -1804,3 +1822,43 @@ export const getAppLogo = async () => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getTenantDetails = async (objectId) => {
|
||||||
|
try {
|
||||||
|
const tenantCreditsQuery = new Parse.Query("partners_Tenant");
|
||||||
|
tenantCreditsQuery.equalTo("UserId", {
|
||||||
|
__type: "Pointer",
|
||||||
|
className: "_User",
|
||||||
|
objectId: objectId
|
||||||
|
});
|
||||||
|
const res = await tenantCreditsQuery.first();
|
||||||
|
if (res) {
|
||||||
|
const updateRes = JSON.parse(JSON.stringify(res));
|
||||||
|
return updateRes;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return "user does not exist!";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//function to convert variable string name to variable value of email body and subject
|
||||||
|
export function replaceMailVaribles(subject, body, variables) {
|
||||||
|
let replacedSubject = subject;
|
||||||
|
let replacedBody = body;
|
||||||
|
|
||||||
|
for (const variable in variables) {
|
||||||
|
const regex = new RegExp(`{{${variable}}}`, "g");
|
||||||
|
if (subject) {
|
||||||
|
replacedSubject = replacedSubject.replace(regex, variables[variable]);
|
||||||
|
}
|
||||||
|
if (body) {
|
||||||
|
replacedBody = replacedBody.replace(regex, variables[variable]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = {
|
||||||
|
subject: replacedSubject,
|
||||||
|
body: replacedBody
|
||||||
|
};
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import { useNavigate, useParams } from "react-router-dom";
|
|||||||
import "../styles/loginPage.css";
|
import "../styles/loginPage.css";
|
||||||
import loader from "../assets/images/loader2.gif";
|
import loader from "../assets/images/loader2.gif";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { themeColor } from "../constant/const";
|
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||||
import { contractUsers } from "../constant/Utils";
|
import { contractUsers, getAppLogo } from "../constant/Utils";
|
||||||
|
|
||||||
function GuestLogin() {
|
function GuestLogin() {
|
||||||
const { id, userMail, contactBookId, serverUrl } = useParams();
|
const { id, userMail, contactBookId, serverUrl } = useParams();
|
||||||
@@ -14,14 +14,27 @@ function GuestLogin() {
|
|||||||
const [EnterOTP, setEnterOtp] = useState(false);
|
const [EnterOTP, setEnterOtp] = useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
const [appLogo, setAppLogo] = useState(
|
||||||
|
"https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handleServerUrl();
|
handleServerUrl();
|
||||||
|
|
||||||
// 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 = () => {
|
const handleServerUrl = async () => {
|
||||||
|
if (isEnableSubscription) {
|
||||||
|
const applogo = await getAppLogo();
|
||||||
|
if (applogo) {
|
||||||
|
setAppLogo(applogo);
|
||||||
|
} else {
|
||||||
|
setAppLogo(localStorage.getItem("appLogo") || "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//split url in array from '&'
|
//split url in array from '&'
|
||||||
localStorage.clear();
|
localStorage.clear();
|
||||||
const checkSplit = serverUrl.split("&");
|
const checkSplit = serverUrl.split("&");
|
||||||
@@ -164,11 +177,12 @@ function GuestLogin() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="main_head">
|
<div className="main_head">
|
||||||
<div className="main-logo">
|
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||||
<img
|
<img
|
||||||
alt="sign img"
|
src={appLogo}
|
||||||
src="https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"
|
loading={true}
|
||||||
width="100%"
|
className="object-contain h-full"
|
||||||
|
alt="logo"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -58,11 +58,13 @@ function Login() {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const saveLogo = async () => {
|
const saveLogo = async () => {
|
||||||
const logo = await getAppLogo();
|
if (isEnableSubscription) {
|
||||||
if (logo) {
|
const logo = await getAppLogo();
|
||||||
setImage(logo);
|
if (logo) {
|
||||||
} else {
|
setImage(logo);
|
||||||
setImage(appInfo?.applogo || undefined);
|
} else {
|
||||||
|
setImage(appInfo?.applogo || undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleChange = (event) => {
|
const handleChange = (event) => {
|
||||||
@@ -1070,7 +1072,6 @@ function Login() {
|
|||||||
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||||
<img
|
<img
|
||||||
src={image}
|
src={image}
|
||||||
loading={true}
|
|
||||||
className="object-contain h-full"
|
className="object-contain h-full"
|
||||||
alt="The image displays the OpenSign logo with a stylized blue square with an open corner, accompanied by the tagline Seal the Deal, Openly."
|
alt="The image displays the OpenSign logo with a stylized blue square with an open corner, accompanied by the tagline Seal the Deal, Openly."
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ import {
|
|||||||
onSaveSign,
|
onSaveSign,
|
||||||
onSaveImage,
|
onSaveImage,
|
||||||
addDefaultSignatureImg,
|
addDefaultSignatureImg,
|
||||||
radioButtonWidget
|
radioButtonWidget,
|
||||||
|
replaceMailVaribles
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import Loader from "../primitives/LoaderWithMsg";
|
import Loader from "../primitives/LoaderWithMsg";
|
||||||
import HandleError from "../primitives/HandleError";
|
import HandleError from "../primitives/HandleError";
|
||||||
@@ -567,14 +568,17 @@ function PdfRequestFiles() {
|
|||||||
flag,
|
flag,
|
||||||
containerWH
|
containerWH
|
||||||
);
|
);
|
||||||
|
//get ExistUserPtr object id of user class to get tenantDetails
|
||||||
|
const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId;
|
||||||
//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
|
||||||
try {
|
try {
|
||||||
const res = await signPdfFun(
|
const res = await signPdfFun(
|
||||||
pdfBytes,
|
pdfBytes,
|
||||||
documentId,
|
documentId,
|
||||||
signerObjectId,
|
signerObjectId,
|
||||||
setIsAlert
|
setIsAlert,
|
||||||
|
objectId,
|
||||||
|
isSubscribed
|
||||||
);
|
);
|
||||||
if (res && res.status === "success") {
|
if (res && res.status === "success") {
|
||||||
setPdfUrl(res.data);
|
setPdfUrl(res.data);
|
||||||
@@ -586,10 +590,12 @@ function PdfRequestFiles() {
|
|||||||
const index = pdfDetails?.[0].Signers.findIndex(
|
const index = pdfDetails?.[0].Signers.findIndex(
|
||||||
(x) => x.Email === jsonSender.email
|
(x) => x.Email === jsonSender.email
|
||||||
);
|
);
|
||||||
|
const requestBody = pdfDetails?.[0]?.RequestBody;
|
||||||
|
const requestSubject = pdfDetails?.[0]?.RequestSubject;
|
||||||
|
|
||||||
const newIndex = index + 1;
|
const newIndex = index + 1;
|
||||||
const user = pdfDetails?.[0].Signers[newIndex];
|
const user = pdfDetails?.[0].Signers[newIndex];
|
||||||
if (user) {
|
if (user) {
|
||||||
// console.log("pdfDetails", pdfDetails);
|
|
||||||
const expireDate = pdfDetails?.[0].ExpiryDate.iso;
|
const expireDate = pdfDetails?.[0].ExpiryDate.iso;
|
||||||
const newDate = new Date(expireDate);
|
const newDate = new Date(expireDate);
|
||||||
const localExpireDate = newDate.toLocaleDateString("en-US", {
|
const localExpireDate = newDate.toLocaleDateString("en-US", {
|
||||||
@@ -597,7 +603,9 @@ function PdfRequestFiles() {
|
|||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric"
|
year: "numeric"
|
||||||
});
|
});
|
||||||
let sender = pdfDetails?.[0].ExtUserPtr.Email;
|
let senderEmail = pdfDetails?.[0].ExtUserPtr.Email;
|
||||||
|
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
||||||
|
const senderName = `${pdfDetails?.[0].ExtUserPtr.Name}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const imgPng =
|
const imgPng =
|
||||||
@@ -625,33 +633,70 @@ function PdfRequestFiles() {
|
|||||||
? pdfDetails[0].ExtUserPtr.Company
|
? pdfDetails[0].ExtUserPtr.Company
|
||||||
: "";
|
: "";
|
||||||
const themeBGcolor = themeColor;
|
const themeBGcolor = themeColor;
|
||||||
|
let replaceVar;
|
||||||
|
if (
|
||||||
|
requestBody &&
|
||||||
|
requestSubject &&
|
||||||
|
(!isEnableSubscription || isSubscribed)
|
||||||
|
) {
|
||||||
|
const replacedRequestBody = requestBody.replace(
|
||||||
|
/"/g,
|
||||||
|
"'"
|
||||||
|
);
|
||||||
|
const htmlReqBody =
|
||||||
|
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
||||||
|
replacedRequestBody +
|
||||||
|
"</body> </html>";
|
||||||
|
|
||||||
|
const variables = {
|
||||||
|
document_title: pdfDetails?.[0].Name,
|
||||||
|
sender_name: senderName,
|
||||||
|
sender_mail: senderEmail,
|
||||||
|
sender_phone: senderPhone,
|
||||||
|
receiver_name: user.Name,
|
||||||
|
receiver_email: user.Email,
|
||||||
|
receiver_phone: user.Phone,
|
||||||
|
expiry_date: localExpireDate,
|
||||||
|
company_name: orgName,
|
||||||
|
signing_url: `<a href=${signPdf}>Sign here</a>`
|
||||||
|
};
|
||||||
|
replaceVar = replaceMailVaribles(
|
||||||
|
requestSubject,
|
||||||
|
htmlReqBody,
|
||||||
|
variables
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let params = {
|
let params = {
|
||||||
extUserId: extUserId,
|
extUserId: extUserId,
|
||||||
recipient: user.Email,
|
recipient: user.Email,
|
||||||
subject: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign ${pdfDetails?.[0].Name}`,
|
subject: requestSubject
|
||||||
from: sender,
|
? replaceVar?.subject
|
||||||
html:
|
: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign ${pdfDetails?.[0].Name}`,
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
from: senderEmail,
|
||||||
imgPng +
|
html: requestBody
|
||||||
" height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" +
|
? replaceVar?.body
|
||||||
themeBGcolor +
|
: "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
||||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
imgPng +
|
||||||
pdfDetails?.[0].ExtUserPtr.Name +
|
" height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" +
|
||||||
" has requested you to review and sign <strong> " +
|
themeBGcolor +
|
||||||
pdfDetails?.[0].Name +
|
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
pdfDetails?.[0].ExtUserPtr.Name +
|
||||||
sender +
|
" has requested you to review and sign <strong> " +
|
||||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
pdfDetails?.[0].Name +
|
||||||
orgName +
|
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
senderEmail +
|
||||||
localExpireDate +
|
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
orgName +
|
||||||
signPdf +
|
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expires on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
localExpireDate +
|
||||||
sender +
|
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
||||||
" directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= " +
|
signPdf +
|
||||||
openSignUrl +
|
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
||||||
" target=_blank>here</a>.</p> </div></div></body> </html>"
|
senderEmail +
|
||||||
|
" directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= " +
|
||||||
|
openSignUrl +
|
||||||
|
" target=_blank>here</a>.</p> </div></div></body> </html>"
|
||||||
};
|
};
|
||||||
await axios.post(url, params, {
|
await axios.post(url, params, {
|
||||||
headers: headers
|
headers: headers
|
||||||
@@ -689,6 +734,7 @@ function PdfRequestFiles() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//function for update TourStatus
|
//function for update TourStatus
|
||||||
const closeTour = async () => {
|
const closeTour = async () => {
|
||||||
setWidgetsTour(false);
|
setWidgetsTour(false);
|
||||||
@@ -1052,9 +1098,9 @@ function PdfRequestFiles() {
|
|||||||
isDecline.currnt === "Sure"
|
isDecline.currnt === "Sure"
|
||||||
? "Are you sure want to decline this document ?"
|
? "Are you sure want to decline this document ?"
|
||||||
: isDecline.currnt === "YouDeclined"
|
: isDecline.currnt === "YouDeclined"
|
||||||
? "You have declined this document!"
|
? "You have declined this document!"
|
||||||
: isDecline.currnt === "another" &&
|
: isDecline.currnt === "another" &&
|
||||||
"You cannot sign this document as it has been declined by one or more recipient(s)."
|
"You cannot sign this document as it has been declined by one or more recipient(s)."
|
||||||
}
|
}
|
||||||
footerMessage={isDecline.currnt === "Sure"}
|
footerMessage={isDecline.currnt === "Sure"}
|
||||||
declineDoc={declineDoc}
|
declineDoc={declineDoc}
|
||||||
|
|||||||
@@ -28,7 +28,9 @@ import {
|
|||||||
textInputWidget,
|
textInputWidget,
|
||||||
textWidget,
|
textWidget,
|
||||||
radioButtonWidget,
|
radioButtonWidget,
|
||||||
color
|
color,
|
||||||
|
getTenantDetails,
|
||||||
|
replaceMailVaribles
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import RenderPdf from "../components/pdf/RenderPdf";
|
import RenderPdf from "../components/pdf/RenderPdf";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
@@ -40,8 +42,11 @@ import ModalUi from "../primitives/ModalUi";
|
|||||||
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
import DropdownWidgetOption from "../components/pdf/DropdownWidgetOption";
|
||||||
import WidgetNameModal from "../components/pdf/WidgetNameModal";
|
import WidgetNameModal from "../components/pdf/WidgetNameModal";
|
||||||
import { SaveFileSize } from "../constant/saveFileSize";
|
import { SaveFileSize } from "../constant/saveFileSize";
|
||||||
|
import { EmailBody } from "../components/pdf/EmailBody";
|
||||||
|
import Upgrade from "../primitives/Upgrade";
|
||||||
|
|
||||||
function PlaceHolderSign() {
|
function PlaceHolderSign() {
|
||||||
|
const editorRef = useRef();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { state } = useLocation();
|
const { state } = useLocation();
|
||||||
const [pdfDetails, setPdfDetails] = useState([]);
|
const [pdfDetails, setPdfDetails] = useState([]);
|
||||||
@@ -83,6 +88,8 @@ function PlaceHolderSign() {
|
|||||||
const [signKey, setSignKey] = useState();
|
const [signKey, setSignKey] = useState();
|
||||||
const [tempSignerId, setTempSignerId] = useState("");
|
const [tempSignerId, setTempSignerId] = useState("");
|
||||||
const [blockColor, setBlockColor] = useState("");
|
const [blockColor, setBlockColor] = useState("");
|
||||||
|
const [defaultBody, setDefaultBody] = useState("");
|
||||||
|
const [defaultSubject, setDefaultSubject] = useState("");
|
||||||
const [pdfLoadFail, setPdfLoadFail] = useState({
|
const [pdfLoadFail, setPdfLoadFail] = useState({
|
||||||
status: false,
|
status: false,
|
||||||
type: "load"
|
type: "load"
|
||||||
@@ -106,11 +113,14 @@ function PlaceHolderSign() {
|
|||||||
const [mailStatus, setMailStatus] = useState("");
|
const [mailStatus, setMailStatus] = useState("");
|
||||||
const [isCurrUser, setIsCurrUser] = useState(false);
|
const [isCurrUser, setIsCurrUser] = useState(false);
|
||||||
const [isSubscribe, setIsSubscribe] = useState(false);
|
const [isSubscribe, setIsSubscribe] = useState(false);
|
||||||
|
const [requestSubject, setRequestSubject] = useState("");
|
||||||
|
const [requestBody, setRequestBody] = useState("");
|
||||||
const [isAlreadyPlace, setIsAlreadyPlace] = useState({
|
const [isAlreadyPlace, setIsAlreadyPlace] = useState({
|
||||||
status: false,
|
status: false,
|
||||||
message: ""
|
message: ""
|
||||||
});
|
});
|
||||||
const [extUserId, setExtUserId] = useState("");
|
const [extUserId, setExtUserId] = useState("");
|
||||||
|
const [isCustomize, setIsCustomize] = useState(false);
|
||||||
const isMobile = window.innerWidth < 767;
|
const isMobile = window.innerWidth < 767;
|
||||||
const [, drop] = useDrop({
|
const [, drop] = useDrop({
|
||||||
accept: "BOX",
|
accept: "BOX",
|
||||||
@@ -170,6 +180,48 @@ function PlaceHolderSign() {
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
//function to fetch tenant Details
|
||||||
|
const fetchTenantDetails = async () => {
|
||||||
|
const user = JSON.parse(
|
||||||
|
localStorage.getItem(
|
||||||
|
`Parse/${localStorage.getItem("parseAppId")}/currentUser`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (user) {
|
||||||
|
try {
|
||||||
|
const tenantDetails = await getTenantDetails(user?.objectId);
|
||||||
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
|
alert("User does not exist");
|
||||||
|
} else if (tenantDetails) {
|
||||||
|
const defaultRequestBody = `<p>Hi {{receiver_name}},</p><br><p>We hope this email finds you well. {{sender_name}} has requested you to review and sign {{document_title}}.</p><p>Your signature is crucial to proceed with the next steps as it signifies your agreement and authorization.</p><br><p>{{signing_url}}</p><br><p>If you have any questions or need further clarification regarding the document or the signing process, please contact the sender.</p><br><p>Thanks</p><p> Team OpenSign™</p><br>`;
|
||||||
|
if (tenantDetails?.RequestBody) {
|
||||||
|
setRequestBody(tenantDetails?.RequestBody);
|
||||||
|
setRequestSubject(tenantDetails?.RequestSubject);
|
||||||
|
|
||||||
|
setDefaultBody(defaultRequestBody);
|
||||||
|
setDefaultSubject(
|
||||||
|
`{{senderName}} has requested you to sign {{documentName}}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setRequestBody(defaultRequestBody);
|
||||||
|
setRequestSubject(
|
||||||
|
`{{senderName}} has requested you to sign {{documentName}}`
|
||||||
|
);
|
||||||
|
setDefaultBody(defaultRequestBody);
|
||||||
|
setDefaultSubject(
|
||||||
|
`{{senderName}} has requested you to sign {{documentName}}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
alert("User does not exist");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
alert("User does not exist");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (divRef.current) {
|
if (divRef.current) {
|
||||||
const pdfWidth = pdfNewWidthFun(divRef);
|
const pdfWidth = pdfNewWidthFun(divRef);
|
||||||
@@ -204,6 +256,7 @@ function PlaceHolderSign() {
|
|||||||
}
|
}
|
||||||
//function for get document details
|
//function for get document details
|
||||||
const getDocumentDetails = async () => {
|
const getDocumentDetails = async () => {
|
||||||
|
fetchTenantDetails();
|
||||||
//getting document details
|
//getting document details
|
||||||
const documentData = await contractDocument(documentId);
|
const documentData = await contractDocument(documentId);
|
||||||
if (documentData && documentData.length > 0) {
|
if (documentData && documentData.length > 0) {
|
||||||
@@ -816,6 +869,7 @@ function PlaceHolderSign() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const sendEmailToSigners = async () => {
|
const sendEmailToSigners = async () => {
|
||||||
|
let htmlReqBody;
|
||||||
setIsUiLoading(true);
|
setIsUiLoading(true);
|
||||||
const pdfUrl = await embedPrefilllData();
|
const pdfUrl = await embedPrefilllData();
|
||||||
setIsSendAlert({});
|
setIsSendAlert({});
|
||||||
@@ -827,12 +881,15 @@ function PlaceHolderSign() {
|
|||||||
month: "long",
|
month: "long",
|
||||||
year: "numeric"
|
year: "numeric"
|
||||||
});
|
});
|
||||||
let sender = pdfDetails?.[0].ExtUserPtr.Email;
|
|
||||||
|
let senderEmail = pdfDetails?.[0]?.ExtUserPtr?.Email;
|
||||||
|
let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone;
|
||||||
let signerMail = signersdata.slice();
|
let signerMail = signersdata.slice();
|
||||||
|
|
||||||
if (pdfDetails?.[0]?.SendinOrder && pdfDetails?.[0]?.SendinOrder === true) {
|
if (pdfDetails?.[0]?.SendinOrder && pdfDetails?.[0]?.SendinOrder === true) {
|
||||||
signerMail.splice(1);
|
signerMail.splice(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < signerMail.length; i++) {
|
for (let i = 0; i < signerMail.length; i++) {
|
||||||
try {
|
try {
|
||||||
const imgPng =
|
const imgPng =
|
||||||
@@ -857,40 +914,77 @@ function PlaceHolderSign() {
|
|||||||
? pdfDetails[0].ExtUserPtr.Company
|
? pdfDetails[0].ExtUserPtr.Company
|
||||||
: "";
|
: "";
|
||||||
const themeBGcolor = themeColor;
|
const themeBGcolor = themeColor;
|
||||||
|
const senderName = `${pdfDetails?.[0].ExtUserPtr.Name}`;
|
||||||
|
const documentName = `${pdfDetails?.[0].Name}`;
|
||||||
|
let replaceVar;
|
||||||
|
if (
|
||||||
|
requestBody &&
|
||||||
|
requestSubject &&
|
||||||
|
isCustomize &&
|
||||||
|
(isSubscribe || !isEnableSubscription)
|
||||||
|
) {
|
||||||
|
const replacedRequestBody = requestBody.replace(/"/g, "'");
|
||||||
|
htmlReqBody =
|
||||||
|
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
|
||||||
|
replacedRequestBody +
|
||||||
|
"</body> </html>";
|
||||||
|
|
||||||
|
const variables = {
|
||||||
|
document_title: documentName,
|
||||||
|
sender_name: senderName,
|
||||||
|
sender_mail: senderEmail,
|
||||||
|
sender_phone: senderPhone,
|
||||||
|
receiver_name: signerMail[i].Name,
|
||||||
|
receiver_email: signerMail[i].Email,
|
||||||
|
receiver_phone: signerMail[i].Phone,
|
||||||
|
expiry_date: localExpireDate,
|
||||||
|
company_name: orgName,
|
||||||
|
signing_url: `<a href=${signPdf}>Sign here</a>`
|
||||||
|
};
|
||||||
|
replaceVar = replaceMailVaribles(
|
||||||
|
requestSubject,
|
||||||
|
htmlReqBody,
|
||||||
|
variables
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let params = {
|
let params = {
|
||||||
extUserId: extUserId,
|
extUserId: extUserId,
|
||||||
recipient: signerMail[i].Email,
|
recipient: signerMail[i].Email,
|
||||||
subject: `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign ${pdfDetails?.[0].Name}`,
|
subject: isCustomize
|
||||||
from: sender,
|
? replaceVar?.subject
|
||||||
html:
|
: `${senderName} has requested you to sign ${documentName}`,
|
||||||
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
from: senderEmail,
|
||||||
imgPng +
|
html: isCustomize
|
||||||
" height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" +
|
? replaceVar?.body
|
||||||
themeBGcolor +
|
: "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /> </head> <body> <div style='background-color: #f5f5f5; padding: 20px'=> <div style=' box-shadow: rgba(0, 0, 0, 0.1) 0px 4px 12px;background: white;padding-bottom: 20px;'> <div style='padding:10px 10px 0 10px'><img src=" +
|
||||||
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
imgPng +
|
||||||
pdfDetails?.[0].ExtUserPtr.Name +
|
" height='50' style='padding: 20px,width:170px,height:40px' /></div> <div style=' padding: 2px;font-family: system-ui;background-color:" +
|
||||||
" has requested you to review and sign <strong> " +
|
themeBGcolor +
|
||||||
pdfDetails?.[0].Name +
|
";'><p style='font-size: 20px;font-weight: 400;color: white;padding-left: 20px;' > Digital Signature Request</p></div><div><p style='padding: 20px;font-family: system-ui;font-size: 14px; margin-bottom: 10px;'> " +
|
||||||
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
pdfDetails?.[0].ExtUserPtr.Name +
|
||||||
sender +
|
" has requested you to review and sign <strong> " +
|
||||||
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
pdfDetails?.[0].Name +
|
||||||
orgName +
|
"</strong>.</p><div style='padding: 5px 0px 5px 25px;display: flex;flex-direction: row;justify-content: space-around;'><table> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Sender</td> <td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||||
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expire on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
senderEmail +
|
||||||
localExpireDate +
|
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Organization</td> <td> </td><td style='color:#626363;font-weight:bold'> " +
|
||||||
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
orgName +
|
||||||
signPdf +
|
"</td></tr> <tr> <td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Expire on</td><td> </td> <td style='color:#626363;font-weight:bold'>" +
|
||||||
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
localExpireDate +
|
||||||
sender +
|
"</td></tr><tr> <td></td> <td> </td></tr></table> </div> <div style='margin-left:70px'><a href=" +
|
||||||
" directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= " +
|
signPdf +
|
||||||
openSignUrl +
|
"> <button style='padding: 12px 12px 12px 12px;background-color: #d46b0f;color: white; border: 0px;box-shadow: rgba(0, 0, 0, 0.05) 0px 6px 24px 0px,rgba(0, 0, 0, 0.08) 0px 0px 0px 1px;font-weight:bold;margin-top:30px'>Sign here</button></a> </div> <div style='display: flex; justify-content: center;margin-top: 10px;'> </div></div></div><div><p> This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " +
|
||||||
" target=_blank>here</a>.</p> </div></div></body> </html>"
|
senderEmail +
|
||||||
|
" directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ <a href= " +
|
||||||
|
openSignUrl +
|
||||||
|
" target=_blank>here</a>.</p> </div></div></body> </html>"
|
||||||
};
|
};
|
||||||
|
|
||||||
sendMail = await axios.post(url, params, { headers: headers });
|
sendMail = await axios.post(url, params, { headers: headers });
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("error", error);
|
console.log("error", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendMail.data.result.status === "success") {
|
if (sendMail.data.result.status === "success") {
|
||||||
setMailStatus("success");
|
setMailStatus("success");
|
||||||
const signers = signersdata?.map((x) => {
|
const signers = signersdata?.map((x) => {
|
||||||
@@ -923,21 +1017,45 @@ function PlaceHolderSign() {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
if (updateExpiryDate) {
|
if (updateExpiryDate) {
|
||||||
data = {
|
if (isCustomize) {
|
||||||
Placeholders: filterPrefill,
|
data = {
|
||||||
SignedUrl: pdfUrl,
|
RequestBody: htmlReqBody,
|
||||||
Signers: signers,
|
RequestSubject: requestSubject,
|
||||||
ExpiryDate: {
|
Placeholders: filterPrefill,
|
||||||
iso: updateExpiryDate,
|
SignedUrl: pdfUrl,
|
||||||
__type: "Date"
|
Signers: signers,
|
||||||
}
|
ExpiryDate: {
|
||||||
};
|
iso: updateExpiryDate,
|
||||||
|
__type: "Date"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
data = {
|
||||||
|
Placeholders: filterPrefill,
|
||||||
|
SignedUrl: pdfUrl,
|
||||||
|
Signers: signers,
|
||||||
|
ExpiryDate: {
|
||||||
|
iso: updateExpiryDate,
|
||||||
|
__type: "Date"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
data = {
|
if (isCustomize) {
|
||||||
Placeholders: filterPrefill,
|
data = {
|
||||||
SignedUrl: pdfUrl,
|
RequestBody: htmlReqBody,
|
||||||
Signers: signers
|
RequestSubject: requestSubject,
|
||||||
};
|
Placeholders: filterPrefill,
|
||||||
|
SignedUrl: pdfUrl,
|
||||||
|
Signers: signers
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
data = {
|
||||||
|
Placeholders: filterPrefill,
|
||||||
|
SignedUrl: pdfUrl,
|
||||||
|
Signers: signers
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
await axios
|
await axios
|
||||||
@@ -1394,6 +1512,15 @@ function PlaceHolderSign() {
|
|||||||
const closePopup = () => {
|
const closePopup = () => {
|
||||||
setIsAddUser({});
|
setIsAddUser({});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//function for handle ontext change and save again text in delta in Request Email flow
|
||||||
|
const handleOnchangeRequest = () => {
|
||||||
|
if (editorRef.current) {
|
||||||
|
const html = editorRef.current.editor.root.innerHTML;
|
||||||
|
setRequestBody(html);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Title title={state?.title ? state.title : "New Document"} />
|
<Title title={state?.title ? state.title : "New Document"} />
|
||||||
@@ -1475,20 +1602,78 @@ function PlaceHolderSign() {
|
|||||||
: isSendAlert.mssg === "confirm" && "Send Mail"
|
: isSendAlert.mssg === "confirm" && "Send Mail"
|
||||||
}
|
}
|
||||||
handleClose={() => setIsSendAlert({})}
|
handleClose={() => setIsSendAlert({})}
|
||||||
|
showHeaderMessage={isSendAlert.mssg === "confirm"}
|
||||||
>
|
>
|
||||||
<div style={{ height: "100%", padding: 20 }}>
|
<div
|
||||||
|
className="max-h-96 overflow-y-scroll scroll-hide"
|
||||||
|
style={{ padding: 20 }}
|
||||||
|
>
|
||||||
{isSendAlert.mssg === "sure" ? (
|
{isSendAlert.mssg === "sure" ? (
|
||||||
<p>Please add field for all recipients.</p>
|
<span>Please add field for all recipients.</span>
|
||||||
) : isSendAlert.mssg === textWidget ? (
|
) : isSendAlert.mssg === textWidget ? (
|
||||||
<p>Please confirm that you have filled the text field.</p>
|
<p>Please confirm that you have filled the text field.</p>
|
||||||
) : (
|
) : (
|
||||||
isSendAlert.mssg === "confirm" && (
|
isSendAlert.mssg === "confirm" && (
|
||||||
<p>
|
<>
|
||||||
Are you sure you want to send out this document for
|
<p>
|
||||||
signatures?
|
Are you sure you want to send out this document for
|
||||||
</p>
|
signatures?
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"flex mt-4 items-center gap-1 mt-2 underline text-blue-700 focus:outline-none "
|
||||||
|
}
|
||||||
|
onClick={() => {
|
||||||
|
isSubscribe ||
|
||||||
|
(!isEnableSubscription &&
|
||||||
|
setIsCustomize(!isCustomize));
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span
|
||||||
|
className={
|
||||||
|
isSubscribe || !isEnableSubscription
|
||||||
|
? "cursor-pointer"
|
||||||
|
: "opacity-30 select-none"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
Cutomize Email
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{!isSubscribe && isEnableSubscription && (
|
||||||
|
<Upgrade message="Upgrade to customize Email" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
|
||||||
|
{isCustomize &&
|
||||||
|
(!isEnableSubscription || isSubscribe) && (
|
||||||
|
<>
|
||||||
|
<EmailBody
|
||||||
|
editorRef={editorRef}
|
||||||
|
requestBody={requestBody}
|
||||||
|
requestSubject={requestSubject}
|
||||||
|
handleOnchangeRequest={handleOnchangeRequest}
|
||||||
|
setRequestSubject={setRequestSubject}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
"flex justify-end items-center gap-1 mt-2 underline text-blue-700 focus:outline-none cursor-pointer "
|
||||||
|
}
|
||||||
|
onClick={() => {
|
||||||
|
setRequestBody(defaultBody);
|
||||||
|
setRequestSubject(defaultSubject);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>Reset to default</span>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
height: "1px",
|
height: "1px",
|
||||||
@@ -1506,7 +1691,7 @@ function PlaceHolderSign() {
|
|||||||
type="button"
|
type="button"
|
||||||
className="finishBtn"
|
className="finishBtn"
|
||||||
>
|
>
|
||||||
Yes
|
Send
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
@@ -1852,6 +2037,7 @@ function PlaceHolderSign() {
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</ModalUi>
|
</ModalUi>
|
||||||
|
|
||||||
<LinkUserModal
|
<LinkUserModal
|
||||||
handleAddUser={handleAddUser}
|
handleAddUser={handleAddUser}
|
||||||
isAddUser={isAddUser}
|
isAddUser={isAddUser}
|
||||||
|
|||||||
@@ -475,11 +475,13 @@ const Signup = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const saveLogo = async () => {
|
const saveLogo = async () => {
|
||||||
const logo = await getAppLogo();
|
if (isEnableSubscription) {
|
||||||
if (logo) {
|
const logo = await getAppLogo();
|
||||||
setImage(logo);
|
if (logo) {
|
||||||
} else {
|
setImage(logo);
|
||||||
setImage(appInfo?.applogo || undefined);
|
} else {
|
||||||
|
setImage(appInfo?.applogo || undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -529,12 +531,7 @@ const Signup = () => {
|
|||||||
<div>
|
<div>
|
||||||
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
<div className="md:m-10 lg:m-16 md:p-4 lg:p-10 p-5 bg-[#ffffff] md:border-[1px] md:border-gray-400 ">
|
||||||
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
<div className="w-[250px] h-[66px] inline-block overflow-hidden">
|
||||||
<img
|
<img src={image} className="object-contain h-full" alt="logo" />
|
||||||
src={image}
|
|
||||||
loading={true}
|
|
||||||
className="object-contain h-full"
|
|
||||||
alt="logo"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-x-2">
|
||||||
<div className="">
|
<div className="">
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useRef, useEffect } from "react";
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
import { PDFDocument } from "pdf-lib";
|
import { PDFDocument } from "pdf-lib";
|
||||||
import "../styles/signature.css";
|
import "../styles/signature.css";
|
||||||
import { themeColor } from "../constant/const";
|
import { isEnableSubscription, themeColor } from "../constant/const";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Loader from "../primitives/LoaderWithMsg";
|
import Loader from "../primitives/LoaderWithMsg";
|
||||||
import loader from "../assets/images/loader2.gif";
|
import loader from "../assets/images/loader2.gif";
|
||||||
@@ -26,7 +26,9 @@ import {
|
|||||||
contactBook,
|
contactBook,
|
||||||
randomId,
|
randomId,
|
||||||
getDate,
|
getDate,
|
||||||
textWidget
|
textWidget,
|
||||||
|
getTenantDetails,
|
||||||
|
checkIsSubscribed
|
||||||
} from "../constant/Utils";
|
} from "../constant/Utils";
|
||||||
import { useParams } from "react-router-dom";
|
import { useParams } from "react-router-dom";
|
||||||
import Tour from "reactour";
|
import Tour from "reactour";
|
||||||
@@ -431,13 +433,13 @@ function SignYourSelf() {
|
|||||||
Width: widgetTypeExist
|
Width: widgetTypeExist
|
||||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getWidth
|
||||||
: dragTypeValue === "initials"
|
: dragTypeValue === "initials"
|
||||||
? defaultWidthHeight(dragTypeValue).width
|
? defaultWidthHeight(dragTypeValue).width
|
||||||
: "",
|
: "",
|
||||||
Height: widgetTypeExist
|
Height: widgetTypeExist
|
||||||
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
|
? calculateInitialWidthHeight(dragTypeValue, widgetValue).getHeight
|
||||||
: dragTypeValue === "initials"
|
: dragTypeValue === "initials"
|
||||||
? defaultWidthHeight(dragTypeValue).height
|
? defaultWidthHeight(dragTypeValue).height
|
||||||
: "",
|
: "",
|
||||||
options: addWidgetOptions(dragTypeValue)
|
options: addWidgetOptions(dragTypeValue)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -595,9 +597,25 @@ function SignYourSelf() {
|
|||||||
// console.log("signyourself", xyPostion);
|
// console.log("signyourself", xyPostion);
|
||||||
//function for get digital signature
|
//function for get digital signature
|
||||||
const signPdfFun = async (base64Url, documentId) => {
|
const signPdfFun = async (base64Url, documentId) => {
|
||||||
|
let isCustomCompletionMail = false;
|
||||||
|
const getIsSubscribe = await checkIsSubscribed();
|
||||||
|
const tenantDetails = await getTenantDetails(jsonSender.objectId);
|
||||||
|
if (tenantDetails && tenantDetails === "user does not exist!") {
|
||||||
|
alert("User does not exist");
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
tenantDetails?.CompletionBody &&
|
||||||
|
tenantDetails?.CompletionSubject &&
|
||||||
|
(!isEnableSubscription || getIsSubscribe)
|
||||||
|
) {
|
||||||
|
isCustomCompletionMail = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let singleSign = {
|
let singleSign = {
|
||||||
pdfFile: base64Url,
|
pdfFile: base64Url,
|
||||||
docId: documentId
|
docId: documentId,
|
||||||
|
isCustomCompletionMail: isCustomCompletionMail
|
||||||
};
|
};
|
||||||
|
|
||||||
await axios
|
await axios
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
|
import { isEnableSubscription } from "../constant/const";
|
||||||
|
import PremiumAlertHeader from "./PremiumAlertHeader";
|
||||||
|
|
||||||
const ModalUi = ({
|
const ModalUi = ({
|
||||||
children,
|
children,
|
||||||
@@ -8,12 +10,13 @@ const ModalUi = ({
|
|||||||
handleClose,
|
handleClose,
|
||||||
showHeader = true,
|
showHeader = true,
|
||||||
showClose = true,
|
showClose = true,
|
||||||
styleClass
|
styleClass,
|
||||||
|
showHeaderMessage
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
<div className="fixed z-[999] top-0 left-0 w-[100%] h-[100%] bg-black bg-opacity-[75%]">
|
<div className="fixed z-[999] 2 top-0 left-0 w-[100%] h-[100%] bg-black bg-opacity-[75%]">
|
||||||
<div
|
<div
|
||||||
className={
|
className={
|
||||||
styleClass
|
styleClass
|
||||||
@@ -37,6 +40,13 @@ const ModalUi = ({
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{!isEnableSubscription && showHeaderMessage && (
|
||||||
|
<PremiumAlertHeader
|
||||||
|
message={
|
||||||
|
"Cutomize Email is free in beta, this feature will incur a fee later."
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<div>{children}</div>
|
<div>{children}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
|
||||||
function Upgrade() {
|
function Upgrade({ message }) {
|
||||||
const navigation = useNavigate();
|
const navigation = useNavigate();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -10,7 +10,7 @@ function Upgrade() {
|
|||||||
onClick={() => navigation("/subscription")}
|
onClick={() => navigation("/subscription")}
|
||||||
className="text-blue-800 text-sm cursor-pointer hover:underline"
|
className="text-blue-800 text-sm cursor-pointer hover:underline"
|
||||||
>
|
>
|
||||||
Upgrade now
|
{message ? message : "Upgrade now"}
|
||||||
</span>
|
</span>
|
||||||
</sup>
|
</sup>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -968,6 +968,9 @@ option {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scroll-hide::-webkit-scrollbar {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
@media screen and (max-width: 350px) and (min-width: 311px) {
|
@media screen and (max-width: 350px) and (min-width: 311px) {
|
||||||
.signatureCanvas {
|
.signatureCanvas {
|
||||||
width: 280px;
|
width: 280px;
|
||||||
|
|||||||
+33
@@ -0,0 +1,33 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Parse} Parse
|
||||||
|
*/
|
||||||
|
exports.up = async Parse => {
|
||||||
|
// TODO: set className here
|
||||||
|
const className = 'contracts_Document';
|
||||||
|
const schema = new Parse.Schema(className);
|
||||||
|
schema.addString('RequestBody');
|
||||||
|
schema.addString('RequestSubject');
|
||||||
|
// TODO: Set the schema here
|
||||||
|
// Example:
|
||||||
|
// schema.addString('name').addNumber('cash');
|
||||||
|
|
||||||
|
return schema.update();
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {Parse} Parse
|
||||||
|
*/
|
||||||
|
exports.down = async Parse => {
|
||||||
|
// TODO: set className here
|
||||||
|
const className = 'contracts_Document';
|
||||||
|
const schema = new Parse.Schema(className);
|
||||||
|
schema.deleteField('RequestBody');
|
||||||
|
schema.deleteField('RequestSubject');
|
||||||
|
// TODO: Set the schema here
|
||||||
|
// Example:
|
||||||
|
// schema.deleteField('name').deleteField('cash');
|
||||||
|
|
||||||
|
return schema.update();
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user