diff --git a/apps/OpenSign/public/locales/en/translation.json b/apps/OpenSign/public/locales/en/translation.json index 461ce6af7..0f544addd 100644 --- a/apps/OpenSign/public/locales/en/translation.json +++ b/apps/OpenSign/public/locales/en/translation.json @@ -673,6 +673,7 @@ "server-down": "Unable to connect to the OpenSign server. If you are self-hosting OpenSign, please ensure that all the steps in the documentation have been followed correctly. If you're running OpenSign locally, you might be accessing it through an incorrect port number.", "admin-exists": "Admin already exists. Please login to the application using admin credentials in order to manage users.", "public-tour-message":"The template needs to be public before you can generate a shareable link.", - "add-user-template": "You need to add a role before you can add fields for it." + "add-user-template": "You need to add a role before you can add fields for it.", + "pdf-uncompatible": "This pdf is not compatible with opensign, please contact " } diff --git a/apps/OpenSign/public/locales/es/translation.json b/apps/OpenSign/public/locales/es/translation.json index 02365d194..2ea7c7c4c 100644 --- a/apps/OpenSign/public/locales/es/translation.json +++ b/apps/OpenSign/public/locales/es/translation.json @@ -673,5 +673,7 @@ "server-down": "No se pudo conectar al servidor de OpenSign. Si estás alojando OpenSign por tu cuenta, por favor, asegúrate de que todos los pasos de la documentación han sido seguidos correctamente. Si estás ejecutando OpenSign localmente, puedes estar accediendo a OpenSign por un número de puerto incorrecto.", "admin-exists": "El administrador ya existe. Por favor, inicia sesión en la aplicación usando las credenciales de administrador para poder administrar los usuarios.", "public-tour-message": "Por favor, convierte la plantilla en pública para copiar la URL pública", - "add-user-template": "Es necesario agregar un rol antes de poder agregarle campos." + "add-user-template": "Es necesario agregar un rol antes de poder agregarle campos.", + "pdf-uncompatible": "Este pdf no es compatible con opensign, comuníquese con " + } diff --git a/apps/OpenSign/public/locales/fr/translation.json b/apps/OpenSign/public/locales/fr/translation.json index 52dbd9933..3d3de12c3 100644 --- a/apps/OpenSign/public/locales/fr/translation.json +++ b/apps/OpenSign/public/locales/fr/translation.json @@ -672,7 +672,8 @@ "server-down": "Impossible de se connecter au serveur OpenSign. Si vous hébergez vous-même OpenSign, veuillez vous assurer que toutes les étapes de la documentation ont été correctement suivies. Si vous exécutez OpenSign localement, vous y accédez peut-être via un numéro de port incorrect.", "admin-exists": "L'administrateur existe déjà. Veuillez vous connecter à l'application en utilisant les informations d'identification de l'administrateur afin de gérer les utilisateurs.", "public-tour-message": "Le modèle doit être public avant que vous puissiez générer un lien partageable.", - "add-user-template":"Vous devez ajouter un rôle avant de pouvoir lui ajouter des champs. " + "add-user-template":"Vous devez ajouter un rôle avant de pouvoir lui ajouter des champs. ", + "pdf-uncompatible":"Ce pdf n'est pas compatible avec opensign, veuillez contacter " } diff --git a/apps/OpenSign/src/constant/Utils.js b/apps/OpenSign/src/constant/Utils.js index f9926022b..8ddedf5cf 100644 --- a/apps/OpenSign/src/constant/Utils.js +++ b/apps/OpenSign/src/constant/Utils.js @@ -1086,18 +1086,22 @@ export const embedDocId = async (pdfDoc, documentId, allPages) => { const textContent = documentId && `OpenSign™ DocumentId: ${documentId} `; const pages = pdfDoc.getPages(); const page = pages[i]; - const getObj = compensateRotation( - page.getRotation().angle, - 10, - 5, - 1, - page.getSize(), - fontSize, - rgb(0.5, 0.5, 0.5), - font, - page - ); - page.drawText(textContent, getObj); + try { + const getObj = compensateRotation( + page.getRotation().angle, + 10, + 5, + 1, + page.getSize(), + fontSize, + rgb(0.5, 0.5, 0.5), + font, + page + ); + page.drawText(textContent, getObj); + } catch (err) { + console.log("Err in embed docId on page", i + 1, err?.message); + } } }; @@ -1327,7 +1331,9 @@ export const multiSignEmbed = async ( ); pdfDoc.registerFontkit(fontkit); const font = await pdfDoc.embedFont(fontBytes, { subset: true }); + let hasError = false; for (let item of widgets) { + if (hasError) break; // Stop the outer loop if an error occurred const containerScale = getContainerScale( pdfOriginalWH, item?.pageNumber, @@ -1370,308 +1376,323 @@ export const multiSignEmbed = async ( } }) ); - widgetsPositionArr.forEach(async (position, id) => { - let img; - if (["signature", "stamp", "initials", "image"].includes(position.type)) { - if (position.ImageType && position.ImageType === "image/jpeg") { - img = await pdfDoc.embedJpg(images[id]); - } else { - img = await pdfDoc.embedPng(images[id]); - } - } else if (!position.type) { - // to handle old widget when only stamp and signature are exists - if (position.ImageType && position.ImageType === "image/jpeg") { - img = await pdfDoc.embedJpg(images[id]); - } else { - img = await pdfDoc.embedPng(images[id]); - } - } - let widgetWidth, widgetHeight; - widgetWidth = placeholderWidth(position); - widgetHeight = placeholderHeight(position); - const xPos = (position) => { - const resizePos = position.xPosition; - //first two condition handle to old data already saved from mobile view which scale point diffrent - if (isMobile && position.isMobile) { - //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale - const x = resizePos * (position.scale / scale); - return x * scale; - } else if (position.isMobile && position.scale) { - const x = resizePos * position.scale; - return x; - } else { - return resizePos; - } - }; - const yPos = (position) => { - const resizePos = position.yPosition; - - if (position.isMobile && position.scale) { - if (position.IsResize) { - const y = resizePos * position.scale; - return y; + for (let [id, position] of widgetsPositionArr.entries()) { + if (hasError) break; // Stop the inner loop if an error occurred + try { + let img; + if ( + ["signature", "stamp", "initials", "image"].includes(position.type) + ) { + if (position.ImageType && position.ImageType === "image/jpeg") { + img = await pdfDoc.embedJpg(images[id]); } else { - const y = resizePos * position.scale; - return y; + img = await pdfDoc.embedPng(images[id]); } - } else { - return resizePos; - } - }; - const color = position?.options?.fontColor; - const updateColorInRgb = getWidgetsFontColor(color); - const fontSize = parseInt(position?.options?.fontSize || 12); - const widgetTypeExist = [ - textWidget, - textInputWidget, - "name", - "company", - "job title", - "date", - "email" - ].includes(position.type); - if (position.type === "checkbox") { - let checkboxGapFromTop, isCheck; - let y = yPos(position); - const optionsFontSize = fontSize || 13; - const checkboxSize = fontSize; - const checkboxTextGapFromLeft = fontSize + 5 || 22; - if (position?.options?.values.length > 0) { - position?.options?.values.forEach((item, ind) => { - const checkboxRandomId = "checkbox" + randomId(); - - if ( - position?.options?.response && - position?.options?.response?.length > 0 - ) { - isCheck = position?.options?.response?.includes(ind); - } else if (position?.options?.defaultValue) { - isCheck = position?.options?.defaultValue?.includes(ind); - } - - const checkbox = form.createCheckBox(checkboxRandomId); - - if (ind > 0) { - y = y + checkboxGapFromTop; - } else { - checkboxGapFromTop = fontSize + 5 || 26; - } - - if (!position?.options?.isHideLabel) { - // below line of code is used to embed label with radio button in pdf - const optionsPosition = compensateRotation( - page.getRotation().angle, - xPos(position) + checkboxTextGapFromLeft, - y, - 1, - page.getSize(), - optionsFontSize, - updateColorInRgb, - font, - page - ); - page.drawText(item, optionsPosition); - } - let checkboxObj = { - x: xPos(position), - y: y, - width: checkboxSize, - height: checkboxSize - }; - checkboxObj = getWidgetPosition(page, checkboxObj, 1); - checkbox.addToPage(page, checkboxObj); - - //applied which checkbox should be checked - if (isCheck) { - checkbox.check(); - } else { - checkbox.uncheck(); - } - checkbox.enableReadOnly(); - }); - } - } else if (widgetTypeExist) { - const fontSize = calculateFontSize( - position, - containerScale, - signyourself, - position.Height - ); - parseInt(fontSize); - let textContent; - if (position?.options?.response) { - textContent = position.options?.response; - } else if (position?.options?.defaultValue) { - textContent = position?.options?.defaultValue; - } - const fixedWidth = widgetWidth; // Set your fixed width - const isNewOnEnterLineExist = textContent.includes("\n"); - - // Function to break text into lines based on the fixed width - const NewbreakTextIntoLines = (textContent, width) => { - const lines = []; - let currentLine = ""; - - for (const word of textContent.split(" ")) { - //get text line width - const lineWidth = font.widthOfTextAtSize( - `${currentLine} ${word}`, - fontSize - ); - //check text content line width is less or equal to container width - if (lineWidth <= width) { - currentLine += ` ${word}`; - } else { - lines.push(currentLine.trim()); - currentLine = `${word}`; - } + } else if (!position.type) { + // to handle old widget when only stamp and signature are exists + if (position.ImageType && position.ImageType === "image/jpeg") { + img = await pdfDoc.embedJpg(images[id]); + } else { + img = await pdfDoc.embedPng(images[id]); + } + } + let widgetWidth, widgetHeight; + widgetWidth = placeholderWidth(position); + widgetHeight = placeholderHeight(position); + const xPos = (position) => { + const resizePos = position.xPosition; + //first two condition handle to old data already saved from mobile view which scale point diffrent + if (isMobile && position.isMobile) { + //if pos.isMobile false -- placeholder saved from desktop view then handle position in mobile view divided by scale + const x = resizePos * (position.scale / scale); + return x * scale; + } else if (position.isMobile && position.scale) { + const x = resizePos * position.scale; + return x; + } else { + return resizePos; } - lines.push(currentLine.trim()); - return lines; }; + const yPos = (position) => { + const resizePos = position.yPosition; - // Function to break text into lines based on when user go next line on press enter button - const breakTextIntoLines = (textContent, width) => { - const lines = []; - - for (const word of textContent.split("\n")) { - const lineWidth = font.widthOfTextAtSize(`${word}`, fontSize); - //checking string length to container width - //if string length is less then container width it means user press enter button - if (lineWidth <= width) { - lines.push(word); - } - //else adjust text content according to width and send it in new line - else { - const newLine = NewbreakTextIntoLines(word, width); - lines.push(...newLine); + if (position.isMobile && position.scale) { + if (position.IsResize) { + const y = resizePos * position.scale; + return y; + } else { + const y = resizePos * position.scale; + return y; } + } else { + return resizePos; } - - return lines; }; + const color = position?.options?.fontColor; + const updateColorInRgb = getWidgetsFontColor(color); + const fontSize = parseInt(position?.options?.fontSize || 12); + const widgetTypeExist = [ + textWidget, + textInputWidget, + "name", + "company", + "job title", + "date", + "email" + ].includes(position.type); + if (position.type === "checkbox") { + let checkboxGapFromTop, isCheck; + let y = yPos(position); + const optionsFontSize = fontSize || 13; + const checkboxSize = fontSize; + const checkboxTextGapFromLeft = fontSize + 5 || 22; + if (position?.options?.values.length > 0) { + position?.options?.values.forEach((item, ind) => { + const checkboxRandomId = "checkbox" + randomId(); - //check if text content have `\n` string it means user press enter to go next line and handle condition - //else auto adjust text content according to container width - const lines = isNewOnEnterLineExist - ? breakTextIntoLines(textContent, fixedWidth) - : NewbreakTextIntoLines(textContent, fixedWidth); - // Set initial y-coordinate for the first line - let x = xPos(position); - let y = yPos(position); - // Embed each line on the page - for (const line of lines) { - const textPosition = compensateRotation( - page.getRotation().angle, - x, - y, - 1, - page.getSize(), - fontSize, - updateColorInRgb, - font, - page + if ( + position?.options?.response && + position?.options?.response?.length > 0 + ) { + isCheck = position?.options?.response?.includes(ind); + } else if (position?.options?.defaultValue) { + isCheck = position?.options?.defaultValue?.includes(ind); + } + + const checkbox = form.createCheckBox(checkboxRandomId); + + if (ind > 0) { + y = y + checkboxGapFromTop; + } else { + checkboxGapFromTop = fontSize + 5 || 26; + } + + if (!position?.options?.isHideLabel) { + // below line of code is used to embed label with radio button in pdf + const optionsPosition = compensateRotation( + page.getRotation().angle, + xPos(position) + checkboxTextGapFromLeft, + y, + 1, + page.getSize(), + optionsFontSize, + updateColorInRgb, + font, + page + ); + page.drawText(item, optionsPosition); + } + let checkboxObj = { + x: xPos(position), + y: y, + width: checkboxSize, + height: checkboxSize + }; + checkboxObj = getWidgetPosition(page, checkboxObj, 1); + checkbox.addToPage(page, checkboxObj); + + //applied which checkbox should be checked + if (isCheck) { + checkbox.check(); + } else { + checkbox.uncheck(); + } + checkbox.enableReadOnly(); + }); + } + } else if (widgetTypeExist) { + const fontSize = calculateFontSize( + position, + containerScale, + signyourself, + position.Height ); - page.drawText(line, textPosition); - y += 18; // Adjust the line height as needed - } - } else if (position.type === "dropdown") { - const fontsize = parseInt(position?.options?.fontSize) || 12; + parseInt(fontSize); + let textContent; + if (position?.options?.response) { + textContent = position.options?.response; + } else if (position?.options?.defaultValue) { + textContent = position?.options?.defaultValue; + } + const fixedWidth = widgetWidth; // Set your fixed width + const isNewOnEnterLineExist = textContent.includes("\n"); - const dropdownRandomId = "dropdown" + randomId(); - const dropdown = form.createDropdown(dropdownRandomId); - dropdown.addOptions(position?.options?.values); - if (position?.options?.response) { - dropdown.select(position.options?.response); - } else if (position?.options?.defaultValue) { - dropdown.select(position?.options?.defaultValue); - } - // Define the default appearance string - // Example format: `/FontName FontSize Tf 0 g` where: - // - `/FontName` is the name of the font (e.g., `/Helv` for Helvetica) - // - `FontSize` is the size you want to set (e.g., 12) - // - `Tf` specifies the font and size - // - `0 g` sets the text color to black - const defaultAppearance = `/Helv ${fontsize} Tf 0 g`; - // Set the default appearance for the dropdown field - dropdown.acroField.setDefaultAppearance(defaultAppearance); - dropdown.setFontSize(fontsize); - const dropdownObj = { - x: xPos(position), - y: yPos(position), - width: widgetWidth, - height: widgetHeight - }; - const dropdownOption = getWidgetPosition(page, dropdownObj, 1); - const dropdownSelected = { ...dropdownOption, font: font }; - dropdown.defaultUpdateAppearances(font); - dropdown.addToPage(page, dropdownSelected); - dropdown.enableReadOnly(); - } else if (position.type === radioButtonWidget) { - const radioRandomId = "radio" + randomId(); - const radioGroup = form.createRadioGroup(radioRandomId); - let radioOptionGapFromTop; - const optionsFontSize = fontSize || 13; - const radioTextGapFromLeft = fontSize + 5 || 20; - const radioSize = fontSize; - let y = yPos(position); - if (position?.options?.values.length > 0) { - position?.options?.values.forEach((item, ind) => { - if (ind > 0) { - y = y + radioOptionGapFromTop; - } else { - radioOptionGapFromTop = fontSize + 10 || 25; - } - if (!position?.options?.isHideLabel) { - // below line of code is used to embed label with radio button in pdf + // Function to break text into lines based on the fixed width + const NewbreakTextIntoLines = (textContent, width) => { + const lines = []; + let currentLine = ""; - const optionsPosition = compensateRotation( - page.getRotation().angle, - xPos(position) + radioTextGapFromLeft, - y, - 1, - page.getSize(), - optionsFontSize, - updateColorInRgb, - font, - page + for (const word of textContent.split(" ")) { + //get text line width + const lineWidth = font.widthOfTextAtSize( + `${currentLine} ${word}`, + fontSize ); - - page.drawText(item, optionsPosition); + //check text content line width is less or equal to container width + if (lineWidth <= width) { + currentLine += ` ${word}`; + } else { + lines.push(currentLine.trim()); + currentLine = `${word}`; + } } - let radioObj = { - x: xPos(position), - y: y, - width: radioSize, - height: radioSize - }; + lines.push(currentLine.trim()); + return lines; + }; - radioObj = getWidgetPosition(page, radioObj, 1); - radioGroup.addOptionToPage(item, page, radioObj); - }); - } - if (position?.options?.response) { - radioGroup.select(position.options?.response); - } else if (position?.options?.defaultValue) { - radioGroup.select(position?.options?.defaultValue); - } - radioGroup.enableReadOnly(); - } else { - const signature = { - x: xPos(position), - y: yPos(position), - width: widgetWidth, - height: widgetHeight - }; + // Function to break text into lines based on when user go next line on press enter button + const breakTextIntoLines = (textContent, width) => { + const lines = []; - const imageOptions = getWidgetPosition(page, signature, 1); - page.drawImage(img, imageOptions); + for (const word of textContent.split("\n")) { + const lineWidth = font.widthOfTextAtSize(`${word}`, fontSize); + //checking string length to container width + //if string length is less then container width it means user press enter button + if (lineWidth <= width) { + lines.push(word); + } + //else adjust text content according to width and send it in new line + else { + const newLine = NewbreakTextIntoLines(word, width); + lines.push(...newLine); + } + } + + return lines; + }; + + //check if text content have `\n` string it means user press enter to go next line and handle condition + //else auto adjust text content according to container width + const lines = isNewOnEnterLineExist + ? breakTextIntoLines(textContent, fixedWidth) + : NewbreakTextIntoLines(textContent, fixedWidth); + // Set initial y-coordinate for the first line + let x = xPos(position); + let y = yPos(position); + // Embed each line on the page + for (const line of lines) { + const textPosition = compensateRotation( + page.getRotation().angle, + x, + y, + 1, + page.getSize(), + fontSize, + updateColorInRgb, + font, + page + ); + page.drawText(line, textPosition); + y += 18; // Adjust the line height as needed + } + } else if (position.type === "dropdown") { + const fontsize = parseInt(position?.options?.fontSize) || 12; + + const dropdownRandomId = "dropdown" + randomId(); + const dropdown = form.createDropdown(dropdownRandomId); + dropdown.addOptions(position?.options?.values); + if (position?.options?.response) { + dropdown.select(position.options?.response); + } else if (position?.options?.defaultValue) { + dropdown.select(position?.options?.defaultValue); + } + // Define the default appearance string + // Example format: `/FontName FontSize Tf 0 g` where: + // - `/FontName` is the name of the font (e.g., `/Helv` for Helvetica) + // - `FontSize` is the size you want to set (e.g., 12) + // - `Tf` specifies the font and size + // - `0 g` sets the text color to black + const defaultAppearance = `/Helv ${fontsize} Tf 0 g`; + // Set the default appearance for the dropdown field + dropdown.acroField.setDefaultAppearance(defaultAppearance); + dropdown.setFontSize(fontsize); + const dropdownObj = { + x: xPos(position), + y: yPos(position), + width: widgetWidth, + height: widgetHeight + }; + const dropdownOption = getWidgetPosition(page, dropdownObj, 1); + const dropdownSelected = { ...dropdownOption, font: font }; + dropdown.defaultUpdateAppearances(font); + dropdown.addToPage(page, dropdownSelected); + dropdown.enableReadOnly(); + } else if (position.type === radioButtonWidget) { + const radioRandomId = "radio" + randomId(); + const radioGroup = form.createRadioGroup(radioRandomId); + let radioOptionGapFromTop; + const optionsFontSize = fontSize || 13; + const radioTextGapFromLeft = fontSize + 5 || 20; + const radioSize = fontSize; + let y = yPos(position); + if (position?.options?.values.length > 0) { + position?.options?.values.forEach((item, ind) => { + if (ind > 0) { + y = y + radioOptionGapFromTop; + } else { + radioOptionGapFromTop = fontSize + 10 || 25; + } + if (!position?.options?.isHideLabel) { + // below line of code is used to embed label with radio button in pdf + + const optionsPosition = compensateRotation( + page.getRotation().angle, + xPos(position) + radioTextGapFromLeft, + y, + 1, + page.getSize(), + optionsFontSize, + updateColorInRgb, + font, + page + ); + + page.drawText(item, optionsPosition); + } + let radioObj = { + x: xPos(position), + y: y, + width: radioSize, + height: radioSize + }; + + radioObj = getWidgetPosition(page, radioObj, 1); + radioGroup.addOptionToPage(item, page, radioObj); + }); + } + if (position?.options?.response) { + radioGroup.select(position.options?.response); + } else if (position?.options?.defaultValue) { + radioGroup.select(position?.options?.defaultValue); + } + radioGroup.enableReadOnly(); + } else { + const signature = { + x: xPos(position), + y: yPos(position), + width: widgetWidth, + height: widgetHeight + }; + + const imageOptions = getWidgetPosition(page, signature, 1); + page.drawImage(img, imageOptions); + } + } catch (err) { + console.log("Err in embed widget on page ", pageNo, err?.message); + hasError = true; // Set the flag to stop both loops + break; // Exit inner loop } - }); + } + } + if (!hasError) { + const pdfBytes = await pdfDoc.saveAsBase64({ useObjectStreams: false }); + return pdfBytes; + } else { + return { + error: + "This pdf is not compatible with opensign please contact " + }; } - const pdfBytes = await pdfDoc.saveAsBase64({ useObjectStreams: false }); - //console.log("pdf", pdfBytes); - return pdfBytes; }; // function for validating URLs diff --git a/apps/OpenSign/src/pages/PdfRequestFiles.js b/apps/OpenSign/src/pages/PdfRequestFiles.js index d1a671abd..97f97c445 100644 --- a/apps/OpenSign/src/pages/PdfRequestFiles.js +++ b/apps/OpenSign/src/pages/PdfRequestFiles.js @@ -907,163 +907,171 @@ function PdfRequestFiles(props) { ); // console.log("pdfte", pdfBytes); //get ExistUserPtr object id of user class to get tenantDetails - const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId; - let activeMailAdapter = - pdfDetails?.[0]?.ExtUserPtr?.active_mail_adapter; - - //function for call to embed signature in pdf and get digital signature pdf - const resSign = await signPdfFun( - pdfBytes, - documentId, - signerObjectId, - objectId, - isSubscribed, - activeMailAdapter, - widgets - ); - if (resSign && resSign.status === "success") { - setPdfUrl(resSign.data); - setIsSigned(true); - setSignedSigners([]); - setUnSignedSigners([]); - getDocumentDetails(documentId, true); - const index = pdfDetails?.[0]?.Signers.findIndex( - (x) => x.objectId === signerObjectId + if (!pdfBytes?.error) { + const objectId = pdfDetails?.[0]?.ExtUserPtr?.UserId?.objectId; + let activeMailAdapter = + pdfDetails?.[0]?.ExtUserPtr?.active_mail_adapter; + //function for call to embed signature in pdf and get digital signature pdf + const resSign = await signPdfFun( + pdfBytes, + documentId, + signerObjectId, + objectId, + isSubscribed, + activeMailAdapter, + widgets ); - const newIndex = index + 1; - const usermail = { - Email: pdfDetails?.[0]?.Placeholders[newIndex]?.email || "" - }; - const user = usermail?.Email - ? usermail - : pdfDetails?.[0]?.Signers[newIndex]; - if (sendmail !== "false" && sendInOrder) { - const requestBody = pdfDetails?.[0]?.RequestBody; - const requestSubject = pdfDetails?.[0]?.RequestSubject; - if (user) { - const expireDate = pdfDetails?.[0].ExpiryDate.iso; - const newDate = new Date(expireDate); - const localExpireDate = newDate.toLocaleDateString( - "en-US", - { - day: "numeric", - month: "long", - year: "numeric" - } - ); - let senderEmail = pdfDetails?.[0].ExtUserPtr.Email; - let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone; - const senderName = `${pdfDetails?.[0].ExtUserPtr.Name}`; + if (resSign && resSign.status === "success") { + setPdfUrl(resSign.data); + setIsSigned(true); + setSignedSigners([]); + setUnSignedSigners([]); + getDocumentDetails(documentId, true); + const index = pdfDetails?.[0]?.Signers.findIndex( + (x) => x.objectId === signerObjectId + ); + const newIndex = index + 1; + const usermail = { + Email: pdfDetails?.[0]?.Placeholders[newIndex]?.email || "" + }; + const user = usermail?.Email + ? usermail + : pdfDetails?.[0]?.Signers[newIndex]; + if (sendmail !== "false" && sendInOrder) { + const requestBody = pdfDetails?.[0]?.RequestBody; + const requestSubject = pdfDetails?.[0]?.RequestSubject; + if (user) { + const expireDate = pdfDetails?.[0].ExpiryDate.iso; + const newDate = new Date(expireDate); + const localExpireDate = newDate.toLocaleDateString( + "en-US", + { + day: "numeric", + month: "long", + year: "numeric" + } + ); + let senderEmail = pdfDetails?.[0].ExtUserPtr.Email; + let senderPhone = pdfDetails?.[0]?.ExtUserPtr?.Phone; + const senderName = `${pdfDetails?.[0].ExtUserPtr.Name}`; - try { - const imgPng = - "https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"; - let url = `${localStorage.getItem( - "baseUrl" - )}functions/sendmailv3`; - const headers = { - "Content-Type": "application/json", - "X-Parse-Application-Id": - localStorage.getItem("parseAppId"), - sessionToken: localStorage.getItem("accesstoken") - }; - const objectId = user?.objectId; - const hostUrl = window.location.origin; - //encode this url value `${pdfDetails?.[0].objectId}/${user.Email}/${objectId}` to base64 using `btoa` function - let encodeBase64; - if (objectId) { - encodeBase64 = btoa( - `${pdfDetails?.[0].objectId}/${user.Email}/${objectId}` - ); - } else { - encodeBase64 = btoa( - `${pdfDetails?.[0].objectId}/${user.Email}` - ); - } - const hostPublicUrl = isStaging - ? "https://staging-app.opensignlabs.com" - : "https://app.opensignlabs.com"; - let signPdf = props?.templateId - ? `${hostPublicUrl}/login/${encodeBase64}` - : `${hostUrl}/login/${encodeBase64}`; - const openSignUrl = - "https://www.opensignlabs.com/contact-us"; - const orgName = pdfDetails[0]?.ExtUserPtr.Company - ? pdfDetails[0].ExtUserPtr.Company - : ""; - const themeBGcolor = themeColor; - let replaceVar; - if (requestBody && requestSubject && isSubscribed) { - const replacedRequestBody = requestBody.replace( - /"/g, - "'" - ); - const htmlReqBody = - "" + - replacedRequestBody + - " "; - - 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: `Sign here` + try { + const imgPng = + "https://qikinnovation.ams3.digitaloceanspaces.com/logo.png"; + let url = `${localStorage.getItem( + "baseUrl" + )}functions/sendmailv3`; + const headers = { + "Content-Type": "application/json", + "X-Parse-Application-Id": + localStorage.getItem("parseAppId"), + sessionToken: localStorage.getItem("accesstoken") }; - replaceVar = replaceMailVaribles( - requestSubject, - htmlReqBody, - variables - ); - } + const objectId = user?.objectId; + const hostUrl = window.location.origin; + //encode this url value `${pdfDetails?.[0].objectId}/${user.Email}/${objectId}` to base64 using `btoa` function + let encodeBase64; + if (objectId) { + encodeBase64 = btoa( + `${pdfDetails?.[0].objectId}/${user.Email}/${objectId}` + ); + } else { + encodeBase64 = btoa( + `${pdfDetails?.[0].objectId}/${user.Email}` + ); + } + const hostPublicUrl = isStaging + ? "https://staging-app.opensignlabs.com" + : "https://app.opensignlabs.com"; + let signPdf = props?.templateId + ? `${hostPublicUrl}/login/${encodeBase64}` + : `${hostUrl}/login/${encodeBase64}`; + const openSignUrl = + "https://www.opensignlabs.com/contact-us"; + const orgName = pdfDetails[0]?.ExtUserPtr.Company + ? pdfDetails[0].ExtUserPtr.Company + : ""; + const themeBGcolor = themeColor; + let replaceVar; + if (requestBody && requestSubject && isSubscribed) { + const replacedRequestBody = requestBody.replace( + /"/g, + "'" + ); + const htmlReqBody = + "" + + replacedRequestBody + + " "; - let params = { - mailProvider: activeMailAdapter, - extUserId: extUserId, - recipient: user.Email, - subject: requestSubject - ? replaceVar?.subject - : `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign "${pdfDetails?.[0].Name}"`, - from: senderEmail, - plan: plancode, - html: requestBody - ? replaceVar?.body - : "

Digital Signature Request

" + - pdfDetails?.[0].ExtUserPtr.Name + - " has requested you to review and sign " + - pdfDetails?.[0].Name + - ".

Sender " + - senderEmail + - "
Organization " + - orgName + - "
Expires on " + - localExpireDate + - "

This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + - senderEmail + - " directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ here.

" - }; - await axios.post(url, params, { headers: headers }); - } catch (error) { - console.log("error", error); + 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: `Sign here` + }; + replaceVar = replaceMailVaribles( + requestSubject, + htmlReqBody, + variables + ); + } + + let params = { + mailProvider: activeMailAdapter, + extUserId: extUserId, + recipient: user.Email, + subject: requestSubject + ? replaceVar?.subject + : `${pdfDetails?.[0].ExtUserPtr.Name} has requested you to sign "${pdfDetails?.[0].Name}"`, + from: senderEmail, + plan: plancode, + html: requestBody + ? replaceVar?.body + : "

Digital Signature Request

" + + pdfDetails?.[0].ExtUserPtr.Name + + " has requested you to review and sign " + + pdfDetails?.[0].Name + + ".

Sender " + + senderEmail + + "
Organization " + + orgName + + "
Expires on " + + localExpireDate + + "

This is an automated email from OpenSign™. For any queries regarding this email, please contact the sender " + + senderEmail + + " directly.If you think this email is inappropriate or spam, you may file a complaint with OpenSign™ here.

" + }; + await axios.post(url, params, { headers: headers }); + } catch (error) { + console.log("error", error); + } } } + } else { + setIsUiLoading(false); + setIsAlert({ isShow: true, alertMessage: resSign.message }); } } else { setIsUiLoading(false); - setIsAlert({ isShow: true, alertMessage: resSign.message }); + setIsAlert({ + header: t("error"), + isShow: true, + alertMessage: t("pdf-uncompatible") + }); } } catch (err) { setIsUiLoading(false); diff --git a/apps/OpenSign/src/pages/SignyourselfPdf.js b/apps/OpenSign/src/pages/SignyourselfPdf.js index ad89d82cd..c4c91950d 100644 --- a/apps/OpenSign/src/pages/SignyourselfPdf.js +++ b/apps/OpenSign/src/pages/SignyourselfPdf.js @@ -617,12 +617,8 @@ function SignYourSelf() { const checkSignUrl = requiredWidgets[i]?.pos?.SignUrl; let checkDefaultSigned = requiredWidgets[i]?.options?.defaultValue; - if (!checkSignUrl) { - if (!checkDefaultSigned) { - if (!showAlert) { - showAlert = true; - } - } + if (!checkSignUrl && !checkDefaultSigned && !showAlert) { + showAlert = true; } } } @@ -649,10 +645,9 @@ function SignYourSelf() { return; } else { setIsUiLoading(true); - const existingPdfBytes = pdfArrayBuffer; // Load a PDFDocument from the existing PDF bytes try { - const pdfDoc = await PDFDocument.load(existingPdfBytes); + const pdfDoc = await PDFDocument.load(pdfArrayBuffer); const isSignYourSelfFlow = true; const extUserPtr = pdfDetails[0].ExtUserPtr; const HeaderDocId = extUserPtr?.HeaderDocId; @@ -671,8 +666,15 @@ function SignYourSelf() { ); // console.log("pdf", pdfBytes); //function for call to embed signature in pdf and get digital signature pdf - if (pdfBytes) { + if (!pdfBytes?.error) { await signPdfFun(pdfBytes, documentId); + } else { + setIsUiLoading(false); + setIsAlert({ + header: t("error"), + isShow: true, + alertMessage: t("pdf-uncompatible") + }); } } catch (err) { setIsUiLoading(false); diff --git a/apps/OpenSign/src/script/locales/en/translation.json b/apps/OpenSign/src/script/locales/en/translation.json index f96845408..e049c3d52 100644 --- a/apps/OpenSign/src/script/locales/en/translation.json +++ b/apps/OpenSign/src/script/locales/en/translation.json @@ -672,6 +672,7 @@ "document-logs": "Document logs", "server-down": "Unable to connect to the OpenSign server. If you are self-hosting OpenSign, please ensure that all the steps in the documentation have been followed correctly. If you're running OpenSign locally, you might be accessing it through an incorrect port number.", "admin-exists": "Admin already exists. Please login to the application using admin credentials in order to manage users.", - "public-tour-message":"The template needs to be public before you can generate a shareable link.", - "add-user-template": "You need to add a role before you can add fields for it." + "public-tour-message": "The template needs to be public before you can generate a shareable link.", + "add-user-template": "You need to add a role before you can add fields for it.", + "pdf-uncompatible": "This pdf is not compatible with opensign, please contact " } diff --git a/apps/OpenSign/src/script/locales/es/translation.json b/apps/OpenSign/src/script/locales/es/translation.json index 02365d194..919219493 100644 --- a/apps/OpenSign/src/script/locales/es/translation.json +++ b/apps/OpenSign/src/script/locales/es/translation.json @@ -673,5 +673,6 @@ "server-down": "No se pudo conectar al servidor de OpenSign. Si estás alojando OpenSign por tu cuenta, por favor, asegúrate de que todos los pasos de la documentación han sido seguidos correctamente. Si estás ejecutando OpenSign localmente, puedes estar accediendo a OpenSign por un número de puerto incorrecto.", "admin-exists": "El administrador ya existe. Por favor, inicia sesión en la aplicación usando las credenciales de administrador para poder administrar los usuarios.", "public-tour-message": "Por favor, convierte la plantilla en pública para copiar la URL pública", - "add-user-template": "Es necesario agregar un rol antes de poder agregarle campos." + "add-user-template": "Es necesario agregar un rol antes de poder agregarle campos.", + "pdf-uncompatible": "Este pdf no es compatible con opensign, comuníquese con " } diff --git a/apps/OpenSign/src/script/locales/fr/translation.json b/apps/OpenSign/src/script/locales/fr/translation.json index b83b915b7..0bdd2d050 100644 --- a/apps/OpenSign/src/script/locales/fr/translation.json +++ b/apps/OpenSign/src/script/locales/fr/translation.json @@ -639,7 +639,7 @@ "public-template-mssg-3": "Besoin de plus de détails ou d'exemples ?", "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-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.", "copy-code": "COPIE", "copied-code": "COPIÉ", "Installation": "Installation", @@ -672,5 +672,6 @@ "server-down": "Impossible de se connecter au serveur OpenSign. Si vous hébergez vous-même OpenSign, veuillez vous assurer que toutes les étapes de la documentation ont été correctement suivies. Si vous exécutez OpenSign localement, vous y accédez peut-être via un numéro de port incorrect.", "admin-exists": "L'administrateur existe déjà. Veuillez vous connecter à l'application en utilisant les informations d'identification de l'administrateur afin de gérer les utilisateurs.", "public-tour-message": "Le modèle doit être public avant que vous puissiez générer un lien partageable.", - "add-user-template":"Vous devez ajouter un rôle avant de pouvoir lui ajouter des champs. " + "add-user-template": "Vous devez ajouter un rôle avant de pouvoir lui ajouter des champs. ", + "pdf-uncompatible": "Ce pdf n'est pas compatible avec opensign, veuillez contacter " }