Merged in feature/IO-2433-esignature (pull request #3133)
Feature/IO-2433 esignature
This commit is contained in:
11
client/package-lock.json
generated
11
client/package-lock.json
generated
@@ -16,6 +16,7 @@
|
||||
"@dnd-kit/modifiers": "^9.0.0",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@documenso/embed-react": "^0.5.1",
|
||||
"@emotion/is-prop-valid": "^1.4.0",
|
||||
"@fingerprintjs/fingerprintjs": "^5.0.1",
|
||||
"@firebase/analytics": "^0.10.19",
|
||||
@@ -2575,6 +2576,16 @@
|
||||
"react": ">=16.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@documenso/embed-react": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@documenso/embed-react/-/embed-react-0.5.1.tgz",
|
||||
"integrity": "sha512-PlkZ3vrdZVBTc0J3xfG2wtPVGmxCxWgpQ/SsdR2oBMdTwsR+rDbj9k+CeTv+M9Xi5tKbLr5Y78bS9Sb8K+ltTQ==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^18.0.0 || ^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dotenvx/dotenvx": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.52.0.tgz",
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
"@dnd-kit/modifiers": "^9.0.0",
|
||||
"@dnd-kit/sortable": "^10.0.0",
|
||||
"@dnd-kit/utilities": "^3.2.2",
|
||||
"@documenso/embed-react": "^0.5.1",
|
||||
"@emotion/is-prop-valid": "^1.4.0",
|
||||
"@fingerprintjs/fingerprintjs": "^5.0.1",
|
||||
"@firebase/analytics": "^0.10.19",
|
||||
|
||||
@@ -509,3 +509,10 @@
|
||||
pointer-events: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.esignature-embed {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-width: 0;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
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 { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
esignatureModal: selectEsignature,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
toggleModalVisible: () => dispatch(toggleModalVisible("esignature"))
|
||||
});
|
||||
|
||||
export function EsignatureModalContainer({ esignatureModal, toggleModalVisible, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
const { open, context } = esignatureModal;
|
||||
const { token, envelopeId, documentId, jobid } = context;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
title={t("jobs.labels.esignature")}
|
||||
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={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);
|
||||
}
|
||||
}}
|
||||
okButtonProps={{ title: "Distribute by Email" }}
|
||||
width="90%"
|
||||
destroyOnHidden
|
||||
>
|
||||
<div style={{ height: "600px", width: "100%" }}>
|
||||
{token ? (
|
||||
<EmbedUpdateDocumentV1
|
||||
presignToken={token}
|
||||
host="https://stg-app.documenso.com"
|
||||
documentId={documentId}
|
||||
className="esignature-embed"
|
||||
onDocumentUpdated={(data) => {
|
||||
console.log("Document updated:", data.documentId);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<div>No token...</div>
|
||||
)}
|
||||
</div>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(EsignatureModalContainer);
|
||||
@@ -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,
|
||||
jobid: 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
|
||||
|
||||
@@ -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 />
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2203,6 +2203,7 @@
|
||||
"duplicateconfirm": "Are you sure you want to duplicate this Job? Some elements of this Job will not be duplicated.",
|
||||
"emailaudit": "Email Audit Trail",
|
||||
"employeeassignments": "Employee Assignments",
|
||||
"esignature": "E-Signature",
|
||||
"estimatelines": "Estimate Lines",
|
||||
"estimator": "Estimator",
|
||||
"existing_jobs": "Existing Jobs",
|
||||
|
||||
@@ -2203,6 +2203,7 @@
|
||||
"duplicateconfirm": "",
|
||||
"emailaudit": "",
|
||||
"employeeassignments": "",
|
||||
"esignature": "",
|
||||
"estimatelines": "",
|
||||
"estimator": "",
|
||||
"existing_jobs": "Empleos existentes",
|
||||
|
||||
@@ -2203,6 +2203,7 @@
|
||||
"duplicateconfirm": "",
|
||||
"emailaudit": "",
|
||||
"employeeassignments": "",
|
||||
"esignature": "",
|
||||
"estimatelines": "",
|
||||
"estimator": "",
|
||||
"existing_jobs": "Emplois existants",
|
||||
|
||||
Reference in New Issue
Block a user