feature/IO-2433-esignature - Code review fixes
This commit is contained in:
@@ -8,6 +8,7 @@ import { createStructuredSelector } from "reselect";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -28,6 +29,10 @@ export function EsignatureCustomDocument({ bodyshop, jobId, setEsignatureContext
|
||||
const notification = useNotification();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (!hasDocumensoApiKey(bodyshop)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const uploadCustomDocument = async ({ file, onError, onSuccess }) => {
|
||||
const formData = new FormData();
|
||||
formData.append("document", file);
|
||||
|
||||
@@ -9,6 +9,7 @@ import { selectEsignature } from "../../redux/modals/modals.selectors";
|
||||
import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { useState } from "react";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
esignatureModal: selectEsignature,
|
||||
@@ -25,6 +26,11 @@ export function EsignatureModalContainer({ esignatureModal, toggleModalVisible,
|
||||
const { open, context } = esignatureModal;
|
||||
const { token, envelopeId, documentId, jobid } = context;
|
||||
const [distributing, setDistributing] = useState(false);
|
||||
|
||||
if (!hasDocumensoApiKey(bodyshop)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
|
||||
@@ -14,6 +14,7 @@ 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";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -26,6 +27,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(JobAuditTrail);
|
||||
export function JobAuditTrail({ bodyshop, jobId }) {
|
||||
const { t } = useTranslation();
|
||||
const notification = useNotification();
|
||||
const esignatureEnabled = hasDocumensoApiKey(bodyshop);
|
||||
const { loading, data, refetch } = useQuery(QUERY_AUDIT_TRAIL, {
|
||||
variables: { jobid: jobId },
|
||||
skip: !jobId,
|
||||
@@ -326,18 +328,20 @@ 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"
|
||||
scroll={{ x: true }}
|
||||
dataSource={data ? data.esignature_documents : []}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
{esignatureEnabled && (
|
||||
<Col span={24}>
|
||||
<Card title={t("jobs.labels.esignatures")}>
|
||||
<ResponsiveTable
|
||||
loading={loading}
|
||||
columns={esigColumns}
|
||||
mobileColumnKeys={["title", "status"]}
|
||||
rowKey="id"
|
||||
scroll={{ x: true }}
|
||||
dataSource={data ? data.esignature_documents : []}
|
||||
/>
|
||||
</Card>
|
||||
</Col>
|
||||
)}
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { notificationScenarios } from "../../utils/jobNotificationScenarios.js";
|
||||
import { Checkbox, Form } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import PropTypes from "prop-types";
|
||||
@@ -9,18 +8,18 @@ import PropTypes from "prop-types";
|
||||
* @param form
|
||||
* @param disabled
|
||||
* @param onHeaderChange
|
||||
* @param scenarioKeys
|
||||
* @returns {JSX.Element}
|
||||
* @constructor
|
||||
*/
|
||||
const ColumnHeaderCheckbox = ({ channel, form, disabled = false, onHeaderChange }) => {
|
||||
const ColumnHeaderCheckbox = ({ channel, form, disabled = false, onHeaderChange, scenarioKeys }) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Subscribe to all form values so that this component re-renders on changes.
|
||||
const formValues = Form.useWatch([], form) || {};
|
||||
|
||||
// Determine if all scenarios for this channel are checked.
|
||||
const allChecked =
|
||||
notificationScenarios.length > 0 && notificationScenarios.every((scenario) => formValues[scenario]?.[channel]);
|
||||
const allChecked = scenarioKeys.length > 0 && scenarioKeys.every((scenario) => formValues[scenario]?.[channel]);
|
||||
|
||||
const onChange = (e) => {
|
||||
const checked = e.target.checked;
|
||||
@@ -28,7 +27,7 @@ const ColumnHeaderCheckbox = ({ channel, form, disabled = false, onHeaderChange
|
||||
const currentValues = form.getFieldsValue();
|
||||
// Update each scenario for this channel.
|
||||
const newValues = { ...currentValues };
|
||||
notificationScenarios.forEach((scenario) => {
|
||||
scenarioKeys.forEach((scenario) => {
|
||||
newValues[scenario] = { ...newValues[scenario], [channel]: checked };
|
||||
});
|
||||
// Update form values.
|
||||
@@ -50,7 +49,8 @@ ColumnHeaderCheckbox.propTypes = {
|
||||
channel: PropTypes.oneOf(["app", "email", "fcm"]).isRequired,
|
||||
form: PropTypes.object.isRequired,
|
||||
disabled: PropTypes.bool,
|
||||
onHeaderChange: PropTypes.func
|
||||
onHeaderChange: PropTypes.func,
|
||||
scenarioKeys: PropTypes.arrayOf(PropTypes.string).isRequired
|
||||
};
|
||||
|
||||
export default ColumnHeaderCheckbox;
|
||||
|
||||
@@ -12,12 +12,13 @@ import {
|
||||
UPDATE_NOTIFICATION_SETTINGS,
|
||||
UPDATE_NOTIFICATIONS_AUTOADD
|
||||
} from "../../graphql/user.queries.js";
|
||||
import { notificationScenarios, notificationScenarioDefaults } from "../../utils/jobNotificationScenarios.js";
|
||||
import { getNotificationScenarios, notificationScenarioDefaults } from "../../utils/jobNotificationScenarios.js";
|
||||
import LoadingSpinner from "../loading-spinner/loading-spinner.component.jsx";
|
||||
import PropTypes from "prop-types";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import ColumnHeaderCheckbox from "../notification-settings/column-header-checkbox.component.jsx";
|
||||
import { useIsEmployee } from "../../utils/useIsEmployee.js";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
/**
|
||||
* Notifications Settings Form
|
||||
@@ -35,6 +36,7 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
const [initialAutoAdd, setInitialAutoAdd] = useState(false);
|
||||
const notification = useNotification();
|
||||
const isEmployee = useIsEmployee(bodyshop, currentUser);
|
||||
const notificationScenarios = getNotificationScenarios({ includeEsign: hasDocumensoApiKey(bodyshop) });
|
||||
|
||||
// Fetch notification settings and notifications_autoadd
|
||||
const { loading, error, data } = useQuery(QUERY_NOTIFICATION_SETTINGS, {
|
||||
@@ -66,7 +68,7 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
setInitialAutoAdd(autoAdd);
|
||||
setIsDirty(false); // Reset dirty state when new data loads
|
||||
}
|
||||
}, [data, form]);
|
||||
}, [data, form, notificationScenarios]);
|
||||
|
||||
// Handle toggle of notifications_autoadd
|
||||
const handleAutoAddToggle = async (checked) => {
|
||||
@@ -137,7 +139,14 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
width: "80%"
|
||||
},
|
||||
{
|
||||
title: <ColumnHeaderCheckbox channel="app" form={form} onHeaderChange={() => setIsDirty(true)} />,
|
||||
title: (
|
||||
<ColumnHeaderCheckbox
|
||||
channel="app"
|
||||
form={form}
|
||||
onHeaderChange={() => setIsDirty(true)}
|
||||
scenarioKeys={notificationScenarios}
|
||||
/>
|
||||
),
|
||||
dataIndex: "app",
|
||||
key: "app",
|
||||
align: "center",
|
||||
@@ -148,7 +157,14 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
)
|
||||
},
|
||||
{
|
||||
title: <ColumnHeaderCheckbox channel="email" form={form} onHeaderChange={() => setIsDirty(true)} />,
|
||||
title: (
|
||||
<ColumnHeaderCheckbox
|
||||
channel="email"
|
||||
form={form}
|
||||
onHeaderChange={() => setIsDirty(true)}
|
||||
scenarioKeys={notificationScenarios}
|
||||
/>
|
||||
),
|
||||
dataIndex: "email",
|
||||
key: "email",
|
||||
align: "center",
|
||||
@@ -163,7 +179,14 @@ const NotificationSettingsForm = ({ currentUser, bodyshop }) => {
|
||||
// Currently disabled for prod
|
||||
if (!import.meta.env.PROD) {
|
||||
columns.push({
|
||||
title: <ColumnHeaderCheckbox channel="fcm" form={form} onHeaderChange={() => setIsDirty(true)} />,
|
||||
title: (
|
||||
<ColumnHeaderCheckbox
|
||||
channel="fcm"
|
||||
form={form}
|
||||
onHeaderChange={() => setIsDirty(true)}
|
||||
scenarioKeys={notificationScenarios}
|
||||
/>
|
||||
),
|
||||
dataIndex: "fcm",
|
||||
key: "fcm",
|
||||
align: "center",
|
||||
|
||||
@@ -12,6 +12,7 @@ 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";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
printCenterModal: selectPrintCenter,
|
||||
@@ -41,6 +42,7 @@ export function PrintCenterItemComponent({
|
||||
const [loading, setLoading] = useState(false);
|
||||
const { context } = printCenterModal;
|
||||
const notification = useNotification();
|
||||
const esignatureEnabled = hasDocumensoApiKey(bodyshop);
|
||||
|
||||
const renderToNewWindow = async () => {
|
||||
setLoading(true);
|
||||
@@ -96,7 +98,7 @@ export function PrintCenterItemComponent({
|
||||
<li>
|
||||
<Space wrap>
|
||||
{item.title}
|
||||
<SignatureFilled onClick={esignatureGenerate} />
|
||||
{esignatureEnabled && <SignatureFilled onClick={esignatureGenerate} />}
|
||||
<PrinterOutlined onClick={renderToNewWindow} />
|
||||
{!technician ? (
|
||||
<MailOutlined
|
||||
|
||||
@@ -15,6 +15,7 @@ import PrintCenterJobsLabels from "../print-center-jobs-labels/print-center-jobs
|
||||
import PrintCenterSpeedPrint from "../print-center-speed-print/print-center-speed-print.component";
|
||||
import { bodyshopHasDmsKey, DMS_MAP, getDmsMode } from "../../utils/dmsUtils";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { hasDocumensoApiKey } from "../../utils/esignature.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
printCenterModal: selectPrintCenter,
|
||||
@@ -39,6 +40,7 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop, technicia
|
||||
const hasDMSKey = bodyshopHasDmsKey(bodyshop);
|
||||
const dmsMode = getDmsMode(bodyshop, "off");
|
||||
const isReynoldsMode = dmsMode === DMS_MAP.reynolds;
|
||||
const esignatureEnabled = hasDocumensoApiKey(bodyshop);
|
||||
|
||||
const Templates = !hasDMSKey
|
||||
? Object.keys(tempList)
|
||||
@@ -98,7 +100,7 @@ export function PrintCenterJobsComponent({ printCenterModal, bodyshop, technicia
|
||||
extra={
|
||||
<Space wrap>
|
||||
<PrintCenterJobsLabels jobId={jobId} />
|
||||
<EsignatureCustomDocument jobId={jobId} />
|
||||
{esignatureEnabled && <EsignatureCustomDocument jobId={jobId} />}
|
||||
<Jobd3RdPartyModal jobId={jobId} job={job} />
|
||||
<Input.Search onChange={(e) => setSearch(e.target.value)} value={search} enterButton />
|
||||
</Space>
|
||||
|
||||
Reference in New Issue
Block a user