Eisgnature Migrations, webhook handling, and clean up.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { EmbedUpdateDocumentV1 } from "@documenso/embed-react";
|
||||
import { Modal } from "antd";
|
||||
import { Modal, notification } from "antd";
|
||||
import axios from "axios";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -7,6 +7,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import { toggleModalVisible } from "../../redux/modals/modals.actions";
|
||||
import { selectEsignature } from "../../redux/modals/modals.selectors";
|
||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { useState } from "react";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
esignatureModal: selectEsignature,
|
||||
@@ -22,13 +23,14 @@ export function EsignatureModalContainer({ esignatureModal, toggleModalVisible,
|
||||
const { t } = useTranslation();
|
||||
const { open, context } = esignatureModal;
|
||||
const { token, envelopeId, documentId, jobid } = context;
|
||||
|
||||
const [distributing, setDistributing] = useState(false);
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
title={t("jobs.labels.esignature")}
|
||||
onOk={async () => {
|
||||
try {
|
||||
setDistributing(true);
|
||||
const distResult = await axios.post("/esign/distribute", {
|
||||
documentId,
|
||||
envelopeId,
|
||||
@@ -39,7 +41,12 @@ export function EsignatureModalContainer({ esignatureModal, toggleModalVisible,
|
||||
toggleModalVisible();
|
||||
} catch (error) {
|
||||
console.error("Error distributing document:", error);
|
||||
notification.error({
|
||||
message: t("esignature.distribute_error"),
|
||||
description: error?.response?.data?.message || error.message
|
||||
});
|
||||
}
|
||||
setDistributing(false);
|
||||
}}
|
||||
onCancel={async () => {
|
||||
try {
|
||||
@@ -51,11 +58,16 @@ export function EsignatureModalContainer({ esignatureModal, toggleModalVisible,
|
||||
toggleModalVisible();
|
||||
} catch (error) {
|
||||
console.error("Error cancelling document:", error);
|
||||
notification.error({
|
||||
message: t("esignature.cancel_error"),
|
||||
description: error?.response?.data?.message || error.message
|
||||
});
|
||||
}
|
||||
}}
|
||||
okButtonProps={{ title: "Distribute by Email" }}
|
||||
width="90%"
|
||||
okButtonProps={{ loading: distributing }}
|
||||
okText={t("esignature.actions.distribute")}
|
||||
destroyOnHidden
|
||||
width={800}
|
||||
>
|
||||
<div style={{ height: "600px", width: "100%" }}>
|
||||
{token ? (
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import { useQuery } from "@apollo/client/react";
|
||||
import { Button, Card, Col, Row, Tag } from "antd";
|
||||
import { Button, Card, Checkbox, Col, Row, Space, Tag } from "antd";
|
||||
import ResponsiveTable from "../responsive-table/responsive-table.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
@@ -12,6 +12,8 @@ import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import BlurWrapperComponent from "../feature-wrapper/blur-wrapper.component";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../upsell/upsell.component";
|
||||
import axios from "axios";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -23,6 +25,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(JobAuditTrail);
|
||||
|
||||
export function JobAuditTrail({ bodyshop, jobId }) {
|
||||
const { t } = useTranslation();
|
||||
const notification = useNotification();
|
||||
const { loading, data, refetch } = useQuery(QUERY_AUDIT_TRAIL, {
|
||||
variables: { jobid: jobId },
|
||||
skip: !jobId,
|
||||
@@ -53,6 +56,125 @@ export function JobAuditTrail({ bodyshop, jobId }) {
|
||||
)
|
||||
}
|
||||
];
|
||||
const esigColumns = [
|
||||
{
|
||||
title: t("audit.fields.created_at"),
|
||||
dataIndex: "created_at",
|
||||
key: "created_at",
|
||||
render: (text) => <DateTimeFormatter>{text}</DateTimeFormatter>
|
||||
},
|
||||
{
|
||||
title: t("audit.fields.updated_at"),
|
||||
dataIndex: "updated_at",
|
||||
key: "updated_at",
|
||||
render: (text) => <DateTimeFormatter>{text}</DateTimeFormatter>
|
||||
},
|
||||
{
|
||||
title: t("audit.fields.title"),
|
||||
dataIndex: "title",
|
||||
key: "title",
|
||||
render: (text) => (
|
||||
<BlurWrapperComponent featureName="audit" bypass>
|
||||
<div>{text}</div>
|
||||
</BlurWrapperComponent>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("audit.fields.external_document_id"),
|
||||
dataIndex: "external_document_id",
|
||||
key: "external_document_id",
|
||||
render: (text) => (
|
||||
<BlurWrapperComponent featureName="audit" bypass>
|
||||
<div>{text}</div>
|
||||
</BlurWrapperComponent>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("audit.fields.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
render: (text) => (
|
||||
<BlurWrapperComponent featureName="audit" bypass>
|
||||
<div>{text}</div>
|
||||
</BlurWrapperComponent>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("audit.fields.opened"),
|
||||
dataIndex: "opened",
|
||||
key: "opened",
|
||||
render: (text) => <Checkbox checked={text} disabled />
|
||||
},
|
||||
{
|
||||
title: t("audit.fields.rejected"),
|
||||
dataIndex: "rejected",
|
||||
key: "rejected",
|
||||
render: (text) => <Checkbox checked={text} disabled />
|
||||
},
|
||||
{
|
||||
title: t("audit.fields.completed"),
|
||||
dataIndex: "completed",
|
||||
key: "completed",
|
||||
render: (text) => <Checkbox checked={text} disabled />
|
||||
},
|
||||
{
|
||||
title: t("audit.fields.completed_at"),
|
||||
dataIndex: "completed_at",
|
||||
key: "completed_at",
|
||||
render: (text) => <DateTimeFormatter>{text}</DateTimeFormatter>
|
||||
},
|
||||
{
|
||||
title: t("general.labels.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (_text, record) => (
|
||||
<Space wrap>
|
||||
<Button
|
||||
disabled={record.completed_at !== null || record.status === "REJECTED"}
|
||||
onClick={async () => {
|
||||
logImEXEvent("job_esig_delete", {});
|
||||
try {
|
||||
const deleteResult = await axios.post("/esign/delete", {
|
||||
documentId: record.external_document_id
|
||||
});
|
||||
console.log("*** ~ JobAuditTrail ~ deleteResult:", deleteResult);
|
||||
refetch();
|
||||
} catch (error) {
|
||||
console.error("Error deleting document:", error?.response?.data || error.message);
|
||||
notification.error({
|
||||
message: t("esignature.delete_error"),
|
||||
description: error?.response?.data?.error || error.message
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
{t("esignature.actions.delete")}
|
||||
</Button>
|
||||
<Button onClick={() => console.log(record)}>{t("esignature.actions.resend")}</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
axios
|
||||
.post("/esign/view", {
|
||||
documentId: record.external_document_id
|
||||
})
|
||||
.then((response) => {
|
||||
window.open(response.data?.document?.downloadUrl, "_blank");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("Error viewing document:", error?.response?.data || error.message);
|
||||
notification.error({
|
||||
message: t("esignature.view_error"),
|
||||
description: error?.response?.data?.message || error.message
|
||||
});
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("esignature.actions.view")}
|
||||
</Button>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
];
|
||||
const emailColumns = [
|
||||
{
|
||||
title: t("audit.fields.created"),
|
||||
@@ -184,6 +306,17 @@ export function JobAuditTrail({ bodyshop, jobId }) {
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Card title={t("jobs.labels.esignatures")}>
|
||||
<ResponsiveTable
|
||||
loading={loading}
|
||||
columns={esigColumns}
|
||||
mobileColumnKeys={["title", "status"]}
|
||||
rowKey="id"
|
||||
dataSource={data ? data.esignature_documents : []}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,23 @@ export const QUERY_AUDIT_TRAIL = gql`
|
||||
useremail
|
||||
status
|
||||
}
|
||||
esignature_documents(where: {jobid: {_eq: $jobid}}) {
|
||||
id
|
||||
created_at
|
||||
updated_at
|
||||
jobid
|
||||
external_document_id
|
||||
subject
|
||||
message
|
||||
title
|
||||
status
|
||||
recipients
|
||||
completed_at
|
||||
opened
|
||||
completed
|
||||
rejected
|
||||
completed_at
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
|
||||
@@ -1239,6 +1239,11 @@
|
||||
"unique_employee_number": "You must enter a unique employee number."
|
||||
}
|
||||
},
|
||||
"esignature": {
|
||||
"actions": {
|
||||
"distribute": "Distribute"
|
||||
}
|
||||
},
|
||||
"eula": {
|
||||
"buttons": {
|
||||
"accept": "Accept EULA"
|
||||
|
||||
@@ -1239,6 +1239,11 @@
|
||||
"unique_employee_number": ""
|
||||
}
|
||||
},
|
||||
"esignature": {
|
||||
"actions": {
|
||||
"distribute": ""
|
||||
}
|
||||
},
|
||||
"eula": {
|
||||
"buttons": {
|
||||
"accept": "Accept EULA"
|
||||
|
||||
@@ -1239,6 +1239,11 @@
|
||||
"unique_employee_number": ""
|
||||
}
|
||||
},
|
||||
"esignature": {
|
||||
"actions": {
|
||||
"distribute": ""
|
||||
}
|
||||
},
|
||||
"eula": {
|
||||
"buttons": {
|
||||
"accept": "Accept EULA"
|
||||
|
||||
Reference in New Issue
Block a user