IO-3020 IO-3036 Update job actions menu & improve feature wrapper/blur wrapper trace
This commit is contained in:
@@ -4,7 +4,7 @@ import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
import { Button, Card, Dropdown, Form, Input, Modal, notification, Popconfirm, Popover, Select, Space } from "antd";
|
||||
import axios from "axios";
|
||||
import parsePhoneNumber from "libphonenumber-js";
|
||||
import React, { useMemo, useState } from "react";
|
||||
import { useMemo, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
@@ -23,9 +23,9 @@ import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import dayjs from "../../utils/day";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||
import FormDateTimePickerComponent from "../form-date-time-picker/form-date-time-picker.component";
|
||||
import LockerWrapperComponent from "../lock-wrapper/lock-wrapper.component";
|
||||
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
||||
import AddToProduction from "./jobs-detail-header-actions.addtoproduction.util";
|
||||
import DuplicateJob from "./jobs-detail-header-actions.duplicate.util";
|
||||
@@ -196,6 +196,7 @@ export function JobsDetailHeaderActions({
|
||||
message: t("appointments.successes.created")
|
||||
});
|
||||
} catch (error) {
|
||||
notification.open({ type: "error", message: t("appointments.errors.saving", { error: error.message }) });
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setVisibility(false);
|
||||
@@ -206,7 +207,7 @@ export function JobsDetailHeaderActions({
|
||||
//delete the job.
|
||||
const result = await deleteJob({ variables: { id: job.id } });
|
||||
|
||||
if (!!!result.errors) {
|
||||
if (!result.errors) {
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.delete")
|
||||
});
|
||||
@@ -264,7 +265,7 @@ export function JobsDetailHeaderActions({
|
||||
awaitRefetchQueries: true
|
||||
});
|
||||
|
||||
if (!!!result.errors) {
|
||||
if (!result.errors) {
|
||||
notification["success"]({ message: t("csi.successes.created") });
|
||||
} else {
|
||||
notification["error"]({
|
||||
@@ -385,7 +386,7 @@ export function JobsDetailHeaderActions({
|
||||
}
|
||||
});
|
||||
|
||||
if (!!!result.errors) {
|
||||
if (!result.errors) {
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.voided")
|
||||
});
|
||||
@@ -405,7 +406,7 @@ export function JobsDetailHeaderActions({
|
||||
}
|
||||
};
|
||||
|
||||
const handleExportCustData = async (e) => {
|
||||
const handleExportCustData = async () => {
|
||||
logImEXEvent("job_export_cust_data");
|
||||
let PartnerResponse;
|
||||
if (bodyshop.accountingconfig && bodyshop.accountingconfig.qbo) {
|
||||
@@ -482,7 +483,7 @@ export function JobsDetailHeaderActions({
|
||||
}
|
||||
};
|
||||
|
||||
const handleAlertToggle = (e) => {
|
||||
const handleAlertToggle = () => {
|
||||
logImEXEvent("production_toggle_alert");
|
||||
//e.stopPropagation();
|
||||
updateJob({
|
||||
@@ -505,7 +506,7 @@ export function JobsDetailHeaderActions({
|
||||
});
|
||||
};
|
||||
|
||||
const handleSuspend = (e) => {
|
||||
const handleSuspend = () => {
|
||||
logImEXEvent("production_toggle_alert");
|
||||
//e.stopPropagation();
|
||||
updateJob({
|
||||
@@ -518,7 +519,7 @@ export function JobsDetailHeaderActions({
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobsuspend(!!job.suspended ? !job.suspended : true),
|
||||
operation: AuditTrailMapping.jobsuspend(job.suspended ? !job.suspended : true),
|
||||
type: "jobsuspend"
|
||||
});
|
||||
};
|
||||
@@ -599,7 +600,7 @@ export function JobsDetailHeaderActions({
|
||||
required: true
|
||||
//message: t("general.validation.required"),
|
||||
},
|
||||
({ getFieldValue }) => ({
|
||||
() => ({
|
||||
async validator(rule, value) {
|
||||
if (value) {
|
||||
const { start } = form.getFieldsValue();
|
||||
@@ -668,75 +669,73 @@ export function JobsDetailHeaderActions({
|
||||
disabled: job.status !== bodyshop.md_ro_statuses.default_scheduled,
|
||||
label: t("menus.jobsactions.cancelallappointments")
|
||||
},
|
||||
...InstanceRenderManager({
|
||||
imex: [
|
||||
...(HasFeatureAccess({ featureName: "checklist", bodyshop })
|
||||
? [
|
||||
{
|
||||
key: "intake",
|
||||
id: "job-actions-intake",
|
||||
disabled: !!job.intakechecklist || !jobInPreProduction || !job.converted || jobRO,
|
||||
label:
|
||||
!!job.intakechecklist || !jobInPreProduction || !job.converted || jobRO ? (
|
||||
t("jobs.actions.intake")
|
||||
) : (
|
||||
<Link to={`/manage/jobs/${job.id}/intake`}>{t("jobs.actions.intake")}</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "deliver",
|
||||
id: "job-actions-deliver",
|
||||
disabled: !jobInProduction || jobRO,
|
||||
label: !jobInProduction ? (
|
||||
t("jobs.actions.deliver")
|
||||
) : (
|
||||
<Link to={`/manage/jobs/${job.id}/deliver`}>{t("jobs.actions.deliver")}</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "checklist",
|
||||
id: "job-actions-checklist",
|
||||
disabled: !job.converted,
|
||||
label: <Link to={`/manage/jobs/${job.id}/checklist`}>{t("jobs.actions.viewchecklist")}</Link>
|
||||
}
|
||||
]
|
||||
: [
|
||||
{
|
||||
key: "toggleproduction",
|
||||
id: "job-actions-toggleproduction",
|
||||
disabled: !job.converted || jobRO,
|
||||
label: <JobsDetailHeaderActionsToggleProduction job={job} refetch={refetch} />
|
||||
}
|
||||
])
|
||||
],
|
||||
rome: "USE_IMEX"
|
||||
}),
|
||||
...(InstanceRenderManager({
|
||||
imex: HasFeatureAccess({ featureName: "timetickets", bodyshop }),
|
||||
rome: "USE_IMEX"
|
||||
})
|
||||
? [
|
||||
{
|
||||
key: "entertimetickets",
|
||||
id: "job-actions-entertimetickets",
|
||||
disabled: !job.converted || (!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced),
|
||||
label: t("timetickets.actions.enter"),
|
||||
onClick: () => {
|
||||
logImEXEvent("job_header_enter_time_ticekts");
|
||||
{
|
||||
key: "intake",
|
||||
id: "job-actions-intake",
|
||||
disabled: !!job.intakechecklist || !jobInPreProduction || !job.converted || jobRO,
|
||||
label:
|
||||
!!job.intakechecklist || !jobInPreProduction || !job.converted || jobRO ? (
|
||||
<LockerWrapperComponent featureName="checklist">{t("jobs.actions.intake")}</LockerWrapperComponent>
|
||||
) : (
|
||||
<Link to={`/manage/jobs/${job.id}/intake`}>
|
||||
<LockerWrapperComponent featureName="checklist">{t("jobs.actions.intake")}</LockerWrapperComponent>
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "deliver",
|
||||
id: "job-actions-deliver",
|
||||
disabled: !jobInProduction || jobRO,
|
||||
label: !jobInProduction ? (
|
||||
<LockerWrapperComponent disabled featureName="checklist">
|
||||
{t("jobs.actions.deliver")}
|
||||
</LockerWrapperComponent>
|
||||
) : (
|
||||
<Link to={`/manage/jobs/${job.id}/deliver`}>
|
||||
<LockerWrapperComponent disabled featureName="checklist">
|
||||
{t("jobs.actions.deliver")}{" "}
|
||||
</LockerWrapperComponent>
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "checklist",
|
||||
id: "job-actions-checklist",
|
||||
disabled: !job.converted,
|
||||
label: (
|
||||
<Link to={`/manage/jobs/${job.id}/checklist`}>
|
||||
<LockerWrapperComponent featureName="checklist">{t("jobs.actions.viewchecklist")}</LockerWrapperComponent>
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "toggleproduction",
|
||||
id: "job-actions-toggleproduction",
|
||||
disabled: !job.converted || jobRO,
|
||||
label: <JobsDetailHeaderActionsToggleProduction job={job} refetch={refetch} />
|
||||
},
|
||||
|
||||
setTimeTicketContext({
|
||||
actions: {},
|
||||
context: {
|
||||
jobId: job.id,
|
||||
created_by: currentUser.displayName
|
||||
? currentUser.email.concat(" | ", currentUser.displayName)
|
||||
: currentUser.email
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
key: "entertimetickets",
|
||||
id: "job-actions-entertimetickets",
|
||||
disabled: !job.converted || (!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced),
|
||||
label: (
|
||||
<LockerWrapperComponent featureName="timetickets">{t("timetickets.actions.enter")}</LockerWrapperComponent>
|
||||
),
|
||||
onClick: () => {
|
||||
logImEXEvent("job_header_enter_time_ticekts");
|
||||
|
||||
setTimeTicketContext({
|
||||
actions: {},
|
||||
context: {
|
||||
jobId: job.id,
|
||||
created_by: currentUser.displayName
|
||||
? currentUser.email.concat(" | ", currentUser.displayName)
|
||||
: currentUser.email
|
||||
}
|
||||
]
|
||||
: [])
|
||||
});
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
if (bodyshop.md_tasks_presets.enable_tasks) {
|
||||
@@ -758,7 +757,7 @@ export function JobsDetailHeaderActions({
|
||||
key: "enterpayments",
|
||||
id: "job-actions-enterpayments",
|
||||
disabled: !job.converted,
|
||||
label: t("menus.header.enterpayment"),
|
||||
label: <LockerWrapperComponent featureName="payments">{t("menus.header.enterpayment")}</LockerWrapperComponent>,
|
||||
onClick: () => {
|
||||
logImEXEvent("job_header_enter_payment");
|
||||
|
||||
@@ -786,18 +785,18 @@ export function JobsDetailHeaderActions({
|
||||
});
|
||||
}
|
||||
|
||||
if (HasFeatureAccess({ featureName: "courtesycars", bodyshop })) {
|
||||
menuItems.push({
|
||||
key: "cccontract",
|
||||
id: "job-actions-cccontract",
|
||||
disabled: jobRO || !job.converted,
|
||||
label: (
|
||||
<Link state={{ jobId: job.id }} to="/manage/courtesycars/contracts/new">
|
||||
menuItems.push({
|
||||
key: "cccontract",
|
||||
id: "job-actions-cccontract",
|
||||
disabled: jobRO || !job.converted,
|
||||
label: (
|
||||
<Link state={{ jobId: job.id }} to="/manage/courtesycars/contracts/new">
|
||||
<LockerWrapperComponent featureName="courtesycars">
|
||||
{t("menus.jobsactions.newcccontract")}
|
||||
</Link>
|
||||
)
|
||||
});
|
||||
}
|
||||
</LockerWrapperComponent>
|
||||
</Link>
|
||||
)
|
||||
});
|
||||
|
||||
menuItems.push({
|
||||
key: "createtask",
|
||||
@@ -882,29 +881,23 @@ export function JobsDetailHeaderActions({
|
||||
}
|
||||
]
|
||||
},
|
||||
...(InstanceRenderManager({
|
||||
imex: HasFeatureAccess({ featureName: "bills", bodyshop }),
|
||||
rome: "USE_IMEX"
|
||||
})
|
||||
? [
|
||||
{
|
||||
key: "postbills",
|
||||
id: "job-actions-postbills",
|
||||
disabled: !job.converted,
|
||||
label: t("jobs.actions.postbills"),
|
||||
onClick: () => {
|
||||
logImEXEvent("job_header_enter_bills");
|
||||
|
||||
setBillEnterContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
job: job
|
||||
}
|
||||
});
|
||||
}
|
||||
{
|
||||
key: "postbills",
|
||||
id: "job-actions-postbills",
|
||||
disabled: !job.converted,
|
||||
label: <LockerWrapperComponent featureName="bill">{t("jobs.actions.postbills")}</LockerWrapperComponent>,
|
||||
onClick: () => {
|
||||
logImEXEvent("job_header_enter_bills");
|
||||
|
||||
setBillEnterContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
job: job
|
||||
}
|
||||
]
|
||||
: []),
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
key: "addtopartsqueue",
|
||||
@@ -919,7 +912,7 @@ export function JobsDetailHeaderActions({
|
||||
}
|
||||
});
|
||||
|
||||
if (!!!result.errors) {
|
||||
if (!result.errors) {
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.partsqueue")
|
||||
});
|
||||
@@ -963,79 +956,70 @@ export function JobsDetailHeaderActions({
|
||||
}
|
||||
);
|
||||
|
||||
if (
|
||||
InstanceRenderManager({
|
||||
imex: HasFeatureAccess({ featureName: "export", bodyshop }),
|
||||
rome: "USE_IMEX"
|
||||
})
|
||||
) {
|
||||
menuItems.push({
|
||||
key: "exportcustdata",
|
||||
id: "job-actions-exportcustdata",
|
||||
disabled: !job.converted,
|
||||
label: t("jobs.actions.exportcustdata"),
|
||||
onClick: handleExportCustData
|
||||
});
|
||||
}
|
||||
menuItems.push({
|
||||
key: "exportcustdata",
|
||||
id: "job-actions-exportcustdata",
|
||||
disabled: !(job.converted && HasFeatureAccess({ bodyshop, featureName: "export", debug: true })),
|
||||
label: <LockerWrapperComponent featureName="export">{t("jobs.actions.exportcustdata")}</LockerWrapperComponent>,
|
||||
onClick: handleExportCustData
|
||||
});
|
||||
|
||||
if (HasFeatureAccess({ featureName: "csi", bodyshop })) {
|
||||
const children = [
|
||||
{
|
||||
key: "email",
|
||||
id: "job-actions-email",
|
||||
disabled: !!!job.ownr_ea,
|
||||
label: t("general.labels.email"),
|
||||
onClick: handleCreateCsi
|
||||
},
|
||||
{
|
||||
key: "text",
|
||||
id: "job-actions-text",
|
||||
disabled: !!!job.ownr_ph1,
|
||||
label: t("general.labels.text"),
|
||||
onClick: handleCreateCsi
|
||||
},
|
||||
{
|
||||
key: "generate",
|
||||
id: "job-actions-generate",
|
||||
disabled: job.csiinvites && job.csiinvites.length > 0,
|
||||
label: t("jobs.actions.generatecsi"),
|
||||
onClick: handleCreateCsi
|
||||
}
|
||||
];
|
||||
|
||||
if (job?.csiinvites?.length) {
|
||||
children.push(
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
...job.csiinvites.map((item, idx) => {
|
||||
return item.completedon
|
||||
? {
|
||||
key: idx,
|
||||
label: (
|
||||
<Link to={`/manage/shop/csi?responseid=${item.id}`}>
|
||||
<DateTimeFormatter>{item.completedon}</DateTimeFormatter>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
: {
|
||||
key: idx,
|
||||
onClick: () => {
|
||||
navigator.clipboard.writeText(`${window.location.protocol}//${window.location.host}/csi/${item.id}`);
|
||||
},
|
||||
label: t("general.actions.copylink")
|
||||
};
|
||||
})
|
||||
);
|
||||
const children = [
|
||||
{
|
||||
key: "email",
|
||||
id: "job-actions-email",
|
||||
disabled: !(job.ownr_ea && HasFeatureAccess({ bodyshop, featureName: "csi", debug: true })),
|
||||
label: <LockerWrapperComponent featureName="checklist">{t("general.labels.email")}</LockerWrapperComponent>,
|
||||
onClick: handleCreateCsi
|
||||
},
|
||||
{
|
||||
key: "text",
|
||||
id: "job-actions-text",
|
||||
disabled: !(job.ownr_ph1 && HasFeatureAccess({ bodyshop, featureName: "csi", debug: true })),
|
||||
label: <LockerWrapperComponent featureName="checklist">{t("general.labels.text")}</LockerWrapperComponent>,
|
||||
onClick: handleCreateCsi
|
||||
},
|
||||
{
|
||||
key: "generate",
|
||||
id: "job-actions-generate",
|
||||
disabled: job.csiinvites?.length > 0 || !HasFeatureAccess({ bodyshop, featureName: "csi", debug: true }),
|
||||
label: <LockerWrapperComponent featureName="checklist">{t("jobs.actions.generatecsi")}</LockerWrapperComponent>,
|
||||
onClick: handleCreateCsi
|
||||
}
|
||||
menuItems.push({
|
||||
key: "sendcsi",
|
||||
id: "job-actions-sendcsi",
|
||||
label: t("jobs.actions.sendcsi"),
|
||||
disabled: !job.converted,
|
||||
children
|
||||
});
|
||||
];
|
||||
|
||||
if (job?.csiinvites?.length) {
|
||||
children.push(
|
||||
{
|
||||
type: "divider"
|
||||
},
|
||||
...job.csiinvites.map((item, idx) => {
|
||||
return item.completedon
|
||||
? {
|
||||
key: idx,
|
||||
label: (
|
||||
<Link to={`/manage/shop/csi?responseid=${item.id}`}>
|
||||
<DateTimeFormatter>{item.completedon}</DateTimeFormatter>
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
: {
|
||||
key: idx,
|
||||
onClick: () => {
|
||||
navigator.clipboard.writeText(`${window.location.protocol}//${window.location.host}/csi/${item.id}`);
|
||||
},
|
||||
label: t("general.actions.copylink")
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
menuItems.push({
|
||||
key: "sendcsi",
|
||||
id: "job-actions-sendcsi",
|
||||
label: <LockerWrapperComponent featureName="checklist">{t("jobs.actions.sendcsi")}</LockerWrapperComponent>,
|
||||
disabled: !job.converted,
|
||||
children
|
||||
});
|
||||
|
||||
menuItems.push({
|
||||
key: "jobcosting",
|
||||
@@ -1075,7 +1059,7 @@ export function JobsDetailHeaderActions({
|
||||
menuItems.push({
|
||||
key: "manualevent",
|
||||
id: "job-actions-manualevent",
|
||||
onClick: (e) => {
|
||||
onClick: () => {
|
||||
setVisibility(true);
|
||||
},
|
||||
label: t("appointments.labels.manualevent")
|
||||
|
||||
@@ -168,8 +168,8 @@ export function JobsDetailHeaderActionsToggleProduction({ bodyshop, job, jobRO,
|
||||
getPopupContainer={(trigger) => trigger.parentNode}
|
||||
trigger="click"
|
||||
>
|
||||
{scenario === "pre" && t("jobs.actions.intake")}
|
||||
{scenario === "prod" && t("jobs.actions.deliver")}
|
||||
{scenario === "pre" && t("jobs.actions.intake_quick")}
|
||||
{scenario === "prod" && t("jobs.actions.deliver_quick")}
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user