IO-2433 Basic embedded authoring.

This commit is contained in:
Patrick Fic
2026-02-27 13:15:10 -08:00
parent e03546d989
commit e25174ff97
15 changed files with 1284 additions and 7 deletions

View File

@@ -475,3 +475,9 @@
margin-left: auto;
flex: 0 0 auto;
}
.esignature-embed {
width: 100%;
height: 100%;
}

View File

@@ -0,0 +1,70 @@
import { Button, Modal } from "antd";
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";
const mapStateToProps = createStructuredSelector({
esignatureModal: selectEsignature
});
const mapDispatchToProps = (dispatch) => ({
toggleModalVisible: () => dispatch(toggleModalVisible("esignature"))
});
export function EsignatureModalContainer({ esignatureModal, toggleModalVisible }) {
const { t } = useTranslation();
const { open, context } = esignatureModal;
const { token, envelopeId, documentId } = context;
return (
<Modal
open={open}
title={t("jobs.labels.esignature")}
onOk={() => {
toggleModalVisible();
}}
onCancel={() => {
toggleModalVisible();
}}
cancelButtonProps={{ style: { display: "none" } }}
width="90%"
destroyOnHidden
>
<div style={{ height: "800px", width: "100%" }}>
{token ? (
<EmbedUpdateDocumentV1
presignToken={token}
host="https://stg-app.documenso.com"
documentId={documentId}
externalId="order-12345"
className="esignature-embed"
onDocumentUpdated={(data) => {
console.log("Document updated:", data.documentId);
}}
/>
) : (
<div>No token...</div>
)}
<Button
onClick={async () => {
// Add your button click handler logic here
try {
const distResult = await axios.post("/esign/distribute", { documentId, envelopeId });
console.log("Distribution result:", distResult);
} catch (error) {
console.error("Error distributing document:", error);
}
}}
>
Distribute Document
</Button>
</div>
</Modal>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(EsignatureModalContainer);

View File

@@ -1,4 +1,4 @@
import { MailOutlined, PrinterOutlined } from "@ant-design/icons";
import { MailOutlined, PrinterOutlined, SignatureFilled } from "@ant-design/icons";
import { Space, Spin } from "antd";
import { useState } from "react";
import { connect } from "react-redux";
@@ -10,6 +10,8 @@ import { GenerateDocument } from "../../utils/RenderTemplate";
import LockWrapperComponent from "../lock-wrapper/lock-wrapper.component";
import { HasFeatureAccess } from "./../feature-wrapper/feature-wrapper.component";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import axios from "axios";
import { setModalContext } from "../../redux/modals/modals.actions.js";
const mapStateToProps = createStructuredSelector({
printCenterModal: selectPrintCenter,
@@ -17,9 +19,25 @@ const mapStateToProps = createStructuredSelector({
technician: selectTechnician
});
const mapDispatchToProps = () => ({});
const mapDispatchToProps = (dispatch) => ({
setEsignatureContext: (context) =>
dispatch(
setModalContext({
context: context,
modal: "esignature"
})
)
});
export function PrintCenterItemComponent({ printCenterModal, item, id, bodyshop, disabled, technician }) {
export function PrintCenterItemComponent({
printCenterModal,
setEsignatureContext,
item,
id,
bodyshop,
disabled,
technician
}) {
const [loading, setLoading] = useState(false);
const { context } = printCenterModal;
const notification = useNotification();
@@ -39,6 +57,30 @@ export function PrintCenterItemComponent({ printCenterModal, item, id, bodyshop,
setLoading(false);
};
const esignatureGenerate = async () => {
setLoading(true);
try {
const {
data: { token, documentId, evnelopeId }
} = await axios.post("/esign/new", {
name: item.key,
variables: { id: id },
context,
bodyshop,
templateObject: {
name: item.key,
variables: { id: id }
}
});
setEsignatureContext({ context: { token, documentId, evnelopeId }, jobid: id });
} catch (error) {
console.log(error);
} finally {
setLoading(false);
}
};
if (
disabled ||
(item.featureNameRestricted && !HasFeatureAccess({ featureName: item.featureNameRestricted, bodyshop }))
@@ -54,6 +96,7 @@ export function PrintCenterItemComponent({ printCenterModal, item, id, bodyshop,
<li>
<Space wrap>
{item.title}
<SignatureFilled onClick={esignatureGenerate} />
<PrinterOutlined onClick={renderToNewWindow} />
{!technician ? (
<MailOutlined

View File

@@ -30,6 +30,7 @@ import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
import useAlertsNotifications from "../../hooks/useAlertsNotifications.jsx";
import { selectDarkMode } from "../../redux/application/application.selectors.js";
import { lazyDev } from "../../utils/lazyWithPreload.jsx";
import EsignatureModalContainer from "../../components/esignature-modal/esignature-modal.container.jsx";
const PrintCenterModalContainer = lazyDev(
() => import("../../components/print-center-modal/print-center-modal.container")
@@ -68,7 +69,9 @@ const FeatureRequestPage = lazyDev(() => import("../feature-request/feature-requ
const JobCostingModal = lazyDev(() => import("../../components/job-costing-modal/job-costing-modal.container"));
const ReportCenterModal = lazyDev(() => import("../../components/report-center-modal/report-center-modal.container"));
const BillEnterModalContainer = lazyDev(() => import("../../components/bill-enter-modal/bill-enter-modal.container"));
const TimeTicketModalContainer = lazyDev(() => import("../../components/time-ticket-modal/time-ticket-modal.container"));
const TimeTicketModalContainer = lazyDev(
() => import("../../components/time-ticket-modal/time-ticket-modal.container")
);
const TimeTicketModalTask = lazyDev(
() => import("../../components/time-ticket-task-modal/time-ticket-task-modal.container")
);
@@ -110,7 +113,9 @@ const TtApprovals = lazyDev(() => import("../tt-approvals/tt-approvals.page.cont
const MyTasksPage = lazyDev(() => import("../tasks/myTasksPageContainer.jsx"));
const AllTasksPage = lazyDev(() => import("../tasks/allTasksPageContainer.jsx"));
const TaskUpsertModalContainer = lazyDev(() => import("../../components/task-upsert-modal/task-upsert-modal.container"));
const TaskUpsertModalContainer = lazyDev(
() => import("../../components/task-upsert-modal/task-upsert-modal.container")
);
const { Content } = Layout;
const mapStateToProps = createStructuredSelector({
@@ -178,6 +183,7 @@ export function Manage({ conflict, bodyshop, partsManagementOnly, isDarkMode, cu
<TaskUpsertModalContainer />
<BreadCrumbs />
<BillEnterModalContainer />
<EsignatureModalContainer />
<JobCostingModal />
<ReportCenterModal />
<EmailOverlayContainer />

View File

@@ -27,7 +27,8 @@ const INITIAL_STATE = {
contractFinder: { ...baseModal },
inventoryUpsert: { ...baseModal },
ca_bc_eftTableConvert: { ...baseModal },
cardPayment: { ...baseModal }
cardPayment: { ...baseModal },
esignature: { ...baseModal }
};
const modalsReducer = (state = INITIAL_STATE, action) => {

View File

@@ -36,3 +36,4 @@ export const selectInventoryUpsert = createSelector([selectModals], (modals) =>
export const selectCaBcEtfTableConvert = createSelector([selectModals], (modals) => modals.ca_bc_eftTableConvert);
export const selectCardPayment = createSelector([selectModals], (modals) => modals.cardPayment);
export const selectEsignature = createSelector([selectModals], (modals) => modals.esignature);