diff --git a/client/package.json b/client/package.json index 85b34916e..f752db97b 100644 --- a/client/package.json +++ b/client/package.json @@ -12,7 +12,7 @@ "@sentry/tracing": "^7.28.1", "@splitsoftware/splitio-react": "^1.6.0", "@tanem/react-nprogress": "^5.0.8", - "antd": "^4.22.3", + "antd": "4.24.5", "apollo-link-logger": "^2.0.0", "axios": "^1.2.2", "craco-less": "^2.0.0", diff --git a/client/src/components/chat-presets/chat-presets.component.jsx b/client/src/components/chat-presets/chat-presets.component.jsx index 74e1a0dd6..16b11de15 100644 --- a/client/src/components/chat-presets/chat-presets.component.jsx +++ b/client/src/components/chat-presets/chat-presets.component.jsx @@ -16,19 +16,15 @@ const mapDispatchToProps = (dispatch) => ({ }); export function ChatPresetsComponent({ bodyshop, setMessage, className }) { - const menu = ( - - {bodyshop.md_messaging_presets.map((i, idx) => ( - setMessage(i.text)} key={idx}> - {i.label} - - ))} - - ); + const menu = bodyshop.md_messaging_presets.map((i, idx) => ({ + label: i.label, + key: idx, + onClick: () => setMessage(i.text), + })); return (
- +
diff --git a/client/src/components/contracts-rates-change-button/contracts-rates-change-button.component.jsx b/client/src/components/contracts-rates-change-button/contracts-rates-change-button.component.jsx index 08e50e6c1..865878ff8 100644 --- a/client/src/components/contracts-rates-change-button/contracts-rates-change-button.component.jsx +++ b/client/src/components/contracts-rates-change-button/contracts-rates-change-button.component.jsx @@ -13,25 +13,14 @@ const mapStateToProps = createStructuredSelector({ export function ContractsRatesChangeButton({ disabled, form, bodyshop }) { const { t } = useTranslation(); - const handleClick = ({ item, key, keyPath }) => { - const { label, ...rate } = item.props.value; - form.setFieldsValue(rate); - }; - - const menu = ( -
- - {bodyshop.md_ccc_rates.map((rate, idx) => ( - - {rate.label} - - ))} - -
- ); + const menu = bodyshop.md_ccc_rates.map((rate, idx) => ({ + onClick: () => form.setFieldsValue(rate), + key: idx, + label: rate.label, + })); return ( - + - + menu={{ + items: [ + { + label: t( + "printcenter.courtesycarcontract.courtesy_car_inventory" + ), + key: "cc_inv", + onClick: () => GenerateDocument( { name: TemplateList("courtesycar").courtesy_car_inventory @@ -193,13 +197,10 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) { }, {}, "p" - ) - } - > - {t("printcenter.courtesycarcontract.courtesy_car_inventory")} - - - } + ), + }, + ], + }} > diff --git a/client/src/components/dashboard-grid/dashboard-grid.component.jsx b/client/src/components/dashboard-grid/dashboard-grid.component.jsx index 39a5432c2..b7bdcf0cd 100644 --- a/client/src/components/dashboard-grid/dashboard-grid.component.jsx +++ b/client/src/components/dashboard-grid/dashboard-grid.component.jsx @@ -117,17 +117,15 @@ export function DashboardGridComponent({ currentUser, bodyshop }) { ); const existingLayoutKeys = state.items.map((i) => i.i); const addComponentOverlay = ( - - {Object.keys(componentList).map((key) => ( - - {componentList[key].label} - - ))} - + ({ + key: key, + value: key, + disabled: existingLayoutKeys.includes(key), + label: componentList[key].label, + }))} + > ); if (error) return ; @@ -283,8 +281,12 @@ const createDashboardQuery = (state) => { monthly_sales: jobs(where: {_and: [ { voided: {_eq: false}}, {date_invoiced: {_gte: "${moment() - .startOf("month").startOf('day').toISOString()}"}}, {date_invoiced: {_lte: "${moment() - .endOf("month").endOf('day').toISOString()}"}}]}) { + .startOf("month") + .startOf("day") + .toISOString()}"}}, {date_invoiced: {_lte: "${moment() + .endOf("month") + .endOf("day") + .toISOString()}"}}]}) { id ro_number date_invoiced diff --git a/client/src/components/dms-post-form/dms-post-form.component.jsx b/client/src/components/dms-post-form/dms-post-form.component.jsx index c9043d050..56179729b 100644 --- a/client/src/components/dms-post-form/dms-post-form.component.jsx +++ b/client/src/components/dms-post-form/dms-post-form.component.jsx @@ -277,36 +277,32 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
{t("jobs.fields.dms.payer.controlnumber")}{" "} - {bodyshop.cdk_configuration.controllist && - bodyshop.cdk_configuration.controllist.map( - (key, idx) => ( - { - form.setFieldsValue({ - payers: form - .getFieldValue("payers") - .map((row, mapIndex) => { - if (index !== mapIndex) - return row; + menu={{ + items: + bodyshop.cdk_configuration.controllist && + bodyshop.cdk_configuration.controllist.map( + (key, idx) => ({ + key: idx, + label: key.name, + onClick: () => { + form.setFieldsValue({ + payers: form + .getFieldValue("payers") + .map((row, mapIndex) => { + if (index !== mapIndex) + return row; - return { - ...row, - controlnumber: - key.controlnumber, - }; - }), - }); - }} - > - {key.name} - - ) - )} - - } + return { + ...row, + controlnumber: + key.controlnumber, + }; + }), + }); + }, + }) + ), + }} > e.preventDefault()}> diff --git a/client/src/components/email-overlay/email-overlay.component.jsx b/client/src/components/email-overlay/email-overlay.component.jsx index 7db03471d..a302f5bb4 100644 --- a/client/src/components/email-overlay/email-overlay.component.jsx +++ b/client/src/components/email-overlay/email-overlay.component.jsx @@ -57,20 +57,23 @@ export function EmailOverlayComponent({ const menu = (
- - {bodyshop.employees - .filter((e) => e.user_email) - .map((e, idx) => ( - - {`${e.first_name} ${e.last_name}`} - - ))} - {bodyshop.md_to_emails.map((e, idx) => ( - - {e.label} - - ))} - + e.user_email) + .map((e, idx) => ({ + value: e.user_email, + key: idx, + label: `${e.first_name} ${e.last_name}`, + })), + ...bodyshop.md_to_emails.map((e, idx) => ({ + value: e.emails, + key: idx + "group", + label: e.label, + })), + ]} + />
); diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx index 1ed3f526d..0a96c233f 100644 --- a/client/src/components/header/header.component.jsx +++ b/client/src/components/header/header.component.jsx @@ -106,304 +106,428 @@ function Header({ selectedKeys={[selectedHeader]} onClick={handleMenuClick} subMenuCloseDelay={0.3} - > - }> - {t("menus.header.home")} - - }> - {t("menus.header.schedule")} - - } - title={t("menus.header.jobs")} - > - }> - {t("menus.header.activejobs")} - - }> - {t("menus.header.readyjobs")} - - }> - {t("menus.header.parts-queue")} - - }> - - {t("menus.header.availablejobs")} - - - }> - {t("menus.header.newjob")} - - - }> - {t("menus.header.alljobs")} - - - }> - - {t("menus.header.productionlist")} - - - }> - - {t("menus.header.productionboard")} - - - - }> - {t("menus.header.scoreboard")} - - - } - title={t("menus.header.customers")} - > - }> - {t("menus.header.owners")} - - }> - {t("menus.header.vehicles")} - - - } - title={t("menus.header.courtesycars")} - > - }> - - {t("menus.header.courtesycars-all")} - - - }> - - {t("menus.header.courtesycars-contracts")} - - - }> - - {t("menus.header.courtesycars-newcontract")} - - - - } - title={t("menus.header.accounting")} - > - } - > - {t("menus.header.bills")} - - } - onClick={() => { - setBillEnterContext({ - actions: {}, - context: {}, - }); - }} - > - {t("menus.header.enterbills")} - - {Simple_Inventory.treatment === "on" && ( - <> - - } - > - - {t("menus.header.inventory")} - - - - )} - - }> - {t("menus.header.allpayments")} - - { - setPaymentContext({ - actions: {}, - context: null, - }); - }} - icon={} - > - {t("menus.header.enterpayment")} - - - }> - - {t("menus.header.timetickets")} - - - } - onClick={() => { - setTimeTicketContext({ - actions: {}, - context: {}, - }); - }} - > - {t("menus.header.entertimeticket")} - - - } - > - - - {t("menus.header.accounting-receivables")} - - - {(!( - (bodyshop && bodyshop.cdk_dealerid) || - (bodyshop && bodyshop.pbs_serialnumber) - ) || - DmsAp.treatment === "on") && ( - - - {t("menus.header.accounting-payables")} - - - )} - {!( - (bodyshop && bodyshop.cdk_dealerid) || - (bodyshop && bodyshop.pbs_serialnumber) - ) && ( - - - {t("menus.header.accounting-payments")} - - - )} - - - {t("menus.header.export-logs")} - - - - - }> - {t("menus.header.phonebook")} - - }> - - {t("menus.header.temporarydocs")} - - - } - > - }> - {t("menus.header.shop_config")} - - }> - {t("menus.header.dashboard")} - - } - onClick={() => { - setReportCenterContext({ - actions: {}, - context: {}, - }); - }} - > - {t("menus.header.reportcenter")} - - } - > - - {t("menus.header.shop_vendors")} - - - }> - {t("menus.header.shop_csi")} - - - - signOutStart()}> - {t("user.actions.signout")} - - { - window.open("https://help.imex.online/", "_blank"); - }} - icon={} - > - {t("menus.header.help")} - - { - window.open("https://imexrescue.com/", "_blank"); - }} - > - {t("menus.header.rescueme")} - - - {t("menus.header.shiftclock")} - - - {t("menus.currentuser.profile")} - + items={[ { - // - // - // {t("menus.currentuser.languageselector")} - // - // } - // > - // - // {t("general.languages.english")} - // - // - // {t("general.languages.french")} - // - // - // {t("general.languages.spanish")} - // - // - } - - }> - {recentItems.map((i, idx) => ( - - {i.label} - - ))} - - + key: "home", + icon: , + label: {t("menus.header.home")}, + }, + { + key: "schedule", + icon: , + label: ( + {t("menus.header.schedule")} + ), + }, + { + key: "jobssubmenu", + icon: , + label: t("menus.header.jobs"), + children: [ + { + key: "activejobs", + icon: , + label: ( + {t("menus.header.activejobs")} + ), + }, + { + key: "readyjobs", + icon: , + label: ( + + {t("menus.header.readyjobs")} + + ), + }, + { + key: "parts-queue", + icon: , + label: ( + + {t("menus.header.parts-queue")} + + ), + }, + { + key: "availablejobs", + icon: , + label: ( + + {t("menus.header.availablejobs")} + + ), + }, + { + key: "newjob", + icon: , + label: ( + {t("menus.header.newjob")} + ), + }, + { type: "divider" }, + { + key: "alljobs", + icon: , + label: ( + {t("menus.header.alljobs")} + ), + }, + { type: "divider" }, + { + key: "productionlist", + icon: , + label: ( + + {t("menus.header.productionlist")} + + ), + }, + { + key: "productionboard", + icon: , + label: ( + + {t("menus.header.productionboard")} + + ), + }, + { + type: "divider", + }, + { + key: "scoreboard", + icon: , + label: ( + + {t("menus.header.scoreboard")} + + ), + }, + ], + }, + { + key: "customers", + icon: , + label: t("menus.header.customers"), + children: [ + { + key: "owners", + icon: , + label: ( + {t("menus.header.owners")} + ), + }, + { + key: "vehicles", + icon: , + label: ( + + {t("menus.header.vehicles")} + + ), + }, + ], + }, + { + key: "ccs", + icon: , + label: t("menus.header.courtesycars"), + children: [ + { + key: "courtesycarsall", + icon: , + label: ( + + {t("menus.header.courtesycars-all")} + + ), + }, + { + key: "contracts", + icon: , + label: ( + + {t("menus.header.courtesycars-contracts")} + + ), + }, + { + key: "newcontract", + icon: , + label: ( + + {t("menus.header.courtesycars-newcontract")} + + ), + }, + ], + }, + { + key: "accounting", + icon: , + label: t("menus.header.accounting"), + children: [ + { + key: "bills", + icon: , + label: ( + {t("menus.header.bills")} + ), + }, + { + key: "enterbills", + icon: , + onClick: () => { + setBillEnterContext({ + actions: {}, + context: {}, + }); + }, + label: t("menus.header.enterbills"), + }, + ...(Simple_Inventory.treatment === "on" + ? [ + { + type: "divider", + }, + { + key: "inventory", + icon: , + label: ( + + {t("menus.header.inventory")} + + ), + }, + ] + : []), + { type: "divider" }, + { + key: "allpayments", + icon: , + label: ( + + {t("menus.header.allpayments")} + + ), + }, + { + key: "enterpayments", + onClick: () => { + setPaymentContext({ + actions: {}, + context: null, + }); + }, + icon: , + label: t("menus.header.enterpayment"), + }, + { type: "divider" }, + { + key: "timetickets", + icon: , + label: ( + + {t("menus.header.timetickets")} + + ), + }, + { + key: "entertimetickets", + icon: , + onClick: () => { + setTimeTicketContext({ + actions: {}, + context: {}, + }); + }, + label: t("menus.header.entertimeticket"), + }, + { type: "divider" }, + { + key: "accountingexport", + icon: , + + label: t("menus.header.export"), + children: [ + { + key: "receivables", + label: ( + + {t("menus.header.accounting-receivables")} + + ), + }, + ...(!( + (bodyshop && bodyshop.cdk_dealerid) || + (bodyshop && bodyshop.pbs_serialnumber) + ) || DmsAp.treatment === "on" + ? [ + { + key: "payables", + label: ( + + {t("menus.header.accounting-payables")} + + ), + }, + ] + : []), + + ...(!( + (bodyshop && bodyshop.cdk_dealerid) || + (bodyshop && bodyshop.pbs_serialnumber) + ) + ? [ + { + key: "payments", + label: ( + + {t("menus.header.accounting-payments")} + + ), + }, + ] + : []), + { + key: "export-logs", + label: ( + + {t("menus.header.export-logs")} + + ), + }, + ], + }, + ], + }, + + { + key: "phonebook", + icon: , + label: ( + {t("menus.header.phonebook")} + ), + }, + { + key: "temporarydocs", + icon: , + label: ( + + {t("menus.header.temporarydocs")} + + ), + }, + + { + key: "shopsubmenu", + icon: , + label: t("menus.header.shop"), + children: [ + { + key: "shop", + icon: , + label: ( + {t("menus.header.shop_config")} + ), + }, + { + key: "dashboard", + icon: , + label: ( + + {t("menus.header.dashboard")} + + ), + }, + { + key: "reportcenter", + icon: , + onClick: () => { + setReportCenterContext({ + actions: {}, + context: {}, + }); + }, + label: t("menus.header.reportcenter"), + }, + { + key: "shop-vendors", + icon: , + label: ( + + {t("menus.header.shop_vendors")} + + ), + }, + { + key: "shop-csi", + icon: , + label: ( + + {t("menus.header.shop_csi")} + + ), + }, + ], + }, + { + key: "user", + label: + currentUser.displayName || + currentUser.email || + t("general.labels.unknown"), + children: [ + { + key: "signout", + danger: true, + onClick: () => signOutStart(), + label: t("user.actions.signout"), + }, + { + key: "help", + icon: , + onClick: () => { + window.open("https://help.imex.online/", "_blank"); + }, + label: t("menus.header.help"), + }, + { + key: "rescue", + onClick: () => { + window.open("https://imexrescue.com/", "_blank"); + }, + label: t("menus.header.rescueme"), + }, + { + key: "shiftclock", + label: ( + + {t("menus.header.shiftclock")} + + ), + }, + { + key: "profile", + label: ( + + {t("menus.currentuser.profile")} + + ), + }, + ], + }, + { + key: "recent", + label: , + children: recentItems.map((i, idx) => ({ + key: idx, + label: {i.label}, + })), + }, + ]} + > ); } diff --git a/client/src/components/job-at-change/job-at-change.component.jsx b/client/src/components/job-at-change/job-at-change.component.jsx index bd6c556ef..845447855 100644 --- a/client/src/components/job-at-change/job-at-change.component.jsx +++ b/client/src/components/job-at-change/job-at-change.component.jsx @@ -37,18 +37,19 @@ export function JobAltTransportChange({ bodyshop, job }) { }); } }; - const menu = ( - - {bodyshop.appt_alt_transport && - bodyshop.appt_alt_transport.map((alt) => ( - {alt} - ))} - - {t("general.actions.clear")} - - ); + const menu = [ + ...(bodyshop.appt_alt_transport && + bodyshop.appt_alt_transport.map((alt) => ({ + key: alt, + label: alt, + value: alt, + onClick, + }))), + { type: "divider" }, + { key: "null", label: t("general.actions.clear"), onClick }, + ]; return ( - +
e.preventDefault()}> diff --git a/client/src/components/job-at-change/schedule-event.color.component.jsx b/client/src/components/job-at-change/schedule-event.color.component.jsx index 632bbdfcf..0066d06e0 100644 --- a/client/src/components/job-at-change/schedule-event.color.component.jsx +++ b/client/src/components/job-at-change/schedule-event.color.component.jsx @@ -44,21 +44,23 @@ export function ScheduleEventColor({ bodyshop, event }) { bodyshop.appt_colors.filter((color) => color.color.hex === event.color)[0] ?.label; - const menu = ( - - {bodyshop.appt_colors && - bodyshop.appt_colors.map((color) => ( - - {color.label} - - ))} - - {t("general.actions.clear")} - - ); + const menu = { + items: [ + ...(bodyshop.appt_colors && + bodyshop.appt_colors.map((color) => ({ + style: { color: color.color.hex }, + key: color.color.hex, + label: color.label, + }))), + { type: "divider" }, + { key: "null", value: t("general.actions.clear") }, + ], + selectedKeys: [event.color], + onClick: onClick, + }; return ( - + e.preventDefault()}> {selectedColor} diff --git a/client/src/components/job-at-change/schedule-event.component.jsx b/client/src/components/job-at-change/schedule-event.component.jsx index e0c0ccc4d..5d7302b90 100644 --- a/client/src/components/job-at-change/schedule-event.component.jsx +++ b/client/src/components/job-at-change/schedule-event.component.jsx @@ -149,10 +149,12 @@ export function ScheduleEventComponent({ ) : null} {event.job ? ( - { + menu={{ + items: [ + { + disabled: event.arrived, + label: t("general.labels.email"), + onClick: () => { const Template = TemplateList("job").appointment_reminder; GenerateDocument( { @@ -166,13 +168,12 @@ export function ScheduleEventComponent({ "e", event.job && event.job.id ); - }} - disabled={event.arrived} - > - {t("general.labels.email")} - - { + }, + }, + { + label: t("general.labels.sms"), + disabled: event.arrived || !bodyshop.messagingservicesid, + onClick: () => { const p = parsePhoneNumber(event.job.ownr_ph1, "CA"); if (p && p.isValid()) { openChatByPhone({ @@ -192,13 +193,10 @@ export function ScheduleEventComponent({ message: t("messaging.error.invalidphone"), }); } - }} - disabled={event.arrived || !bodyshop.messagingservicesid} - > - {t("general.labels.sms")} - - - } + }, + }, + ], + }} > @@ -249,7 +247,7 @@ export function ScheduleEventComponent({ const RegularEvent = event.isintake ? ( alphaSort(a.line_desc, b.line_desc), - onCell: (record) => ({ className: record.manual_line && "job-line-manual" }), + onCell: (record) => ({ + className: record.manual_line && "job-line-manual", + }), sortOrder: state.sortedInfo.columnKey === "line_desc" && state.sortedInfo.order, ellipsis: true, @@ -405,16 +407,17 @@ export function JobLinesComponent({ } }; - const markMenu = ( - - {t("joblines.fields.part_types.PAA")} - {t("joblines.fields.part_types.PAN")} - {t("joblines.fields.part_types.PAL")} - {t("joblines.fields.part_types.PAS")} - - {t("general.labels.clear")} - - ); + const markMenu = { + onClick: handleMark, + items: [ + { key: "PAA", label: t("joblines.fields.part_types.PAA") }, + { key: "PAN", label: t("joblines.fields.part_types.PAN") }, + { key: "PAL", label: t("joblines.fields.part_types.PAL") }, + { key: "PAS", label: t("joblines.fields.part_types.PAS") }, + { type: "divider" }, + { key: "clear", label: t("general.labels.clear") }, + ], + }; return (
@@ -544,7 +547,7 @@ export function JobLinesComponent({ > {t("jobs.actions.filterpartsonly")} - + ) : ( diff --git a/client/src/components/jobs-detail-change-estimator/jobs-detail-change-estimator.component.jsx b/client/src/components/jobs-detail-change-estimator/jobs-detail-change-estimator.component.jsx index 61035b23e..37577f0e2 100644 --- a/client/src/components/jobs-detail-change-estimator/jobs-detail-change-estimator.component.jsx +++ b/client/src/components/jobs-detail-change-estimator/jobs-detail-change-estimator.component.jsx @@ -15,20 +15,17 @@ export function JobsDetailChangeEstimator({ disabled, form, bodyshop }) { form.setFieldsValue(est); }; - const menu = ( -
- - {bodyshop.md_estimators.map((est, idx) => ( - - {`${est.est_ct_fn} ${est.est_ct_ln}`} - - ))} - -
- ); + const menu = { + onClick: handleClick, + items: bodyshop.md_estimators.map((est, idx) => ({ + value: est, + key: idx, + label: `${est.est_ct_fn || ""} ${est.est_ct_ln || ""}`.trim(), + })), + }; return ( - +
- {bodyshop.md_filehandlers.map((est, idx) => ( - - {`${est.ins_ct_fn} ${est.ins_ct_ln}`} - - ))} - - ); + const menu = { + onClick: handleClick, + style: { + columnCount: Math.floor(bodyshop.md_filehandlers.length / 10) + 1, + }, + items: bodyshop.md_filehandlers.map((est, idx) => ({ + value: est, + key: idx, + style: { breakInside: "avoid" }, + label: `${est.ins_ct_fn || ""} ${est.ins_ct_ln || ""}`.trim(), + })), + }; return ( - + ({ - //setUserLanguage: language => dispatch(setUserLanguage(language)) -}); -export default connect( - mapStateToProps, - mapDispatchToProps -)(JobsDetailHeaderAddEvent); - -export function JobsDetailHeaderAddEvent({ bodyshop, jobid, ...props }) { +export default function JobsDetailHeaderAddEvent({ bodyshop, jobid }) { const { t } = useTranslation(); const [insertAppointment] = useMutation(INSERT_MANUAL_APPT); @@ -153,11 +138,12 @@ export function JobsDetailHeaderAddEvent({ bodyshop, jobid, ...props }) { setVisibility(true); }; - return ( - - + return { + key: "addmanualevent", + label: ( + {t("appointments.labels.manualevent")} - - - ); + + ), + }; } diff --git a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx index 5002a0e5d..7342f303d 100644 --- a/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx +++ b/client/src/components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx @@ -105,13 +105,14 @@ export function JobsDetailHeaderActions({ }); }; - const statusmenu = ( - - { + const statusmenu = { + items: [ + { + key: "schedule", + disabled: !jobInPreProduction || !job.converted || jobRO, + label: t("jobs.actions.schedule"), + onClick: () => { logImEXEvent("job_header_schedule"); - setScheduleContext({ actions: { refetch: refetch }, context: { @@ -120,200 +121,228 @@ export function JobsDetailHeaderActions({ alt_transport: job.alt_transport, }, }); - }} - > - {t("jobs.actions.schedule")} - - - e.stopPropagation()} - disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled} - onConfirm={async () => { - const jobUpdate = await cancelAllAppointments({ - variables: { - jobid: job.id, - job: { - date_scheduled: null, - scheduled_in: null, - scheduled_completion: null, - status: bodyshop.md_ro_statuses.default_imported, + }, + }, + { + key: "cancelappts", + disabled: job.status !== bodyshop.md_ro_statuses.default_scheduled, + label: ( + e.stopPropagation()} + disabled={job.status !== bodyshop.md_ro_statuses.default_scheduled} + onConfirm={async () => { + const jobUpdate = await cancelAllAppointments({ + variables: { + jobid: job.id, + job: { + date_scheduled: null, + scheduled_in: null, + scheduled_completion: null, + status: bodyshop.md_ro_statuses.default_imported, + }, }, - }, - }); - if (!jobUpdate.errors) { - notification["success"]({ - message: t("appointments.successes.canceled"), }); - return; - } - }} - getPopupContainer={(trigger) => trigger.parentNode} - > - {t("menus.jobsactions.cancelallappointments")} - - - trigger.parentNode} + > + {t("menus.jobsactions.cancelallappointments")} + + ), + }, + { + key: "intake", + disabled: !!job.intakechecklist || !jobInPreProduction || !job.converted || - jobRO - } - > - {!!job.intakechecklist || - !jobInPreProduction || - !job.converted || - jobRO ? ( - t("jobs.actions.intake") - ) : ( - - {t("jobs.actions.intake")} - - )} - - - {!jobInProduction ? ( + jobRO, + label: + !!job.intakechecklist || + !jobInPreProduction || + !job.converted || + jobRO ? ( + t("jobs.actions.intake") + ) : ( + + {t("jobs.actions.intake")} + + ), + }, + { + disabled: !jobInProduction || jobRO, + key: "deliver", + label: !jobInProduction ? ( t("jobs.actions.deliver") ) : ( {t("jobs.actions.deliver")} - )} - - - - {t("jobs.actions.viewchecklist")} - - - + {t("jobs.actions.viewchecklist")} + + ), + }, + { + key: "entertimetickets", + disabled: !job.converted || - (!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced) - } - onClick={() => { + (!bodyshop.tt_allow_post_to_invoiced && job.date_invoiced), + onClick: () => { logImEXEvent("job_header_enter_time_ticekts"); setTimeTicketContext({ actions: {}, context: { jobId: job.id }, }); - }} - > - {t("timetickets.actions.enter")} - - { + }, + label: t("timetickets.actions.enter"), + }, + { + key: "enterpayments", + disabled: !job.converted, + label: t("menus.header.enterpayment"), + onClick: () => { logImEXEvent("job_header_enter_payment"); setPaymentContext({ actions: {}, context: { jobid: job.id }, }); - }} - > - {t("menus.header.enterpayment")} - - - - {t("menus.jobsactions.newcccontract")} - - - {job.inproduction ? ( - AddToProduction(client, job.id, refetch, true)} - > - {t("jobs.actions.removefromproduction")} - - ) : ( - AddToProduction(client, job.id, refetch)} - > - {t("jobs.actions.addtoproduction")} - - )} - - {job.suspended + }, + }, + { + key: "cccontract", + disabled: jobRO || !job.converted, + label: ( + + {t("menus.jobsactions.newcccontract")} + + ), + }, + ...(job.inproduction + ? [ + { + key: "removetoproduction", + disabled: !job.converted, + onClick: () => AddToProduction(client, job.id, refetch, true), + label: t("jobs.actions.removefromproduction"), + }, + ] + : [ + { + key: "addtoproduction", + disabled: !job.converted, + onClick: () => AddToProduction(client, job.id, refetch), + label: t("jobs.actions.addtoproduction"), + }, + ]), + { + key: "togglesuspend", + onClick: handleSuspend, + label: job.suspended ? t("production.actions.unsuspend") - : t("production.actions.suspend")} - - - {job.production_vars && job.production_vars.alert - ? t("production.labels.alertoff") - : t("production.labels.alerton")} - - - - e.stopPropagation()} - onConfirm={() => - DuplicateJob( - client, - job.id, - { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported }, - (newJobId) => { - history.push(`/manage/jobs/${newJobId}`); - notification["success"]({ - message: t("jobs.successes.duplicated"), - }); - }, - true - ) - } - getPopupContainer={(trigger) => trigger.parentNode} - > - {t("menus.jobsactions.duplicate")} - - - - e.stopPropagation()} - onConfirm={() => - DuplicateJob( - client, - job.id, - { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported }, - (newJobId) => { - history.push(`/manage/jobs/${newJobId}`); - notification["success"]({ - message: t("jobs.successes.duplicated"), - }); + : t("production.actions.suspend"), + }, + { + key: "toggleAlert", + onClick: handleAlertToggle, + label: + job.production_vars && job.production_vars.alert + ? t("production.labels.alertoff") + : t("production.labels.alerton"), + }, + { + key: "dupe", + label: t("menus.jobsactions.duplicate"), + children: [ + { + key: "dupewithlines", + label: ( + e.stopPropagation()} + onConfirm={() => + DuplicateJob( + client, + job.id, + { + defaultOpenStatus: + bodyshop.md_ro_statuses.default_imported, + }, + (newJobId) => { + history.push(`/manage/jobs/${newJobId}`); + notification["success"]({ + message: t("jobs.successes.duplicated"), + }); + }, + true + ) } - ) - } - getPopupContainer={(trigger) => trigger.parentNode} - > - {t("menus.jobsactions.duplicatenolines")} - - - - - { + getPopupContainer={(trigger) => trigger.parentNode} + > + {t("menus.jobsactions.duplicate")} + + ), + }, + { + key: "dupewithoutlines", + label: ( + e.stopPropagation()} + onConfirm={() => + DuplicateJob( + client, + job.id, + { + defaultOpenStatus: + bodyshop.md_ro_statuses.default_imported, + }, + (newJobId) => { + history.push(`/manage/jobs/${newJobId}`); + notification["success"]({ + message: t("jobs.successes.duplicated"), + }); + } + ) + } + getPopupContainer={(trigger) => trigger.parentNode} + > + {t("menus.jobsactions.duplicatenolines")} + + ), + }, + ], + }, + { + key: "postbills", + disabled: !job.converted, + label: t("jobs.actions.postbills"), + onClick: () => { logImEXEvent("job_header_enter_bills"); setBillEnterContext({ @@ -322,14 +351,13 @@ export function JobsDetailHeaderActions({ job: job, }, }); - }} - > - {t("jobs.actions.postbills")} - - { + }, + }, + { + key: "addtopartsqueue", + disabled: !job.converted || !jobInProduction || jobRO, + label: t("jobs.actions.addtopartsqueue"), + onClick: async () => { const result = await updateJob({ variables: { jobId: job.id, @@ -348,12 +376,12 @@ export function JobsDetailHeaderActions({ }), }); } - }} - > - {t("jobs.actions.addtopartsqueue")} - - - {!jobInPostProduction ? ( + }, + }, + { + disabled: !jobInPostProduction, + key: "closejob", + label: !jobInPostProduction ? ( t("menus.jobsactions.closejob") ) : ( {t("menus.jobsactions.closejob")} - )} - - - - {t("menus.jobsactions.admin")} - - - - - { + ), + }, + { + key: "admin", + label: ( + + {t("menus.jobsactions.admin")} + + ), + }, + JobsDetailHeaderActionsExportcustdataComponent({ bodyshop, job }), + JobsDetaiLheaderCsi({ job, bodyshop }), + { + key: "jobcosting", + label: t("jobs.labels.jobcosting"), + disabled: !job.converted, + onClick: () => { logImEXEvent("job_header_job_costing"); setJobCostingContext({ actions: { refetch: refetch }, @@ -387,96 +419,108 @@ export function JobsDetailHeaderActions({ jobId: job.id, }, }); - }} - > - {t("jobs.labels.jobcosting")} - - {job && !job.converted && ( - - e.stopPropagation()} - onConfirm={async () => { - //delete the job. - const result = await deleteJob({ variables: { id: job.id } }); + }, + }, + ...(job && !job.converted + ? [ + { + key: "deletejob", + label: ( + e.stopPropagation()} + onConfirm={async () => { + //delete the job. + const result = await deleteJob({ + variables: { id: job.id }, + }); - if (!!!result.errors) { - notification["success"]({ - message: t("jobs.successes.delete"), - }); - //go back to jobs list. - history.push(`/manage/`); - } else { - notification["error"]({ - message: t("jobs.errors.deleted", { - error: JSON.stringify(result.errors), - }), - }); - } - }} - getPopupContainer={(trigger) => trigger.parentNode} - > - {t("menus.jobsactions.deletejob")} - - - )} - - {!jobRO && job.converted && ( - - e.stopPropagation()} - onConfirm={async () => { - //delete the job. - const result = await voidJob({ - variables: { - jobId: job.id, - job: { - status: bodyshop.md_ro_statuses.default_void, - voided: true, - scheduled_in: null, - scheduled_completion: null, - inproduction: false, - }, - note: [ - { - jobid: job.id, - created_by: currentUser.email, - audit: true, - text: t("jobs.labels.voidnote"), - }, - ], - }, - }); + if (!!!result.errors) { + notification["success"]({ + message: t("jobs.successes.delete"), + }); + //go back to jobs list. + history.push(`/manage/`); + } else { + notification["error"]({ + message: t("jobs.errors.deleted", { + error: JSON.stringify(result.errors), + }), + }); + } + }} + getPopupContainer={(trigger) => trigger.parentNode} + > + {t("menus.jobsactions.deletejob")} + + ), + }, + ] + : []), + ///////HEADER ADD EVENT ITEM + JobsDetailHeaderActionsAddevent({ jobid: job.id, bodyshop }), + ...(!jobRO && job.converted + ? [ + { + key: "voidjob", + label: ( + e.stopPropagation()} + onConfirm={async () => { + //delete the job. + const result = await voidJob({ + variables: { + jobId: job.id, + job: { + status: bodyshop.md_ro_statuses.default_void, + voided: true, + scheduled_in: null, + scheduled_completion: null, + inproduction: false, + }, + note: [ + { + jobid: job.id, + created_by: currentUser.email, + audit: true, + text: t("jobs.labels.voidnote"), + }, + ], + }, + }); + + if (!!!result.errors) { + notification["success"]({ + message: t("jobs.successes.voided"), + }); + //go back to jobs list. + history.push(`/manage/`); + } else { + notification["error"]({ + message: t("jobs.errors.voiding", { + error: JSON.stringify(result.errors), + }), + }); + } + }} + getPopupContainer={(trigger) => trigger.parentNode} + > + {t("menus.jobsactions.void")} + + ), + }, + ] + : []), + ], + }; - if (!!!result.errors) { - notification["success"]({ - message: t("jobs.successes.voided"), - }); - //go back to jobs list. - history.push(`/manage/`); - } else { - notification["error"]({ - message: t("jobs.errors.voiding", { - error: JSON.stringify(result.errors), - }), - }); - } - }} - getPopupContainer={(trigger) => trigger.parentNode} - > - {t("menus.jobsactions.void")} - - - )} - - ); return ( - +