Compare commits

...
Author SHA1 Message Date
nxglabs d4c0051cd9 Merge pull request #695 from OpenSignLabs/login_to_sandbox
refactor: handle conditions of sandbox
2025-05-29 19:04:16 +00:00
31 changed files with 302 additions and 291 deletions
-25
View File
@@ -1,25 +0,0 @@
# Use an official Node runtime as the base image
FROM node:18
# Set the working directory inside the container
WORKDIR /usr/src/app
# Copy package.json and package-lock.json first to leverage Docker cache
COPY ./package*.json ./
# Install application dependencies
RUN npm install
# Copy the current directory contents into the container
COPY ./ .
COPY ./.husky .
# Make port 3000 available to the world outside this container
EXPOSE 3000
# Define environment variables if needed
# ENV NODE_ENV production
# Run the application
ENTRYPOINT npm run start
+9
View File
@@ -13,6 +13,10 @@ RUN npm install
# Copy the current directory contents into the container # Copy the current directory contents into the container
COPY apps/OpenSign/ . COPY apps/OpenSign/ .
COPY apps/OpenSign/.husky . COPY apps/OpenSign/.husky .
COPY apps/OpenSign/entrypoint.sh .
# make the entrypoint.sh file executable
RUN chmod +x entrypoint.sh
# Define environment variables if needed # Define environment variables if needed
ENV NODE_ENV=production ENV NODE_ENV=production
@@ -20,8 +24,13 @@ ENV GENERATE_SOURCEMAP=false
# build # build
RUN npm run build RUN npm run build
# Inject env.js loader into index.html
RUN sed -i '/<head>/a\<script src="/env.js"></script>' build/index.html
# Make port 3000 available to the world outside this container # Make port 3000 available to the world outside this container
EXPOSE 3000 EXPOSE 3000
ENTRYPOINT ["./entrypoint.sh"]
# Run the application # Run the application
CMD ["npm", "start"] CMD ["npm", "start"]
+29
View File
@@ -0,0 +1,29 @@
#!/bin/sh
ENV_FILE=./build/env.js
DOTENV_FILE=./.env.prod # ✅ use .env.prod
echo "Generating runtime env file at $ENV_FILE..."
echo "window.RUNTIME_ENV = {" > $ENV_FILE
# List of keys to include
RUNTIME_KEYS="REACT_APP_SERVERURL"
for key in $RUNTIME_KEYS; do
# First check docker env (-e), fallback to .env file
value=$(printenv "$key")
if [ -z "$value" ] && [ -f "$DOTENV_FILE" ]; then
# fallback: read from .env
value=$(grep "^$key=" "$DOTENV_FILE" | cut -d '=' -f2- | tr -d '\r\n' | sed 's/"/\\"/g')
else
value=$(echo "$value" | sed 's/"/\\"/g')
fi
echo " $key: \"$value\"," >> $ENV_FILE
done
echo "};" >> $ENV_FILE
exec "$@"
@@ -1,6 +1,7 @@
{ {
"header-news": "Neue Funktion: Benutzer des Teams-Plans können jetzt ihre eigenen AWS S3-Buckets für die Dateispeicherung integrieren", "header-news": "Neue Funktion: Benutzer des Teams-Plans können jetzt ihre eigenen AWS S3-Buckets für die Dateispeicherung integrieren",
"header-news-btn": "Jetzt einrichten", "header-news-btn": "Jetzt einrichten",
"sandbox-news": "Dies ist eine Sandbox-Umgebung. Bitte nicht für produktive Zwecke verwenden.",
"create-account": "Konto erstellen", "create-account": "Konto erstellen",
"login": "Anmelden", "login": "Anmelden",
"language": "Sprache", "language": "Sprache",
@@ -675,7 +676,7 @@
"public-template-mssg-1": "Um OpenSign in Ihr React- oder Next.js-Projekt zu integrieren, führen Sie einfach den folgenden Befehl aus:", "public-template-mssg-1": "Um OpenSign in Ihr React- oder Next.js-Projekt zu integrieren, führen Sie einfach den folgenden Befehl aus:",
"public-template-mssg-2": "Stellen Sie sicher, dass npm oder yarn in Ihrem Projekt eingerichtet ist. Wenn Sie Yarn verwenden, können Sie npm install durch yarn add @opensign/react ersetzen.", "public-template-mssg-2": "Stellen Sie sicher, dass npm oder yarn in Ihrem Projekt eingerichtet ist. Wenn Sie Yarn verwenden, können Sie npm install durch yarn add @opensign/react ersetzen.",
"public-template-mssg-3": "Benötigen Sie weitere Details oder Beispiele?", "public-template-mssg-3": "Benötigen Sie weitere Details oder Beispiele?",
"public-template-mssg-4": "Besuchen Sie die", "public-template-mssg-4": "Besuchen Sie die ",
"public-template-mssg-5": " npm für die neuesten Updates, detaillierte Dokumentationen und Versionshistorie.", "public-template-mssg-5": " npm für die neuesten Updates, detaillierte Dokumentationen und Versionshistorie.",
"public-template-mssg-6": "Bevor Sie diesen Code-Schnipsel verwenden können, müssen Sie diese Vorlage öffentlich machen.", "public-template-mssg-6": "Bevor Sie diesen Code-Schnipsel verwenden können, müssen Sie diese Vorlage öffentlich machen.",
"public-template-mssg-7": "Bevor Sie einen öffentlichen Link generieren können, müssen Sie diese Vorlage öffentlich machen.", "public-template-mssg-7": "Bevor Sie einen öffentlichen Link generieren können, müssen Sie diese Vorlage öffentlich machen.",
@@ -1,6 +1,7 @@
{ {
"header-news": "New feature: Protect your account with Two-Factor Authentication (2FA) and enjoy the future of login with Passkeys — no passwords needed.", "header-news": "New feature: Protect your account with Two-Factor Authentication (2FA) and enjoy the future of login with Passkeys — no passwords needed.",
"header-news-btn": "Setup now", "header-news-btn": "Setup now",
"sandbox-news": "This is a sandbox environment. Please do not use it for production purposes.",
"create-account": "Create account", "create-account": "Create account",
"login": "Login", "login": "Login",
"language": "Language", "language": "Language",
@@ -675,7 +676,7 @@
"public-template-mssg-1": "To integrate OpenSign into your React or Next.js project, simply run the following command:", "public-template-mssg-1": "To integrate OpenSign into your React or Next.js project, simply run the following command:",
"public-template-mssg-2": "Ensure you have npm or yarn set up in your project. If you're using Yarn, you can replace npm install with yarn add @opensign/react.", "public-template-mssg-2": "Ensure you have npm or yarn set up in your project. If you're using Yarn, you can replace npm install with yarn add @opensign/react.",
"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": "Before you can use this code snippet, you must make this template public.", "public-template-mssg-6": "Before you can use this code snippet, you must make this template public.",
"public-template-mssg-7": "Before you can generate a public link you must make this template public.", "public-template-mssg-7": "Before you can generate a public link you must make this template public.",
@@ -1,6 +1,7 @@
{ {
"header-news": "Nueva característica: los usuarios del plan Teams ahora pueden integrar sus propios depósitos de AWS S3 para el almacenamiento de archivos", "header-news": "Nueva característica: los usuarios del plan Teams ahora pueden integrar sus propios depósitos de AWS S3 para el almacenamiento de archivos",
"header-news-btn": "Configurar ahora", "header-news-btn": "Configurar ahora",
"sandbox-news": "Este es un entorno sandbox. Por favor, no lo utilice con fines de producción.",
"create-account": "Crear cuenta", "create-account": "Crear cuenta",
"login": "Iniciar sesión", "login": "Iniciar sesión",
"language": "Idioma", "language": "Idioma",
@@ -675,7 +676,7 @@
"public-template-mssg-1": "Para integrar OpenSign a tu proyecto React o Next.js, simplemente ejecuta los siguientes comandos:", "public-template-mssg-1": "Para integrar OpenSign a tu proyecto React o Next.js, simplemente ejecuta los siguientes comandos:",
"public-template-mssg-2": "Asegúrate de tener «npm» o «yarn» configurado en tu proyecto. Si estás usando «yarn», puedes reemplazar «npm install» con «yarn add @opensign/react».", "public-template-mssg-2": "Asegúrate de tener «npm» o «yarn» configurado en tu proyecto. Si estás usando «yarn», puedes reemplazar «npm install» con «yarn add @opensign/react».",
"public-template-mssg-3": "¿Necesitas más detalles o ejemplos?", "public-template-mssg-3": "¿Necesitas más detalles o ejemplos?",
"public-template-mssg-4": "Visita la", "public-template-mssg-4": "Visita la ",
"public-template-mssg-5": " «npm» para las últimas actualizaciones, documentación detallada e historial de versiones.", "public-template-mssg-5": " «npm» para las últimas actualizaciones, documentación detallada e historial de versiones.",
"public-template-mssg-6": "Antes de que puedas usar este fragmento de código, debes convertir esta plantilla en pública.", "public-template-mssg-6": "Antes de que puedas usar este fragmento de código, debes convertir esta plantilla en pública.",
"public-template-mssg-7": "Antes de poder generar un enlace público, debes hacer que esta plantilla sea pública.", "public-template-mssg-7": "Antes de poder generar un enlace público, debes hacer que esta plantilla sea pública.",
@@ -1,6 +1,7 @@
{ {
"header-news": "Nouvelle fonctionnalité : les utilisateurs du forfait Teams peuvent désormais intégrer leurs propres compartiments AWS S3 pour le stockage de fichiers", "header-news": "Nouvelle fonctionnalité : les utilisateurs du forfait Teams peuvent désormais intégrer leurs propres compartiments AWS S3 pour le stockage de fichiers",
"header-news-btn": "Configurer maintenant", "header-news-btn": "Configurer maintenant",
"sandbox-news": "Ceci est un environnement sandbox. Veuillez ne pas l'utiliser à des fins de production.",
"create-account": "Créer un compte", "create-account": "Créer un compte",
"login": "Se Connecter", "login": "Se Connecter",
"language": "Langue", "language": "Langue",
@@ -675,7 +676,7 @@
"public-template-mssg-1": "Pour intégrer OpenSign dans votre projet React ou Next.js, exécutez simplement la commande suivante :", "public-template-mssg-1": "Pour intégrer OpenSign dans votre projet React ou Next.js, exécutez simplement la commande suivante :",
"public-template-mssg-2": "Assurez-vous que npm ou Yarn est configuré dans votre projet. Si vous utilisez Yarn, vous pouvez remplacer npm install par Yarn Add @opensign/react.", "public-template-mssg-2": "Assurez-vous que npm ou Yarn est configuré dans votre projet. Si vous utilisez Yarn, vous pouvez remplacer npm install par Yarn Add @opensign/react.",
"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": "Avant de pouvoir utiliser cet extrait de code, vous devez rendre ce modèle public.", "public-template-mssg-6": "Avant de pouvoir utiliser cet extrait de code, vous devez rendre ce modèle public.",
"public-template-mssg-7": "Avant de pouvoir générer un lien public, vous devez rendre ce modèle public.", "public-template-mssg-7": "Avant de pouvoir générer un lien public, vous devez rendre ce modèle public.",
@@ -1,6 +1,7 @@
{ {
"header-news": "Nuova funzionalità: Gli utenti del piano Teams possono ora integrare i propri bucket AWS S3 per l'archiviazione dei file", "header-news": "Nuova funzionalità: Gli utenti del piano Teams possono ora integrare i propri bucket AWS S3 per l'archiviazione dei file",
"header-news-btn": "Configura Ora", "header-news-btn": "Configura Ora",
"sandbox-news": "Questo è un ambiente sandbox. Si prega di non utilizzarlo per scopi di produzione.",
"create-account": "Crea Account", "create-account": "Crea Account",
"login": "Accedi", "login": "Accedi",
"language": "Lingua", "language": "Lingua",
@@ -675,7 +676,7 @@
"public-template-mssg-1": "Per integrare OpenSign nel tuo progetto React o Next.js, esegui semplicemente il seguente comando:", "public-template-mssg-1": "Per integrare OpenSign nel tuo progetto React o Next.js, esegui semplicemente il seguente comando:",
"public-template-mssg-2": "Assicurati di avere npm o yarn configurato nel tuo progetto. Se usi Yarn, puoi sostituire npm install con yarn add @opensign/react.", "public-template-mssg-2": "Assicurati di avere npm o yarn configurato nel tuo progetto. Se usi Yarn, puoi sostituire npm install con yarn add @opensign/react.",
"public-template-mssg-3": "Hai bisogno di maggiori dettagli o esempi?", "public-template-mssg-3": "Hai bisogno di maggiori dettagli o esempi?",
"public-template-mssg-4": "Visita il", "public-template-mssg-4": "Visita il ",
"public-template-mssg-5": " npm per gli aggiornamenti più recenti, documentazione dettagliata e cronologia delle versioni.", "public-template-mssg-5": " npm per gli aggiornamenti più recenti, documentazione dettagliata e cronologia delle versioni.",
"public-template-mssg-6": "Prima di poter utilizzare questo frammento di codice, devi rendere questo modello pubblico.", "public-template-mssg-6": "Prima di poter utilizzare questo frammento di codice, devi rendere questo modello pubblico.",
"public-template-mssg-7": "Prima di poter generare un link pubblico, devi rendere questo modello pubblico.", "public-template-mssg-7": "Prima di poter generare un link pubblico, devi rendere questo modello pubblico.",
+5 -5
View File
@@ -106,10 +106,10 @@ function App() {
element={<LazyPage Page={GuestLogin} />} element={<LazyPage Page={GuestLogin} />}
/> />
<Route path="/debugpdf" element={<LazyPage Page={DebugPdf} />} /> <Route path="/debugpdf" element={<LazyPage Page={DebugPdf} />} />
<Route <Route
path="/forgetpassword" path="/forgetpassword"
element={<LazyPage Page={ForgetPassword} />} element={<LazyPage Page={ForgetPassword} />}
/> />
<Route <Route
element={ element={
<ValidateSession> <ValidateSession>
@@ -165,7 +165,7 @@ function App() {
path="/recipientSignPdf/:docId" path="/recipientSignPdf/:docId"
element={<PdfRequestFiles />} element={<PdfRequestFiles />}
/> />
<Route path="/users" element={<UserList />} /> <Route path="/users" element={<UserList />} />
<Route <Route
path="/preferences" path="/preferences"
element={<LazyPage Page={Preferences} />} element={<LazyPage Page={Preferences} />}
@@ -22,7 +22,7 @@ function DropdownWidgetOption(props) {
const resetState = () => { const resetState = () => {
setDropdownOptionList(["option-1", "option-2"]); setDropdownOptionList(["option-1", "option-2"]);
setDropdownName( props.currWidgetsDetails?.options?.name || props.type); setDropdownName(props.currWidgetsDetails?.options?.name || props.type);
setIsReadOnly(false); setIsReadOnly(false);
setIsHideLabel(false); setIsHideLabel(false);
setMinCount(0); setMinCount(0);
@@ -115,7 +115,7 @@ function DropdownWidgetOption(props) {
defaultData, defaultData,
isHideLabel isHideLabel
); );
resetState() resetState();
}; };
@@ -1,4 +1,4 @@
import React, { import {
useState, useState,
useRef, useRef,
} from "react"; } from "react";
@@ -168,34 +168,34 @@ function PlaceholderType(props) {
<div style={{ zIndex: props.isSignYourself && "99" }}> <div style={{ zIndex: props.isSignYourself && "99" }}>
{props.pos.options?.values?.map((data, ind) => { {props.pos.options?.values?.map((data, ind) => {
return ( return (
<div <div key={ind} className="select-none-cls pointer-events-none">
key={ind} <label
className="select-none-cls flex items-center text-center gap-0.5 pointer-events-none" htmlFor={`checkbox-${props.pos.key + ind}`}
> style={{ fontSize: fontSize, color: fontColor }}
<input className={`mb-0 flex items-center gap-1 ${
id={`checkbox-${props.pos.key + ind}`} ind > 0 ? "mt-[3px]" : "mt-[0px]"
style={{ width: fontSize, height: fontSize }} }`}
className={`${ >
ind === 0 ? "mt-0" : "mt-[5px]" <input
} flex justify-center op-checkbox rounded-[1px] `} id={`checkbox-${props.pos.key + ind}`}
disabled={ style={{
props.isNeedSign && width: fontSize,
(props.pos.options?.isReadOnly || height: fontSize
props.data?.signerObjId !== props.signerObjId) }}
} className="op-checkbox rounded-[1px]"
type="checkbox" disabled={
readOnly props.isNeedSign &&
checked={!!selectCheckbox(ind, selectedCheckbox)} (props.pos.options?.isReadOnly ||
/> props.data?.signerObjId !== props.signerObjId)
{!props.pos.options?.isHideLabel && ( }
<label type="checkbox"
htmlFor={`checkbox-${props.pos.key + ind}`} readOnly
style={{ fontSize: fontSize, color: fontColor }} checked={!!selectCheckbox(ind, selectedCheckbox)}
className="text-xs mb-0 text-center" />
> {!props.pos.options?.isHideLabel && (
{data} <span className="leading-none">{data}</span>
</label> )}
)} </label>
</div> </div>
); );
})} })}
@@ -243,7 +243,6 @@ function PlaceholderType(props) {
<i className="fa-light fa-circle-chevron-down mr-1 "></i> <i className="fa-light fa-circle-chevron-down mr-1 "></i>
</div> </div>
); );
case "initials": case "initials":
return props.pos.SignUrl ? ( return props.pos.SignUrl ? (
<img <img
@@ -444,36 +443,40 @@ function PlaceholderType(props) {
return ( return (
<div <div
key={ind} key={ind}
className="select-none-cls flex items-center text-center gap-0.5 pointer-events-none" className="select-none-cls pointer-events-none"
> >
<input <label
readOnly htmlFor={`radio-${props.pos.key + ind}`}
id={`radio-${props.pos.key + ind}`}
style={{ style={{
width: fontSize, fontSize: fontSize,
height: fontSize, color: fontColor,
marginTop: ind > 0 ? "10px" : "0px" marginTop: ind > 0 ? "5px" : "0px"
}} }}
className={`op-radio rounded-full border- border-black appearance-none bg-white inline-block align-middle relative ${ className="text-xs mb-0 flex items-center gap-1 "
handleRadioCheck(data) ? "checked-radio" : "" >
}`} <input
type="radio" readOnly
disabled={ id={`radio-${props.pos.key + ind}`}
props.isNeedSign && style={{
(props.pos.options?.isReadOnly || width: fontSize,
props.data?.signerObjId !== props.signerObjId) height: fontSize,
} lineHeight: 2
checked={handleRadioCheck(data)} }}
/> className={`op-radio rounded-full border- border-black appearance-none bg-white inline-block align-middle relative ${
{!props.pos.options?.isHideLabel && ( handleRadioCheck(data) ? "checked-radio" : ""
<label }`}
htmlFor={`radio-${props.pos.key + ind}`} type="radio"
style={{ fontSize: fontSize, color: fontColor }} disabled={
className="text-xs mb-0" props.isNeedSign &&
> (props.pos.options?.isReadOnly ||
{data} props.data?.signerObjId !== props.signerObjId)
</label> }
)} checked={handleRadioCheck(data)}
/>
{!props.pos.options?.isHideLabel && (
<span className="leading-none">{data}</span>
)}
</label>
</div> </div>
); );
})} })}
@@ -231,7 +231,9 @@ function WidgetsValueModal(props) {
setXyPosition, setXyPosition,
uniqueId, uniqueId,
false, false,
data?.format data?.format,
currWidgetsDetails?.options?.fontSize || 12,
currWidgetsDetails?.options?.fontColor || "black"
); );
setSelectDate({ date: date, format: data?.format }); setSelectDate({ date: date, format: data?.format });
}; };
@@ -1327,47 +1329,42 @@ function WidgetsValueModal(props) {
<div className="border-[1px] border-gray-300 rounded-[2px] p-1 px-3"> <div className="border-[1px] border-gray-300 rounded-[2px] p-1 px-3">
{currWidgetsDetails?.options?.values?.map((data, ind) => { {currWidgetsDetails?.options?.values?.map((data, ind) => {
return ( return (
<div <div key={ind} className=" select-none-cls">
key={ind} <label
className=" select-none-cls flex items-center text-center gap-0.5" htmlFor={`checkbox-${currWidgetsDetails?.key + ind}`}
> className="text-xs flex items-center gap-1"
<input >
id={`checkbox-${currWidgetsDetails?.key + ind}`} <input
className={`${ id={`checkbox-${currWidgetsDetails?.key + ind}`}
ind === 0 ? "mt-0" : "mt-[5px]" className={`${
} op-checkbox op-checkbox-sm rounded-[1px] `} ind === 0 ? "mt-0" : "mt-[5px]"
type="checkbox" } op-checkbox op-checkbox-xs rounded-[1px] `}
checked={!!selectCheckbox(ind, selectedCheckbox)} type="checkbox"
onChange={(e) => { checked={!!selectCheckbox(ind, selectedCheckbox)}
if (e.target.checked) { onChange={(e) => {
const maxRequired = if (e.target.checked) {
currWidgetsDetails?.options?.validation const maxRequired =
?.maxRequiredCount; currWidgetsDetails?.options?.validation
const maxCountInt = ?.maxRequiredCount;
maxRequired && parseInt(maxRequired); const maxCountInt =
if (maxCountInt > 0) { maxRequired && parseInt(maxRequired);
if ( if (maxCountInt > 0) {
selectedCheckbox && if (
selectedCheckbox?.length <= maxCountInt - 1 selectedCheckbox &&
) { selectedCheckbox?.length <= maxCountInt - 1
) {
handleCheckboxValue(e.target.checked, ind);
}
} else {
handleCheckboxValue(e.target.checked, ind); handleCheckboxValue(e.target.checked, ind);
} }
} else { } else {
handleCheckboxValue(e.target.checked, ind); handleCheckboxValue(e.target.checked, ind);
} }
} else { }}
handleCheckboxValue(e.target.checked, ind); />
} {data}
}} </label>
/>
{!currWidgetsDetails?.options?.isHideLabel && (
<label
htmlFor={`checkbox-${currWidgetsDetails?.key + ind}`}
className="text-xs mb-0 text-center"
>
{data}
</label>
)}
</div> </div>
); );
})} })}
@@ -1515,32 +1512,23 @@ function WidgetsValueModal(props) {
<div className="border-[1px] border-gray-300 rounded-[2px] p-1 px-3"> <div className="border-[1px] border-gray-300 rounded-[2px] p-1 px-3">
{currWidgetsDetails?.options?.values.map((data, ind) => { {currWidgetsDetails?.options?.values.map((data, ind) => {
return ( return (
<div <div key={ind} className="select-none-cls">
key={ind} <label
className="select-none-cls flex items-center text-center gap-0.5" htmlFor={`radio-${currWidgetsDetails?.key + ind}`}
> className="cursor-pointer flex items-center text-sm gap-1"
<input >
id={`radio-${currWidgetsDetails?.key + ind}`} <input
style={{ id={`radio-${currWidgetsDetails?.key + ind}`}
marginTop: ind > 0 ? "10px" : "0px" className={`op-radio op-radio-xs`}
}} type="radio"
className={`flex justify-center op-radio`} value={data}
type="radio" checked={handleRadioCheck(data)}
value={data} onChange={(e) => {
checked={handleRadioCheck(data)} handleCheckRadio(e.target.value);
onChange={(e) => { }}
handleCheckRadio(e.target.value); />
}} {data}
/> </label>
{!currWidgetsDetails?.options?.isHideLabel && (
<label
htmlFor={`radio-${currWidgetsDetails?.key + ind}`}
// style={{ fontSize: fontSize, color: fontColor }}
className="text-xs mb-0"
>
{data}
</label>
)}
</div> </div>
); );
})} })}
@@ -1652,7 +1640,7 @@ function WidgetsValueModal(props) {
const validateExpression = (regexValidation) => { const validateExpression = (regexValidation) => {
if (widgetValue && regexValidation) { if (widgetValue && regexValidation) {
let regexObject = regexValidation; let regexObject = regexValidation;
if (props.pos?.options?.validation?.type === "regex") { if (currWidgetsDetails?.options?.validation?.type === "regex") {
regexObject = RegexParser(regexValidation); regexObject = RegexParser(regexValidation);
} }
let isValidate = regexObject.test(widgetValue); let isValidate = regexObject.test(widgetValue);
@@ -1675,7 +1663,8 @@ function WidgetsValueModal(props) {
validateExpression(regexValidation); validateExpression(regexValidation);
break; break;
default: default:
regexValidation = props.pos?.options?.validation?.pattern || ""; regexValidation =
currWidgetsDetails?.options?.validation?.pattern || "";
validateExpression(regexValidation); validateExpression(regexValidation);
break; break;
} }
@@ -2,9 +2,19 @@ import React, { useEffect, useState } from "react";
import AsyncSelect from "react-select/async"; import AsyncSelect from "react-select/async";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import axios from "axios"; import axios from "axios";
import { handleUnlinkSigner } from "../../../constant/Utils";
const SelectSigners = (props) => { const SelectSigners = (props) => {
const { t } = useTranslation(); const { t } = useTranslation();
const {
signerPos,
setSignerPos,
signersData,
setSignersData,
uniqueId,
isRemove,
handleAddUser
} = props;
const [userList, setUserList] = useState([]); const [userList, setUserList] = useState([]);
const [selected, setSelected] = useState(); const [selected, setSelected] = useState();
const [userData, setUserData] = useState({}); const [userData, setUserData] = useState({});
@@ -30,7 +40,7 @@ const SelectSigners = (props) => {
//checking if user select no signer option from dropdown //checking if user select no signer option from dropdown
if (item) { if (item) {
//checking selected signer is already assign to the document or not //checking selected signer is already assign to the document or not
const alreadyAssign = props.signersData.some( const alreadyAssign = signersData.some(
(item2) => item2.objectId === item.value (item2) => item2.objectId === item.value
); );
if (alreadyAssign) { if (alreadyAssign) {
@@ -49,7 +59,7 @@ const SelectSigners = (props) => {
}; };
const handleAdd = () => { const handleAdd = () => {
if (userData && userData.objectId) { if (userData && userData.objectId) {
props.details(userData); handleAddUser(userData);
if (props.closePopup) { if (props.closePopup) {
props.closePopup(); props.closePopup();
} }
@@ -60,7 +70,13 @@ const SelectSigners = (props) => {
}; };
//function to use remove signer from assigned widgets in create template flow //function to use remove signer from assigned widgets in create template flow
const handleRemove = () => { const handleRemove = () => {
props.handleUnlinkSigner(); handleUnlinkSigner(
signerPos,
setSignerPos,
signersData,
setSignersData,
uniqueId
);
if (props.closePopup) { if (props.closePopup) {
props.closePopup(); props.closePopup();
} }
@@ -161,7 +177,7 @@ const SelectSigners = (props) => {
<button className="op-btn op-btn-primary" onClick={() => handleAdd()}> <button className="op-btn op-btn-primary" onClick={() => handleAdd()}>
{t("submit")} {t("submit")}
</button> </button>
{props.isExistSigner && props.handleUnlinkSigner && ( {props.isExistSigner && isRemove && (
<button <button
className="op-btn op-btn-accent op-btn-outline" className="op-btn op-btn-accent op-btn-outline"
onClick={() => handleRemove()} onClick={() => handleRemove()}
+46 -22
View File
@@ -1,6 +1,5 @@
import axios from "axios"; import axios from "axios";
import moment from "moment"; import moment from "moment";
import React from "react";
import { PDFDocument, rgb, degrees } from "pdf-lib"; import { PDFDocument, rgb, degrees } from "pdf-lib";
import Parse from "parse"; import Parse from "parse";
import { appInfo } from "./appinfo"; import { appInfo } from "./appinfo";
@@ -21,7 +20,9 @@ export const isTabAndMobile = window.innerWidth < 1023;
export const textInputWidget = "text input"; export const textInputWidget = "text input";
export const textWidget = "text"; export const textWidget = "text";
export const radioButtonWidget = "radio button"; export const radioButtonWidget = "radio button";
export function getEnv() {
return window?.RUNTIME_ENV || {};
}
//function for create list of year for date widget //function for create list of year for date widget
export const range = (start, end, step) => { export const range = (start, end, step) => {
@@ -1665,10 +1666,11 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
].includes(position.type); ].includes(position.type);
if (position.type === "checkbox") { if (position.type === "checkbox") {
let checkboxGapFromTop, isCheck; let checkboxGapFromTop, isCheck;
let y = yPos(position); let y = yPos(position) + 2;
const optionsFontSize = fontSize || 13; //calculate checkbox size to draw on pdf
const checkboxSize = fontSize; const checkboxSize = fontSize - 1;
const checkboxTextGapFromLeft = fontSize + 5 || 22; //calculate gap between checkbox and options
const checkboxTextGapFromLeft = fontSize + 5;
if (position?.options?.values.length > 0) { if (position?.options?.values.length > 0) {
position?.options?.values.forEach((item, ind) => { position?.options?.values.forEach((item, ind) => {
const checkboxRandomId = "checkbox" + randomId(); const checkboxRandomId = "checkbox" + randomId();
@@ -1680,13 +1682,11 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
} else if (position?.options?.defaultValue) { } else if (position?.options?.defaultValue) {
isCheck = position?.options?.defaultValue?.includes(ind); isCheck = position?.options?.defaultValue?.includes(ind);
} }
const checkbox = form.createCheckBox(checkboxRandomId); const checkbox = form.createCheckBox(checkboxRandomId);
if (ind > 0) { if (ind > 0) {
y = y + checkboxGapFromTop; y = y + checkboxGapFromTop;
} else { } else {
checkboxGapFromTop = fontSize + 5 || 26; checkboxGapFromTop = fontSize + 3.2;
} }
if (!position?.options?.isHideLabel) { if (!position?.options?.isHideLabel) {
@@ -1694,10 +1694,10 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
const optionsPosition = compensateRotation( const optionsPosition = compensateRotation(
page.getRotation().angle, page.getRotation().angle,
xPos(position) + checkboxTextGapFromLeft, xPos(position) + checkboxTextGapFromLeft,
y, y - 3,
1, 1,
page.getSize(), page.getSize(),
optionsFontSize, fontSize,
updateColorInRgb, updateColorInRgb,
font, font,
page page
@@ -1780,7 +1780,7 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
: NewbreakTextIntoLines(textContent, fixedWidth); : NewbreakTextIntoLines(textContent, fixedWidth);
// Set initial y-coordinate for the first line // Set initial y-coordinate for the first line
let x = xPos(position); let x = xPos(position);
let y = yPos(position); let y = yPos(position) - 4;
// Embed each line on the page // Embed each line on the page
for (const line of lines) { for (const line of lines) {
const textPosition = compensateRotation( const textPosition = compensateRotation(
@@ -1830,28 +1830,33 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
} else if (position.type === radioButtonWidget) { } else if (position.type === radioButtonWidget) {
const radioRandomId = "radio" + randomId(); const radioRandomId = "radio" + randomId();
const radioGroup = form.createRadioGroup(radioRandomId); const radioGroup = form.createRadioGroup(radioRandomId);
let radioOptionGapFromTop; //draw radio button on document and options if hide label is enable
const optionsFontSize = fontSize || 13; let radioButtonFromTop;
const radioTextGapFromLeft = fontSize + 5 || 20; //getting radio buttons options text font size
const optionsFontSize = fontSize;
//calculate value of gap between radio button and options
const radioTextGapFromLeft = fontSize + 6;
//getting radio button font size
const radioSize = fontSize; const radioSize = fontSize;
//getting position of radio widget in y direction
let y = yPos(position); let y = yPos(position);
//on the basic of option's length create radio button and message
if (position?.options?.values.length > 0) { if (position?.options?.values.length > 0) {
position?.options?.values.forEach((item, ind) => { position?.options?.values.forEach((item, ind) => {
if (ind > 0) { if (ind > 0) {
y = y + radioOptionGapFromTop; y = y + radioButtonFromTop;
} else { } else {
radioOptionGapFromTop = fontSize + 10 || 25; radioButtonFromTop = fontSize + 6;
} }
if (!position?.options?.isHideLabel) { if (!position?.options?.isHideLabel) {
// below line of code is used to embed label with radio button in pdf // below line of code is used to embed label with radio button in pdf
const optionsPosition = compensateRotation( const optionsPosition = compensateRotation(
page.getRotation().angle, page.getRotation().angle,
xPos(position) + radioTextGapFromLeft, xPos(position) + radioTextGapFromLeft,
y, y - 2,
1, 1,
page.getSize(), page.getSize(),
optionsFontSize, fontSize,
updateColorInRgb, updateColorInRgb,
font, font,
page page
@@ -1860,7 +1865,7 @@ export const multiSignEmbed = async (widgets, pdfDoc, signyourself, scale) => {
page.drawText(item, optionsPosition); page.drawText(item, optionsPosition);
} }
let radioObj = { let radioObj = {
x: xPos(position), x: xPos(position) + 2,
y: y, y: y,
width: radioSize, width: radioSize,
height: radioSize height: radioSize
@@ -3066,7 +3071,7 @@ export const mailTemplate = (param) => {
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Note</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'>Note</td><td></td><td style='color:#626363;font-weight:bold'>" +
param.note + param.note +
"</td></tr><tr><td></td><td></td></tr></table></div> <div style='margin-left:70px'><a target=_blank href=" + "</td></tr><tr><td></td><td></td></tr></table></div> <div style='margin-left:70px'><a target=_blank href=" +
param.sigingUrl + param.signingUrl +
"><button style='padding:12px;background-color:#d46b0f;color:white;border:0px;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 " + "><button style='padding:12px;background-color:#d46b0f;color:white;border:0px;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 " +
appName + appName +
". For any queries regarding this email, please contact the sender " + ". For any queries regarding this email, please contact the sender " +
@@ -3161,3 +3166,22 @@ export const checkRegularExpress = (validateType, setValidatePlaceholder) => {
setValidatePlaceholder("please enter value"); setValidatePlaceholder("please enter value");
} }
}; };
//function to use unlink signer from widgets
export const handleUnlinkSigner = (signerPos,setSignerPos,signersdata,setSignersData,uniqueId) => {
//remove existing signer's details from 'signerPos' array
const updatePlaceHolder = signerPos.map((x) => {
if (x.Id === uniqueId) {
return { ...x, signerPtr: {}, signerObjId: "" };
}
return { ...x };
});
setSignerPos(updatePlaceHolder);
//remove existing signer's details from 'signersdata' array and keep role and id
const updateSigner = signersdata.map((item) => {
if (item.Id == uniqueId) {
return { Role: item.Role, Id: item.Id, blockColor: item.blockColor };
}
return item;
});
setSignersData(updateSigner);
};
+6 -3
View File
@@ -1,9 +1,12 @@
import logo from "../assets/images/logo.png"; import logo from "../assets/images/logo.png";
import { getEnv } from "./Utils";
export function serverUrl_fn() { export function serverUrl_fn() {
let baseUrl = process.env.REACT_APP_SERVERURL const env = getEnv();
? process.env.REACT_APP_SERVERURL const serverurl = env?.REACT_APP_SERVERURL
: window.location.origin + "/api/app"; ? env.REACT_APP_SERVERURL // env.REACT_APP_SERVERURL is used for prod
: process.env.REACT_APP_SERVERURL; // process.env.REACT_APP_SERVERURL is used for dev (locally)
let baseUrl = serverurl ? serverurl : window.location.origin + "/api/app";
return baseUrl; return baseUrl;
} }
export const appInfo = { export const appInfo = {
+12 -9
View File
@@ -1,3 +1,13 @@
const userssetting = [
{
icon: "fa-light fa-users fa-fw",
title: "Users",
target: "_self",
pageType: "",
description: "",
objectId: "users"
}
];
export const subSetting = [ export const subSetting = [
{ {
icon: "fa-light fa-sliders", icon: "fa-light fa-sliders",
@@ -7,14 +17,7 @@ export const subSetting = [
description: "", description: "",
objectId: "preferences" objectId: "preferences"
}, },
{ ...userssetting
icon: "fa-light fa-users fa-fw",
title: "Users",
target: "_self",
pageType: "",
description: "",
objectId: "users"
}
]; ];
const sidebarList = [ const sidebarList = [
@@ -65,7 +68,7 @@ const sidebarList = [
pageType: "report", pageType: "report",
description: "", description: "",
objectId: "6TeaPr321t" objectId: "6TeaPr321t"
}, }
] ]
}, },
{ {
+24 -23
View File
@@ -68,6 +68,7 @@ function Login() {
setState({ ...state, loading: false, alertType: type, alertMsg: msg }); setState({ ...state, loading: false, alertType: type, alertMsg: msg });
setTimeout(() => setState({ ...state, alertMsg: "" }), 2000); setTimeout(() => setState({ ...state, alertMsg: "" }), 2000);
}; };
const checkUserExt = async () => { const checkUserExt = async () => {
const app = await getAppLogo(); const app = await getAppLogo();
if (app?.error === "invalid_json") { if (app?.error === "invalid_json") {
@@ -82,11 +83,11 @@ function Login() {
} else { } else {
setImage(appInfo?.applogo || undefined); setImage(appInfo?.applogo || undefined);
} }
dispatch(fetchAppInfo());
if (localStorage.getItem("accesstoken")) { if (localStorage.getItem("accesstoken")) {
setState({ ...state, loading: true }); setState({ ...state, loading: true });
GetLoginData(); GetLoginData();
} }
dispatch(fetchAppInfo());
}; };
const handleChange = (event) => { const handleChange = (event) => {
let { name, value } = event.target; let { name, value } = event.target;
@@ -96,20 +97,15 @@ function Login() {
setState({ ...state, [name]: value }); setState({ ...state, [name]: value });
}; };
const handleSubmit = async (event) => { const handleLogin = async (
localStorage.removeItem("accesstoken"); ) => {
event.preventDefault(); const email = state?.email
const password = state?.password
if (!emailRegex.test(state.email)) {
alert("Please enter a valid email address.");
return;
}
const { email, password } = state;
if (!email || !password) { if (!email || !password) {
return; return;
} }
localStorage.removeItem("accesstoken");
try { try {
setState({ ...state, loading: true }); setState({ ...state, loading: true });
localStorage.setItem("appLogo", appInfo.applogo); localStorage.setItem("appLogo", appInfo.applogo);
@@ -132,6 +128,14 @@ function Login() {
showToast("danger", "Invalid username/password or region"); showToast("danger", "Invalid username/password or region");
} }
}; };
const handleLoginBtn = async (event) => {
event.preventDefault();
if (!emailRegex.test(state.email)) {
alert("Please enter a valid email address.");
return;
}
await handleLogin();
};
const setThirdpartyLoader = (value) => { const setThirdpartyLoader = (value) => {
setState({ ...state, thirdpartyLoader: value }); setState({ ...state, thirdpartyLoader: value });
@@ -275,7 +279,6 @@ function Login() {
const userInformation = JSON.parse( const userInformation = JSON.parse(
localStorage.getItem("UserInformation") localStorage.getItem("UserInformation")
); );
// console.log("payload ", payload);
if (payload && payload.sessionToken) { if (payload && payload.sessionToken) {
const params = { const params = {
userDetails: { userDetails: {
@@ -289,7 +292,6 @@ function Login() {
} }
}; };
const userSignUp = await Parse.Cloud.run("usersignup", params); const userSignUp = await Parse.Cloud.run("usersignup", params);
// console.log("userSignUp ", userSignUp);
if (userSignUp && userSignUp.sessionToken) { if (userSignUp && userSignUp.sessionToken) {
const LocalUserDetails = { const LocalUserDetails = {
name: userInformation.name, name: userInformation.name,
@@ -430,7 +432,7 @@ function Login() {
</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> <div>
<form onSubmit={handleSubmit} aria-label="Login Form"> <form onSubmit={handleLoginBtn} aria-label="Login Form">
<h1 className="text-[30px] mt-6">{t("welcome")}</h1> <h1 className="text-[30px] mt-6">{t("welcome")}</h1>
<fieldset> <fieldset>
<legend className="text-[12px] text-[#878787]"> <legend className="text-[12px] text-[#878787]">
@@ -488,15 +490,14 @@ function Login() {
)} )}
</span> </span>
</div> </div>
<div className="relative mt-1">
<div className="relative mt-1"> <NavLink
<NavLink to="/forgetpassword"
to="/forgetpassword" className="text-[13px] op-link op-link-primary underline-offset-1 focus:outline-none ml-1"
className="text-[13px] op-link op-link-primary underline-offset-1 focus:outline-none ml-1" >
> {t("forgot-password")}
{t("forgot-password")} </NavLink>
</NavLink> </div>
</div>
</div> </div>
</fieldset> </fieldset>
<div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-center text-xs font-bold mt-2"> <div className="grid grid-cols-1 md:grid-cols-2 gap-2 text-center text-xs font-bold mt-2">
+4 -4
View File
@@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect } from "react"; import { useState, useRef, useEffect } from "react";
import { PDFDocument } from "pdf-lib"; import { PDFDocument } from "pdf-lib";
import "../styles/signature.css"; import "../styles/signature.css";
import Parse from "parse"; import Parse from "parse";
@@ -916,7 +916,7 @@ function PdfRequestFiles(
const htmlReqBody = const htmlReqBody =
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" + "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8' /></head><body>" +
replacedRequestBody + replacedRequestBody +
"</body> </html>"; "</body></html>";
const variables = { const variables = {
document_title: documentName, document_title: documentName,
@@ -929,7 +929,7 @@ function PdfRequestFiles(
receiver_phone: user?.Phone || "", receiver_phone: user?.Phone || "",
expiry_date: localExpireDate, expiry_date: localExpireDate,
company_name: orgName, company_name: orgName,
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>` signing_url: signPdf
}; };
replaceVar = replaceMailVaribles( replaceVar = replaceMailVaribles(
requestSubject, requestSubject,
@@ -944,7 +944,7 @@ function PdfRequestFiles(
title: documentName, title: documentName,
organization: orgName, organization: orgName,
localExpireDate: localExpireDate, localExpireDate: localExpireDate,
sigingUrl: signPdf signingUrl: signPdf
}; };
let params = { let params = {
replyto: senderEmail || "", replyto: senderEmail || "",
+3 -3
View File
@@ -1220,7 +1220,7 @@ function PlaceHolderSign() {
receiver_phone: signerMail[i]?.Phone || "", receiver_phone: signerMail[i]?.Phone || "",
expiry_date: localExpireDate, expiry_date: localExpireDate,
company_name: orgName, company_name: orgName,
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>` signing_url: signPdf
}; };
replaceVar = replaceMailVaribles( replaceVar = replaceMailVaribles(
requestSubject, requestSubject,
@@ -1249,7 +1249,7 @@ function PlaceHolderSign() {
receiver_phone: signerMail[i]?.Phone || "", receiver_phone: signerMail[i]?.Phone || "",
expiry_date: localExpireDate, expiry_date: localExpireDate,
company_name: orgName, company_name: orgName,
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>` signing_url: signPdf
}; };
replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables); replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables);
} }
@@ -1260,7 +1260,7 @@ function PlaceHolderSign() {
title: documentName, title: documentName,
organization: orgName, organization: orgName,
localExpireDate: localExpireDate, localExpireDate: localExpireDate,
sigingUrl: signPdf signingUrl: signPdf
}; };
let params = { let params = {
extUserId: owner?.objectId, extUserId: owner?.objectId,
+1 -1
View File
@@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect } from "react"; import { useState, useRef, useEffect } from "react";
import { PDFDocument } from "pdf-lib"; import { PDFDocument } from "pdf-lib";
import "../styles/signature.css"; import "../styles/signature.css";
import Parse from "parse"; import Parse from "parse";
@@ -1149,25 +1149,6 @@ const TemplatePlaceholder = () => {
const handleLinkUser = (id) => { const handleLinkUser = (id) => {
setIsAddUser({ [id]: true }); setIsAddUser({ [id]: true });
}; };
//function to use unlink signer from widgets
const handleUnlinkSigner = () => {
//remove existing signer's details from 'signerPos' array
const updatePlaceHolder = signerPos.map((x) => {
if (x.Id === uniqueId) {
return { ...x, signerPtr: {}, signerObjId: "" };
}
return { ...x };
});
setSignerPos(updatePlaceHolder);
//remove existing signer's details from 'signersdata' array and keep role and id
const updateSigner = signersdata.map((item) => {
if (item.Id == uniqueId) {
return { Role: item.Role, Id: item.Id, blockColor: item.blockColor };
}
return item;
});
setSignersData(updateSigner);
};
// `handleAddUser` is used to adduser // `handleAddUser` is used to adduser
const handleAddUser = (data) => { const handleAddUser = (data) => {
const signerPtr = { const signerPtr = {
@@ -1950,7 +1931,9 @@ const TemplatePlaceholder = () => {
closePopup={closePopup} closePopup={closePopup}
signersData={signersdata} signersData={signersdata}
signerPos={signerPos} signerPos={signerPos}
handleUnlinkSigner={handleUnlinkSigner} setSignerPos={setSignerPos}
setSignersData={setSignersData}
isRemove={true}
/> />
)} )}
</div> </div>
@@ -679,7 +679,7 @@ const ReportTable = (props) => {
receiver_phone: userDetails?.Phone || "", receiver_phone: userDetails?.Phone || "",
expiry_date: localExpireDate, expiry_date: localExpireDate,
company_name: doc.ExtUserPtr.Company, company_name: doc.ExtUserPtr.Company,
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>` signing_url: signPdf
}; };
const res = replaceMailVaribles(subject, "", variables); const res = replaceMailVaribles(subject, "", variables);
setMail((prev) => ({ ...prev, subject: res.subject })); setMail((prev) => ({ ...prev, subject: res.subject }));
@@ -710,7 +710,7 @@ const ReportTable = (props) => {
receiver_phone: userDetails?.Phone || "", receiver_phone: userDetails?.Phone || "",
expiry_date: localExpireDate, expiry_date: localExpireDate,
company_name: doc.ExtUserPtr.Company, company_name: doc.ExtUserPtr.Company,
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>` signing_url: signPdf
}; };
const res = replaceMailVaribles("", body, variables); const res = replaceMailVaribles("", body, variables);
@@ -754,7 +754,7 @@ const ReportTable = (props) => {
receiver_phone: user?.signerPtr?.Phone || "", receiver_phone: user?.signerPtr?.Phone || "",
expiry_date: localExpireDate, expiry_date: localExpireDate,
company_name: doc?.ExtUserPtr?.Company || "", company_name: doc?.ExtUserPtr?.Company || "",
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>` signing_url: signPdf
}; };
const subject = const subject =
doc?.RequestSubject || doc?.RequestSubject ||
@@ -25,12 +25,10 @@ const LinkUserModal = (props) => {
handleClose={props.closePopup} handleClose={props.closePopup}
> >
<SelectSigners <SelectSigners
details={props.handleAddUser} {...props}
closePopup={props.closePopup} closePopup={props.closePopup}
signersData={props?.signersData}
isContact={isContact} isContact={isContact}
setIsContact={setIsContact} setIsContact={setIsContact}
handleUnlinkSigner={props.handleUnlinkSigner}
isExistSigner={isExistSigner} isExistSigner={isExistSigner}
/> />
{isContact && ( {isContact && (
-27
View File
@@ -1,27 +0,0 @@
# Use an official Node runtime as the base image
FROM node:20
# Set the working directory inside the container
WORKDIR /usr/src/app
# Copy package.json and package-lock.json first to leverage Docker cache
COPY ./package*.json ./
# Install application dependencies
RUN npm install
# If you have native dependencies, you'll need extra tools. Uncomment the following line if needed.
# RUN apk add --no-cache make gcc g++ python3
# Copy the current directory contents into the container
COPY ./ .
# Make port 8080 available to the world outside this container
EXPOSE 8080
# Define environment variables if needed
# ENV NODE_ENV production
# ENV DATABASE_URL mongodb://db:27017
# Run the application
ENTRYPOINT npm start
+1 -1
View File
@@ -252,7 +252,7 @@ export const mailTemplate = param => {
"</td></tr><tr><td style='font-weight:bold;font-family:sans-serif;font-size:15px'>Note</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'>Note</td><td></td><td style='color:#626363;font-weight:bold'>" +
param.note + param.note +
"</td></tr><tr><td></td><td></td></tr></table></div> <div style='margin-left:70px'><a target=_blank href=" + "</td></tr><tr><td></td><td></td></tr></table></div> <div style='margin-left:70px'><a target=_blank href=" +
param.sigingUrl + param.signingUrl +
"><button style='padding:12px;background-color:#d46b0f;color:white;border:0px;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 " + "><button style='padding:12px;background-color:#d46b0f;color:white;border:0px;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 " +
AppName + AppName +
'. For any queries regarding this email, please contact the sender ' + '. For any queries regarding this email, please contact the sender ' +
@@ -4,9 +4,9 @@ export default async function Newsletter(request) {
const email = request.params?.email?.toLowerCase()?.replace(/\s/g, ''); const email = request.params?.email?.toLowerCase()?.replace(/\s/g, '');
const domain = request.params.domain; const domain = request.params.domain;
try { try {
const envAppId = process.env.REACT_APP_APPID || 'opensign'; const envAppId = 'opensign';
const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': envAppId }; const headers = { 'Content-Type': 'application/json', 'X-Parse-Application-Id': envAppId };
const envProdServer = process.env.REACT_APP_SERVERURL || 'https://app.opensignlabs.com/api/app'; const envProdServer = 'https://app.opensignlabs.com/api/app';
const newsletter = await axios.post( const newsletter = await axios.post(
`${envProdServer}/classes/Newsletter`, `${envProdServer}/classes/Newsletter`,
{ Name: name, Email: email, Domain: domain }, { Name: name, Email: email, Domain: domain },
@@ -14,7 +14,7 @@ async function deductcount(docsCount, extUserId) {
} }
async function sendMail(document, publicUrl) { async function sendMail(document, publicUrl) {
//sessionToken //sessionToken
const baseUrl = new URL(publicUrl); //process.env.PUBLIC_URL const baseUrl = new URL(publicUrl);
// console.log("pdfDetails", pdfDetails); // console.log("pdfDetails", pdfDetails);
const timeToCompleteDays = document?.TimeToCompleteDays || 15; const timeToCompleteDays = document?.TimeToCompleteDays || 15;
@@ -71,7 +71,7 @@ async function sendMail(document, publicUrl) {
receiver_phone: existSigner?.Phone || '', receiver_phone: existSigner?.Phone || '',
expiry_date: localExpireDate, expiry_date: localExpireDate,
company_name: orgName, company_name: orgName,
signing_url: `<a href=${signPdf} target=_blank>Sign here</a>`, signing_url: signPdf,
}; };
replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables); replaceVar = replaceMailVaribles(mailSubject, htmlReqBody, variables);
} }
@@ -82,7 +82,7 @@ async function sendMail(document, publicUrl) {
title: document.Name, title: document.Name,
organization: orgName, organization: orgName,
localExpireDate: localExpireDate, localExpireDate: localExpireDate,
sigingUrl: signPdf, signingUrl: signPdf,
}; };
let params = { let params = {
extUserId: document.ExtUserPtr.objectId, extUserId: document.ExtUserPtr.objectId,
@@ -116,7 +116,7 @@ async function sendNotifyMail(doc, signUser, mailProvider, publicUrl) {
const creatorEmail = doc.ExtUserPtr.Email; const creatorEmail = doc.ExtUserPtr.Email;
const signerName = signUser.Name; const signerName = signUser.Name;
const signerEmail = signUser.Email; const signerEmail = signUser.Email;
const viewDocUrl = `${publicUrl}/recipientSignPdf/${doc.objectId}`; // ` ${process.env.PUBLIC_URL}/recipientSignPdf/${doc.objectId}`; const viewDocUrl = `${publicUrl}/recipientSignPdf/${doc.objectId}`;
const subject = `Document "${pdfName}" has been signed by ${signerName}`; const subject = `Document "${pdfName}" has been signed by ${signerName}`;
const body = const body =
"<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background-color:white'>" + "<html><head><meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/></head><body><div style='background-color:#f5f5f5;padding:20px'><div style='background-color:white'>" +
+1 -1
View File
@@ -161,7 +161,7 @@ app.use(express.urlencoded({ limit: '50mb', extended: true }));
app.use(function (req, res, next) { app.use(function (req, res, next) {
req.headers['x-real-ip'] = getUserIP(req); req.headers['x-real-ip'] = getUserIP(req);
const publicUrl = 'https://' + req?.get('host'); const publicUrl = 'https://' + req?.get('host');
req.headers['public_url'] = publicUrl; // process.env.PUBLIC_URL req.headers['public_url'] = publicUrl;
next(); next();
}); });
function getUserIP(request) { function getUserIP(request) {
+2 -2
View File
@@ -1,12 +1,12 @@
{ {
"name": "open_sign_server", "name": "open_sign_server",
"version": "1.4.0", "version": "2.21.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "open_sign_server", "name": "open_sign_server",
"version": "1.4.0", "version": "2.21.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@aws-sdk/client-s3": "^3.812.0", "@aws-sdk/client-s3": "^3.812.0",