IO-2433 Delete on cancel, improved styling.

This commit is contained in:
Patrick Fic
2026-02-27 16:03:27 -08:00
parent 52f43a600c
commit 51fba24a3d
5 changed files with 66 additions and 40 deletions

View File

@@ -480,4 +480,5 @@
.esignature-embed {
width: 100%;
height: 100%;
border-width: 0;
}

View File

@@ -1,11 +1,11 @@
import { Button, Modal } from "antd";
import { EmbedUpdateDocumentV1 } from "@documenso/embed-react";
import { Modal } from "antd";
import axios from "axios";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectEsignature } from "../../redux/modals/modals.selectors";
import { EmbedUpdateDocumentV1 } from "@documenso/embed-react";
import axios from "axios";
import { selectBodyshop } from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
@@ -26,23 +26,42 @@ export function EsignatureModalContainer({ esignatureModal, toggleModalVisible,
<Modal
open={open}
title={t("jobs.labels.esignature")}
onOk={() => {
toggleModalVisible();
onOk={async () => {
try {
const distResult = await axios.post("/esign/distribute", {
documentId,
envelopeId,
jobid,
bodyshopid: bodyshop.id
});
console.log("Distribution result:", distResult);
toggleModalVisible();
} catch (error) {
console.error("Error distributing document:", error);
}
}}
onCancel={() => {
toggleModalVisible();
onCancel={async () => {
try {
const cancelResult = await axios.post("/esign/delete", {
documentId,
envelopeId
});
console.log("Cancel result:", cancelResult);
toggleModalVisible();
} catch (error) {
console.error("Error cancelling document:", error);
}
}}
cancelButtonProps={{ style: { display: "none" } }}
okButtonProps={{ title: "Distribute by Email" }}
width="90%"
destroyOnHidden
>
<div style={{ height: "800px", width: "100%" }}>
<div style={{ height: "600px", width: "100%" }}>
{token ? (
<EmbedUpdateDocumentV1
presignToken={token}
host="https://stg-app.documenso.com"
documentId={documentId}
externalId={jobid}
className="esignature-embed"
onDocumentUpdated={(data) => {
console.log("Document updated:", data.documentId);
@@ -51,24 +70,6 @@ export function EsignatureModalContainer({ esignatureModal, toggleModalVisible,
) : (
<div>No token...</div>
)}
<Button
onClick={async () => {
// Add your button click handler logic here
try {
const distResult = await axios.post("/esign/distribute", {
documentId,
envelopeId,
jobid,
bodyshopid: bodyshop.id
});
console.log("Distribution result:", distResult);
} catch (error) {
console.error("Error distributing document:", error);
}
}}
>
Distribute Document
</Button>
</div>
</Modal>
);

View File

@@ -43,8 +43,25 @@ async function distributeDocument(req, res) {
}
}
async function newEsignDocument(req, res) {
async function deleteDocument(req, res) {
try {
const { documentId } = req.body;
//TODO: This needs to be hardened to prevent deleting other people's documents, completed ones, etc.
const deleteResult = await documenso.documents.delete({
documentId
});
res.json({ success: true, deleteResult });
} catch (error) {
console.error("Error deleting document:", error?.data);
logger.log(`esig-delete-error`, "ERROR", "esig", "api", {
message: error.message, stack: error.stack,
body: req.body
});
res.status(500).json({ error: "An error occurred while deleting the document." });
}
}
async function newEsignDocument(req, res) {
try {
const client = req.userGraphQLClient;
const { bodyshop } = req.body
@@ -58,7 +75,7 @@ async function newEsignDocument(req, res) {
const createDocumentResponse = await documenso.documents.create({
payload: {
title: esigData?.title,
externalId: req.body.jobid,
externalId: `${req.body.jobid}|${req.user?.email}`, //Have to pass the uploaded by later on. Limited to 255 chars.
recipients: [
{
email: "patrick@imexsystems.ca",//jobData.ownr_ea,
@@ -264,7 +281,8 @@ const fetchContextData = async ({ templateObject, jsrAuth, req, }) => {
module.exports = {
newEsignDocument,
distributeDocument
distributeDocument,
deleteDocument
}

View File

@@ -85,8 +85,14 @@ async function handleDocumentCompleted(payload = sampleComplete) {
//Check if the bodyshop is on image proxy or not
try {
//Split the external id to get the uploaded user.
const [jobid, uploaded_by] = payload.externalId.split("|");
if (!jobid || !uploaded_by) {
throw new Error(`Invalid externalId format. Expected "jobid|uploaded_by", got "${payload.externalId}"`);
}
const { jobs_by_pk } = await client.request(QUERY_META_FOR_ESIG_COMPLETION, {
jobid: payload.externalId
jobid
});
const document = await documenso.document.documentDownload({
documentId: payload.id,
@@ -97,25 +103,24 @@ async function handleDocumentCompleted(payload = sampleComplete) {
const buffer = Buffer.from(arrayBuffer);
let key = `${jobs_by_pk.bodyshop.id}/${jobs_by_pk.id}/${replaceAccents(document.filename).replace(/[^A-Z0-9]+/gi, "_")}-${new Date().getTime()}.pdf`;
if (jobs_by_pk?.bodyshop?.uselocalmediaserver) {
//LMS not yet implemented.
} else {
//S3 Upload
let key = `${jobs_by_pk.bodyshop.id}/${jobs_by_pk.id}/${replaceAccents(document.filename).replace(/[^A-Z0-9]+/gi, "_")}-${new Date().getTime()}.pdf`;
const uploadResult = await uploadFileBuffer({ key, buffer, contentType: "application/pdf" });
if (!uploadResult.success) {
logger.log(`esig-webhook-s3-upload-error`, "ERROR", "redis", "api", {
message: uploadResult.message,
stack: uploadResult.stack,
jobid: payload.externalId,
jobid: jobid,
documentId: payload.id
});
} else {
logger.log(`esig-webhook-s3-upload-success`, "INFO", "redis", "api", {
jobid: payload.externalId,
jobid: jobid,
documentId: payload.id,
s3Key: key,
bucket: uploadResult.bucket
@@ -125,7 +130,7 @@ async function handleDocumentCompleted(payload = sampleComplete) {
jobid: jobs_by_pk.id,
bodyshopid: jobs_by_pk.bodyshop.id,
operation: `Esignature document with title ${payload.title} (ID: ${payload.documentMeta.id}) has been completed.`,
useremail: "patrick@imex.dev", //TODO: Figure out the hardcoded bypass.
useremail: uploaded_by,
type: 'esig-complete'
}
})
@@ -133,12 +138,12 @@ async function handleDocumentCompleted(payload = sampleComplete) {
await client.request(INSERT_ESIGNATURE_DOCUMENT, {
docInput: {
jobid: jobs_by_pk.id,
uploaded_by: "patrick@imex.dev", //TODO: Figure out the hard coded bypass.
uploaded_by: uploaded_by,
key,
type: "application/pdf",
extension: "pdf",
bodyshopid: jobs_by_pk.bodyshop.id,
size: buffer.length, //Leftover from Cloudinary. We don't do any optimization on upload, so it will always be file.size.
size: buffer.length,
takenat: new Date().toISOString(),
}
})

View File

@@ -3,13 +3,14 @@ const router = express.Router();
const validateFirebaseIdTokenMiddleware = require("../middleware/validateFirebaseIdTokenMiddleware");
const withUserGraphQLClientMiddleware = require("../middleware/withUserGraphQLClientMiddleware");
const { newEsignDocument, distributeDocument } = require("../esign/esign-new");
const { newEsignDocument, distributeDocument, deleteDocument } = require("../esign/esign-new");
const { esignWebhook } = require("../esign/webhook");
//router.use(validateFirebaseIdTokenMiddleware);
router.post("/new", validateFirebaseIdTokenMiddleware, withUserGraphQLClientMiddleware, newEsignDocument);
router.post("/distribute", validateFirebaseIdTokenMiddleware, withUserGraphQLClientMiddleware, distributeDocument);
router.post("/delete", validateFirebaseIdTokenMiddleware, withUserGraphQLClientMiddleware, deleteDocument);
router.post("/webhook", esignWebhook);