Majority of Dropdown Overlay Menu refactors.

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2023-12-29 13:26:37 -05:00
parent 79dce5d069
commit 07b46ed92b
32 changed files with 744 additions and 833 deletions

View File

@@ -1,5 +1,5 @@
import { PlusCircleOutlined } from "@ant-design/icons"; import { PlusCircleOutlined } from "@ant-design/icons";
import { Dropdown, Menu } from "antd"; import { Dropdown } from "antd";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -16,19 +16,16 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export function ChatPresetsComponent({ bodyshop, setMessage, className }) { export function ChatPresetsComponent({ bodyshop, setMessage, className }) {
const menuItems = bodyshop.md_messaging_presets.map((i, idx) => ({
const items = bodyshop.md_messaging_presets.map((i, idx) => ({
key: idx, key: idx,
label: i.label, label: (i.label),
onClick: () => setMessage(i.text), onClick: () => setMessage(i.text),
})); }));
const menu = (
<Menu items={menuItems} />
);
return ( return (
<div className={className}> <div className={className}>
<Dropdown trigger={["click"]} menu={menu}> <Dropdown trigger={["click"]} menu={{items}}>
<PlusCircleOutlined /> <PlusCircleOutlined />
</Dropdown> </Dropdown>
</div> </div>

View File

@@ -24,11 +24,8 @@ export function ContractsRatesChangeButton({ disabled, form, bodyshop }) {
value: i, value: i,
})); }));
const menu = ( const menu = {items: menuItems, onClick: handleClick}
<div>
<Menu onClick={handleClick} items={menuItems} />
</div>
);
return ( return (
<Dropdown menu={menu} disabled={disabled}> <Dropdown menu={menu} disabled={disabled}>

View File

@@ -179,7 +179,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
) )
: courtesycars; : courtesycars;
const menuItems = [ const items = [
{ {
key: "courtesycar_inventory", key: "courtesycar_inventory",
label: t("printcenter.courtesycarcontract.courtesy_car_inventory"), label: t("printcenter.courtesycarcontract.courtesy_car_inventory"),
@@ -205,11 +205,7 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
<Button onClick={() => refetch()}> <Button onClick={() => refetch()}>
<SyncOutlined /> <SyncOutlined />
</Button> </Button>
<Dropdown <Dropdown trigger="click" menu={{items}}
trigger="click"
menu={
<Menu items={menuItems} />
}
> >
<Button>{t("general.labels.print")}</Button> <Button>{t("general.labels.print")}</Button>
</Dropdown> </Dropdown>

View File

@@ -131,9 +131,7 @@ export function DashboardGridComponent({ currentUser, bodyshop }) {
disabled: existingLayoutKeys.includes(key), disabled: existingLayoutKeys.includes(key),
})); }));
const addComponentOverlay = ( const menu = {items: menuItems, onClick: handleAddComponent};
<Menu onClick={handleAddComponent} items={menuItems} />
);
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
@@ -145,7 +143,7 @@ export function DashboardGridComponent({ currentUser, bodyshop }) {
<Button onClick={() => refetch()}> <Button onClick={() => refetch()}>
<SyncOutlined /> <SyncOutlined />
</Button> </Button>
<Dropdown menu={addComponentOverlay} trigger={["click"]}> <Dropdown menu={menu} trigger={["click"]}>
<Button>{t("dashboard.actions.addcomponent")}</Button> <Button>{t("dashboard.actions.addcomponent")}</Button>
</Dropdown> </Dropdown>
</Space> </Space>

View File

@@ -291,25 +291,23 @@ export function DmsPostForm({bodyshop, socket, job, logsRef}) {
label={ label={
<div> <div>
{t("jobs.fields.dms.payer.controlnumber")}{" "} {t("jobs.fields.dms.payer.controlnumber")}{" "}
<Dropdown <Dropdown menu={{
menu={<Menu items: bodyshop.cdk_configuration.controllist?.map((key, idx) => ({
items={bodyshop.cdk_configuration.controllist?.map((key, idx) => ({ key: idx,
key: idx, label: key.name,
label: key.name, onClick: () => {
onClick: () => { form.setFieldsValue({
form.setFieldsValue({ payers: form.getFieldValue("payers").map((row, mapIndex) => {
payers: form.getFieldValue("payers").map((row, mapIndex) => { if (index !== mapIndex) return row;
if (index !== mapIndex) return row; return {
return { ...row,
...row, controlnumber: key.controlnumber,
controlnumber: key.controlnumber, };
}; }),
}), });
}); },
}, }))
}))} }}>
/>}
>
<a href=" #" onClick={(e) => e.preventDefault()}> <a href=" #" onClick={(e) => e.preventDefault()}>
<DownOutlined/> <DownOutlined/>
</a> </a>

View File

@@ -1,5 +1,5 @@
import {UploadOutlined, UserAddOutlined} from "@ant-design/icons"; import {UploadOutlined, UserAddOutlined} from "@ant-design/icons";
import {Button, Divider, Dropdown, Form, Input, Menu, Select, Space, Tabs, Upload,} from "antd"; import {Button, Divider, Dropdown, Form, Input, Select, Space, Tabs, Upload,} from "antd";
import _ from "lodash"; import _ from "lodash";
import React from "react"; import React from "react";
import {useTranslation} from "react-i18next"; import {useTranslation} from "react-i18next";
@@ -50,47 +50,40 @@ export function EmailOverlayComponent({
}); });
}; };
const menu = ( const emailsToMenu = {
<Menu items: [
onClick={handleClick} ...bodyshop.employees
items={[ .filter((e) => e.user_email)
...bodyshop.employees .map((e, idx) => ({
.filter((e) => e.user_email) key: idx,
.map((e, idx) => ({ label: `${e.first_name} ${e.last_name}`,
key: idx, value: e.user_email,
label: `${e.first_name} ${e.last_name}`, })),
value: e.user_email, ...bodyshop.md_to_emails.map((e, idx) => ({
})), key: idx + "group",
...bodyshop.md_to_emails.map((e, idx) => ({ label: e.label,
key: idx + "group", value: e.emails,
label: e.label, })),
value: e.emails, ],
})), onClick: handleClick,
]} };
/> const menuCC = {
); items: [
...bodyshop.employees
const menuCC = ( .filter((e) => e.user_email)
<div> .map((e, idx) => ({
<Menu key: idx,
onClick={handle_CC_Click} label: `${e.first_name} ${e.last_name}`,
items={[ value: e.user_email,
...bodyshop.employees })),
.filter((e) => e.user_email) ...bodyshop.md_to_emails.map((e, idx) => ({
.map((e, idx) => ({ key: idx + "group",
key: idx, label: e.label,
label: `${e.first_name} ${e.last_name}`, value: e.emails,
value: e.user_email, })),
})), ],
...bodyshop.md_to_emails.map((e, idx) => ({ onClick: handle_CC_Click,
key: idx + "group", };
label: e.label,
value: e.emails,
})),
]}
/>
</div>
);
return ( return (
<div> <div>
@@ -119,7 +112,7 @@ export function EmailOverlayComponent({
label={ label={
<Space> <Space>
{t("emails.fields.to")} {t("emails.fields.to")}
<Dropdown menu={menu}> <Dropdown menu={emailsToMenu}>
<a <a
className="ant-dropdown-link" className="ant-dropdown-link"
href=" #" href=" #"

View File

@@ -4,7 +4,7 @@ import { UPDATE_JOB } from "../../graphql/jobs.queries";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { Dropdown, Menu, notification } from "antd"; import { Dropdown, notification } from "antd";
import { DownOutlined } from "@ant-design/icons"; import { DownOutlined } from "@ant-design/icons";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
@@ -37,19 +37,19 @@ export function JobAltTransportChange({ bodyshop, job }) {
}); });
} }
}; };
const menu = (
<Menu const menu = {
selectedKeys={[job && job.alt_transport]} items: [
onClick={onClick} ...(bodyshop.appt_alt_transport || []).map((alt) => ({
items={[
...(bodyshop.appt_alt_transport || []).map((alt) => ({
key: alt, key: alt,
label: alt, label: alt,
})), })),
{ key: "null", label: t("general.actions.clear") }, { key: "null", label: t("general.actions.clear") },
]} ],
/> onClick: onClick,
); defaultSelectedKeys: [job && job.alt_transport]
}
return ( return (
<Dropdown menu={menu}> <Dropdown menu={menu}>
<a href=" #" onClick={(e) => e.preventDefault()}> <a href=" #" onClick={(e) => e.preventDefault()}>

View File

@@ -4,7 +4,7 @@ import { UPDATE_APPOINTMENT } from "../../graphql/appointments.queries";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { Dropdown, Menu, notification } from "antd"; import { Dropdown, notification } from "antd";
import { DownOutlined } from "@ant-design/icons"; import { DownOutlined } from "@ant-design/icons";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
@@ -44,21 +44,20 @@ export function ScheduleEventColor({ bodyshop, event }) {
bodyshop.appt_colors.filter((color) => color.color.hex === event.color)[0] bodyshop.appt_colors.filter((color) => color.color.hex === event.color)[0]
?.label; ?.label;
const menu = (
<Menu const menu = {
selectedKeys={[event.color]} defaultSelectedKeys: [event.color],
onClick={onClick} onClick: onClick,
items={[ items: [
...(bodyshop.appt_colors || []).map((color) => ({ ...(bodyshop.appt_colors || []).map((color) => ({
key: color.color.hex, key: color.color.hex,
label: color.label, label: color.label,
style: { color: color.color.hex }, style: { color: color.color.hex },
})), })),
{ key: "divider", label: <hr />, disabled: true }, { key: "divider", label: <hr />, disabled: true },
{ key: "null", label: t("general.actions.clear") }, { key: "null", label: t("general.actions.clear") },
]} ]
/> };
);
return ( return (
<Dropdown menu={menu}> <Dropdown menu={menu}>
@@ -69,4 +68,5 @@ export function ScheduleEventColor({ bodyshop, event }) {
</Dropdown> </Dropdown>
); );
} }
export default connect(mapStateToProps, mapDispatchToProps)(ScheduleEventColor); export default connect(mapStateToProps, mapDispatchToProps)(ScheduleEventColor);

View File

@@ -5,7 +5,6 @@ import {
Dropdown, Dropdown,
Form, Form,
Input, Input,
Menu,
notification, notification,
Popover, Popover,
Select, Select,
@@ -185,58 +184,54 @@ export function ScheduleEventComponent({
) : null} ) : null}
{event.job ? ( {event.job ? (
<Dropdown <Dropdown
menu={ menu={{items: [
<Menu {
items={[ key: "email",
{ label: t("general.labels.email"),
key: "email", disabled: event.arrived,
label: t("general.labels.email"), onClick: () => {
disabled: event.arrived, const Template = TemplateList("job").appointment_reminder;
onClick: () => { GenerateDocument(
const Template = TemplateList("job").appointment_reminder; {
GenerateDocument( name: Template.key,
{ variables: { id: event.job.id },
name: Template.key, },
variables: { id: event.job.id }, {
}, to: event.job && event.job.ownr_ea,
{ subject: Template.subject,
to: event.job && event.job.ownr_ea, },
subject: Template.subject, "e",
}, event.job && event.job.id
"e", );
event.job && event.job.id },
},
{
key: "sms",
label: t("general.labels.sms"),
disabled: event.arrived || !bodyshop.messagingservicesid,
onClick: () => {
const p = parsePhoneNumber(event.job.ownr_ph1, "CA");
if (p && p.isValid()) {
openChatByPhone({
phone_num: p.formatInternational(),
jobid: event.job.id,
});
setMessage(
t("appointments.labels.reminder", {
shopname: bodyshop.shopname,
date: dayjs(event.start).format("MM/DD/YYYY"),
time: dayjs(event.start).format("HH:mm a"),
})
); );
}, setVisible(false);
} else {
notification["error"]({
message: t("messaging.error.invalidphone"),
});
}
}, },
{ },
key: "sms", ]}}
label: t("general.labels.sms"),
disabled: event.arrived || !bodyshop.messagingservicesid,
onClick: () => {
const p = parsePhoneNumber(event.job.ownr_ph1, "CA");
if (p && p.isValid()) {
openChatByPhone({
phone_num: p.formatInternational(),
jobid: event.job.id,
});
setMessage(
t("appointments.labels.reminder", {
shopname: bodyshop.shopname,
date: dayjs(event.start).format("MM/DD/YYYY"),
time: dayjs(event.start).format("HH:mm a"),
})
);
setVisible(false);
} else {
notification["error"]({
message: t("messaging.error.invalidphone"),
});
}
},
},
]}
/>
}
> >
<Button>{t("appointments.actions.sendreminder")}</Button> <Button>{t("appointments.actions.sendreminder")}</Button>
</Dropdown> </Dropdown>

View File

@@ -13,7 +13,6 @@ import {
Button, Button,
Dropdown, Dropdown,
Input, Input,
Menu,
Space, Space,
Table, Table,
Tag, Tag,
@@ -410,19 +409,17 @@ export function JobLinesComponent({
} }
}; };
const markMenu = ( const markMenu = {
<Menu onClick: handleMark,
onClick={handleMark} items: [
items={[ { key: "PAA", label: t("joblines.fields.part_types.PAA") },
{ key: "PAA", label: t("joblines.fields.part_types.PAA") }, { key: "PAN", label: t("joblines.fields.part_types.PAN") },
{ key: "PAN", label: t("joblines.fields.part_types.PAN") }, { key: "PAL", label: t("joblines.fields.part_types.PAL") },
{ key: "PAL", label: t("joblines.fields.part_types.PAL") }, { key: "PAS", label: t("joblines.fields.part_types.PAS") },
{ key: "PAS", label: t("joblines.fields.part_types.PAS") }, { key: "divider", label: <hr />, disabled: true },
{ key: "divider", label: <hr />, disabled: true }, { key: "clear", label: t("general.labels.clear") },
{ key: "clear", label: t("general.labels.clear") }, ]
]} }
/>
);
return ( return (
<div> <div>

View File

@@ -1,5 +1,5 @@
import { DownOutlined } from "@ant-design/icons"; import { DownOutlined } from "@ant-design/icons";
import { Dropdown, Menu } from "antd"; import { Dropdown } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -21,22 +21,21 @@ export function JoblinePresetButton({ bodyshop, form }) {
form.setFieldsValue(item); form.setFieldsValue(item);
}; };
const menu = (
<Menu const menu = {
style={{ items: bodyshop.md_jobline_presets.map((i, idx) => ({
columnCount: Math.max( key: idx,
Math.floor(bodyshop.md_jobline_presets.length / 15), label: i.label,
1 style: { breakInside: "avoid" },
), onClick: () => handleSelect(i),
}} })),
items={bodyshop.md_jobline_presets.map((i, idx) => ({ style: {
key: idx, columnCount: Math.max(
label: i.label, Math.floor(bodyshop.md_jobline_presets.length / 15),
style: { breakInside: "avoid" }, 1
onClick: () => handleSelect(i), ),
}))} },
/> }
);
return ( return (
<div> <div>

View File

@@ -40,20 +40,18 @@ export function JobsAdminStatus({ insertAuditTrail, bodyshop, job }) {
}); });
}; };
const statusmenu = ( const statusMenu = {
<Menu items: bodyshop.md_ro_statuses.statuses.map((item) => ({
onClick={(e) => { key: item,
updateJobStatus(e.key); label: item,
}} })),
items={bodyshop.md_ro_statuses.statuses.map((item) => ({ onClick: (e) => {
key: item, updateJobStatus(e.key);
label: item, },
}))} }
/>
);
return ( return (
<Dropdown menu={statusmenu} trigger={["click"]} key="changestatus"> <Dropdown menu={statusMenu} trigger={["click"]} key="changestatus">
<Button shape="round"> <Button shape="round">
<span>{job.status}</span> <span>{job.status}</span>

View File

@@ -1,6 +1,6 @@
import { DownCircleFilled } from "@ant-design/icons"; import { DownCircleFilled } from "@ant-design/icons";
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Button, Dropdown, Menu, notification } from "antd"; import { Button, Dropdown, notification } from "antd";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -81,32 +81,28 @@ export function JobsChangeStatus({ job, bodyshop, jobRO, insertAuditTrail }) {
} }
}, [job, setAvailableStatuses, bodyshop]); }, [job, setAvailableStatuses, bodyshop]);
const statusmenu = ( const statusMenu = {
<Menu items: [
onClick={(e) => { ...availableStatuses.map((item) => ({
updateJobStatus(e.key); key: item,
}} label: item,
items={[ })),
...availableStatuses.map((item) => ({ ...(job.converted
key: item, ? [
label: item, { key: "divider", label: <hr />, disabled: true },
})), ...otherStages.map((item) => ({
...(job.converted key: item,
? [ label: item,
{ key: "divider", label: <hr />, disabled: true }, })),
...otherStages.map((item) => ({ ]
key: item, : []),
label: item, ],
})), onClick: (e) => updateJobStatus(e.key)
] }
: []),
]}
/>
);
return ( return (
<Dropdown <Dropdown
menu={statusmenu} menu={statusMenu}
trigger={["click"]} trigger={["click"]}
key="changestatus" key="changestatus"
disabled={jobRO || !job.converted} disabled={jobRO || !job.converted}

View File

@@ -1,4 +1,4 @@
import { Button, Dropdown, Menu } from "antd"; import { Button, Dropdown } from "antd";
import _ from "lodash"; import _ from "lodash";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -62,19 +62,17 @@ export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
); );
}; };
const overlay = (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && ( const menu = {
<Menu items: bodyshop.md_responsibility_centers.dms_defaults.map((mapping) => ({
onClick={handleMenuClick} key: mapping.name,
items={bodyshop.md_responsibility_centers.dms_defaults.map((mapping) => ({ label: mapping.name,
key: mapping.name, disabled: disabled,
label: mapping.name, })),
disabled: disabled, onClick: handleMenuClick,
}))} }
/>
);
return bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? ( return bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? (
<Dropdown menu={overlay}> <Dropdown menu={menu}>
<Button disabled={disabled}>{t("jobs.actions.dmsautoallocate")}</Button> <Button disabled={disabled}>{t("jobs.actions.dmsautoallocate")}</Button>
</Dropdown> </Dropdown>
) : ( ) : (

View File

@@ -1,5 +1,5 @@
import { DownOutlined } from "@ant-design/icons"; import { DownOutlined } from "@ant-design/icons";
import { Dropdown, Menu } from "antd"; import { Dropdown } from "antd";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -15,16 +15,14 @@ export function JobsDetailChangeEstimator({ disabled, form, bodyshop }) {
form.setFieldsValue(est); form.setFieldsValue(est);
}; };
const menu = ( const menu = {
<Menu items: bodyshop.md_estimators.map((est, idx) => ({
onClick={handleClick}
items={bodyshop.md_estimators.map((est, idx) => ({
key: idx, key: idx,
label: `${est.est_ct_fn} ${est.est_ct_ln}`, label: `${est.est_ct_fn} ${est.est_ct_ln}`,
value: est, value: est,
}))} })),
/> onClick: handleClick
); }
return ( return (
<Dropdown menu={menu} disabled={disabled}> <Dropdown menu={menu} disabled={disabled}>

View File

@@ -15,20 +15,18 @@ export function JobsDetailChangeFilehandler({ disabled, form, bodyshop }) {
form.setFieldsValue(est); form.setFieldsValue(est);
}; };
const menu = ( const menu = {
<Menu items: bodyshop.md_filehandlers.map((est, idx) => ({
onClick={handleClick} key: idx,
style={{ label: `${est.ins_ct_fn} ${est.ins_ct_ln}`,
columnCount: Math.floor(bodyshop.md_filehandlers.length / 10) + 1, value: est,
}} style: { breakInside: "avoid" },
items={bodyshop.md_filehandlers.map((est, idx) => ({ })),
key: idx, style: {
label: `${est.ins_ct_fn} ${est.ins_ct_ln}`, columnCount: Math.floor(bodyshop.md_filehandlers.length / 10) + 1,
value: est, },
style: { breakInside: "avoid" }, onClick: handleClick
}))} }
/>
);
return ( return (
<Dropdown menu={menu} disabled={disabled}> <Dropdown menu={menu} disabled={disabled}>

View File

@@ -1,5 +1,5 @@
import { DownOutlined } from "@ant-design/icons"; import { DownOutlined } from "@ant-design/icons";
import { Dropdown, Menu } from "antd"; import { Dropdown } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -18,16 +18,14 @@ export function JobsDetailRatesChangeButton({ disabled, form, bodyshop }) {
form.setFieldsValue({ ...rate, labor_rate_desc: rate.rate_label }); form.setFieldsValue({ ...rate, labor_rate_desc: rate.rate_label });
}; };
const menu = ( const menu = {
<Menu items: bodyshop.md_labor_rates.map((rate, idx) => ({
onClick={handleClick} key: idx,
items={bodyshop.md_labor_rates.map((rate, idx) => ({ label: rate.rate_label,
key: idx, value: rate,
label: rate.rate_label, })),
value: rate, onClick: handleClick
}))} }
/>
);
return ( return (
<Dropdown menu={menu} disabled={disabled}> <Dropdown menu={menu} disabled={disabled}>

View File

@@ -1,53 +1,52 @@
import { DownOutlined } from "@ant-design/icons"; import {DownOutlined} from "@ant-design/icons";
import { Dropdown, Menu } from "antd"; import {Dropdown} from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import {useTranslation} from "react-i18next";
import { connect } from "react-redux"; import {connect} from "react-redux";
import { createStructuredSelector } from "reselect"; import {createStructuredSelector} from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {selectBodyshop} from "../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language)) //setUserLanguage: language => dispatch(setUserLanguage(language))
}); });
export function NotesPresetButton({ bodyshop, form }) { export function NotesPresetButton({bodyshop, form}) {
const { t } = useTranslation(); const {t} = useTranslation();
const handleSelect = (item) => { const handleSelect = (item) => {
form.setFieldsValue({ text: item.text }); form.setFieldsValue({text: item.text});
}; };
const menu = (
<Menu
style={{
columnCount: Math.floor(bodyshop.md_notes_presets.length / 10) + 1,
}}
items={bodyshop.md_notes_presets.map((i, idx) => ({
key: idx,
label: i.label,
style: { breakInside: "avoid" },
onClick: () => handleSelect(i),
}))}
/>
);
return ( const menu = {
<div> items: bodyshop.md_notes_presets.map((i, idx) => ({
<Dropdown trigger={["click"]} menu={menu}> key: idx,
<a label: i.label,
className="ant-dropdown-link" style: {breakInside: "avoid"},
href="# " onClick: () => handleSelect(i),
onClick={(e) => e.preventDefault()} })),
> style: {
{t("messaging.labels.presets")} <DownOutlined /> columnCount: Math.floor(bodyshop.md_notes_presets.length / 10) + 1,
</a> },
</Dropdown> }
</div>
); return (
<div>
<Dropdown trigger={["click"]} menu={menu}>
<a
className="ant-dropdown-link"
href="# "
onClick={(e) => e.preventDefault()}
>
{t("messaging.labels.presets")} <DownOutlined/>
</a>
</Dropdown>
</div>
);
} }
export default connect(mapStateToProps, mapDispatchToProps)(NotesPresetButton); export default connect(mapStateToProps, mapDispatchToProps)(NotesPresetButton);

View File

@@ -1,97 +1,95 @@
import { DownOutlined } from "@ant-design/icons"; import {DownOutlined} from "@ant-design/icons";
import { Dropdown, InputNumber, Menu, Space } from "antd"; import {Dropdown, InputNumber, Space} from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import {useTranslation} from "react-i18next";
export default function PartsOrderModalPriceChange({ form, field }) {
const { t } = useTranslation();
const menu = (
<Menu
onClick={({ key }) => {
if (key === "custom") return;
const values = form.getFieldsValue();
const { parts_order_lines } = values; export default function PartsOrderModalPriceChange({form, field}) {
const {t} = useTranslation();
const menu = {
items: [
{
key: "5",
label: t("parts_orders.labels.discount", {percent: "5%"}),
},
{
key: "10",
label: t("parts_orders.labels.discount", {percent: "10%"}),
},
{
key: "15",
label: t("parts_orders.labels.discount", {percent: "15%"}),
},
{
key: "20",
label: t("parts_orders.labels.discount", {percent: "20%"}),
},
{
key: "25",
label: t("parts_orders.labels.discount", {percent: "25%"}),
},
{
key: "custom",
label: (
<InputNumber
onClick={(e) => e.stopPropagation()}
addonAfter="%"
onKeyUp={(e) => {
if (e.key === "Enter") {
const values = form.getFieldsValue();
const {parts_order_lines} = values;
form.setFieldsValue({ form.setFieldsValue({
parts_order_lines: { parts_order_lines: {
data: parts_order_lines.data.map((p, idx) => { data: parts_order_lines.data.map((p, idx) => {
if (idx !== field.name) return p; if (idx !== field.name) return p;
return { console.log(
...p, p,
act_price: (p.act_price || 0) * ((100 - key) / 100), e.target.value,
}; (p.act_price || 0) *
}), ((100 - (e.target.value || 0)) / 100)
}, );
}); return {
}} ...p,
items={[ act_price:
{ (p.act_price || 0) *
key: "5", ((100 - (e.target.value || 0)) / 100),
label: t("parts_orders.labels.discount", { percent: "5%" }), };
}, }),
{ },
key: "10", });
label: t("parts_orders.labels.discount", { percent: "10%" }), e.target.value = 0;
}, }
{ }}
key: "15", min={0}
label: t("parts_orders.labels.discount", { percent: "15%" }), max={100}
}, />
{ ),
key: "20", },
label: t("parts_orders.labels.discount", { percent: "20%" }), ],
}, onClick: ({key}) => {
{ if (key === "custom") return;
key: "25", const values = form.getFieldsValue();
label: t("parts_orders.labels.discount", { percent: "25%" }), const {parts_order_lines} = values;
}, form.setFieldsValue({
{ parts_order_lines: {
key: "custom", data: parts_order_lines.data.map((p, idx) => {
label: (
<InputNumber
onClick={(e) => e.stopPropagation()}
addonAfter="%"
onKeyUp={(e) => {
if (e.key === "Enter") {
const values = form.getFieldsValue();
const { parts_order_lines } = values;
form.setFieldsValue({
parts_order_lines: {
data: parts_order_lines.data.map((p, idx) => {
if (idx !== field.name) return p; if (idx !== field.name) return p;
console.log(
p,
e.target.value,
(p.act_price || 0) *
((100 - (e.target.value || 0)) / 100)
);
return { return {
...p, ...p,
act_price: act_price: (p.act_price || 0) * ((100 - key) / 100),
(p.act_price || 0) *
((100 - (e.target.value || 0)) / 100),
}; };
}), }),
}, },
}); });
e.target.value = 0; }
} };
}}
min={0} return (
max={100} <Dropdown menu={menu} trigger="click">
/> <Space>
), %
}, <DownOutlined/>
]} </Space>
/> </Dropdown>
); );
return (
<Dropdown menu={menu} trigger="click">
<Space>
%
<DownOutlined />
</Space>
</Dropdown>
);
} }

View File

@@ -39,16 +39,14 @@ export function PartsOrderModalComponent({bodyshop, vendorList, sendTypeState, i
form.setFieldsValue({comments: item.props.value}); form.setFieldsValue({comments: item.props.value});
}; };
const menu = ( const menu = {
<Menu items: bodyshop.md_parts_order_comment.map((comment, idx) => ({
onClick={handleClick} key: idx,
items={bodyshop.md_parts_order_comment.map((comment, idx) => ({ label: comment.label,
key: idx, value: comment.comment,
label: comment.label, })),
value: comment.comment, onClick: handleClick
}))} };
/>
);
return ( return (
<div> <div>

View File

@@ -47,21 +47,21 @@ export function ProductionColumnsComponent({
state: tableState, state: tableState,
activeStatuses: bodyshop.md_ro_statuses.active_statuses, activeStatuses: bodyshop.md_ro_statuses.active_statuses,
}); });
const menu = (
<Menu const menu = {
onClick={handleAdd} items: cols
style={{ .filter((i) => !columnKeys.includes(i.key))
columnCount: Math.max(Math.floor(cols.length / 10), 1), .map((item) => ({
}} key: item.key,
items={cols label: item.title,
.filter((i) => !columnKeys.includes(i.key)) style: { breakInside: "avoid" },
.map((item) => ({ })),
key: item.key, style: {
label: item.title, columnCount: Math.max(Math.floor(cols.length / 10), 1),
style: { breakInside: "avoid" }, },
}))} onClick: handleAdd,
/> };
);
return ( return (
<div> <div>
<Dropdown menu={menu}> <Dropdown menu={menu}>

View File

@@ -1,6 +1,6 @@
import { ExclamationCircleFilled } from "@ant-design/icons"; import { ExclamationCircleFilled } from "@ant-design/icons";
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Dropdown, Menu } from "antd"; import { Dropdown } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
@@ -51,23 +51,21 @@ export function ProductionListColumnAlert({ record, insertAuditTrail }) {
}); });
}; };
const menu = {
items: [
{
key: "toggleAlert",
label: record.production_vars && record.production_vars.alert
? t("production.labels.alertoff")
: t("production.labels.alerton"),
onClick: handleAlertToggle,
},
]
};
return ( return (
<Dropdown <Dropdown
menu={ menu={menu} trigger={["contextMenu"]}>
<Menu
items={[
{
key: "toggleAlert",
label: record.production_vars && record.production_vars.alert
? t("production.labels.alertoff")
: t("production.labels.alerton"),
onClick: handleAlertToggle,
},
]}
/>
}
trigger={["contextMenu"]}
>
<div <div
style={{ style={{
//width: "100%", //width: "100%",

View File

@@ -29,33 +29,30 @@ export default function ProductionListColumnBodyPriority({ record }) {
}); });
}; };
const menu = {
items: [
{
key: "clearBodyPriority",
label: t("production.actions.bodypriority-clear"),
},
{
key: "set",
label: t("production.actions.bodypriority-set"),
children: new Array(15).fill().map((value, index) => ({
key: index + 1,
label: (
<div style={{ marginLeft: "2rem", marginRight: "2rem" }}>
{index + 1}
</div>
),
})),
},
],
onClick: handleSetBodyPriority
};
return ( return (
<Dropdown <Dropdown menu={menu} trigger={["click"]}>
menu={
<Menu
onClick={handleSetBodyPriority}
items={[
{
key: "clearBodyPriority",
label: t("production.actions.bodypriority-clear"),
},
{
key: "set",
label: t("production.actions.bodypriority-set"),
children: new Array(15).fill().map((value, index) => ({
key: index + 1,
label: (
<div style={{ marginLeft: "2rem", marginRight: "2rem" }}>
{index + 1}
</div>
),
})),
},
]}
/>
}
trigger={["click"]}
>
<div style={{ width: "100%", height: "19px" }}> <div style={{ width: "100%", height: "19px" }}>
{record.production_vars && record.production_vars.bodypriority} {record.production_vars && record.production_vars.bodypriority}
</div> </div>

View File

@@ -29,33 +29,31 @@ export default function ProductionListColumnDetailPriority({ record }) {
}); });
}; };
const menu = {
items: [
{
key: "clearDetailPriority",
label: t("production.actions.detailpriority-clear"),
},
{
key: "set",
label: t("production.actions.detailpriority-set"),
children: new Array(15).fill().map((value, index) => ({
key: index + 1,
label: (
<div style={{ marginLeft: "2rem", marginRight: "2rem" }}>
{index + 1}
</div>
),
})),
},
],
onClick: handleSetDetailPriority
}
return ( return (
<Dropdown <Dropdown
menu={ menu={menu} trigger={["click"]}>
<Menu
onClick={handleSetDetailPriority}
items={[
{
key: "clearDetailPriority",
label: t("production.actions.detailpriority-clear"),
},
{
key: "set",
label: t("production.actions.detailpriority-set"),
children: new Array(15).fill().map((value, index) => ({
key: index + 1,
label: (
<div style={{ marginLeft: "2rem", marginRight: "2rem" }}>
{index + 1}
</div>
),
})),
},
]}
/>
}
trigger={["click"]}
>
<div style={{ width: "100%", height: "19px" }}> <div style={{ width: "100%", height: "19px" }}>
{record.production_vars && record.production_vars.detailpriority} {record.production_vars && record.production_vars.detailpriority}
</div> </div>

View File

@@ -1,5 +1,5 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Dropdown, Menu } from "antd"; import { Dropdown } from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { UPDATE_JOB } from "../../graphql/jobs.queries";
@@ -29,33 +29,30 @@ export default function ProductionListColumnPaintPriority({ record }) {
}); });
}; };
const menu = {
items: [
{
key: "clearPaintPriority",
label: t("production.actions.paintpriority-clear"),
},
{
key: "set",
label: t("production.actions.paintpriority-set"),
children: new Array(15).fill().map((value, index) => ({
key: index + 1,
label: (
<div style={{ marginLeft: "2rem", marginRight: "2rem" }}>
{index + 1}
</div>
),
})),
},
],
onClick: handleSetPaintPriority
};
return ( return (
<Dropdown <Dropdown menu={menu} trigger={["click"]}>
menu={
<Menu
onClick={handleSetPaintPriority}
items={[
{
key: "clearPaintPriority",
label: t("production.actions.paintpriority-clear"),
},
{
key: "set",
label: t("production.actions.paintpriority-set"),
children: new Array(15).fill().map((value, index) => ({
key: index + 1,
label: (
<div style={{ marginLeft: "2rem", marginRight: "2rem" }}>
{index + 1}
</div>
),
})),
},
]}
/>
}
trigger={["click"]}
>
<div style={{ width: "100%", height: "19px" }}> <div style={{ width: "100%", height: "19px" }}>
{record.production_vars && record.production_vars.paintpriority} {record.production_vars && record.production_vars.paintpriority}
</div> </div>

View File

@@ -1,5 +1,5 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Dropdown, Menu, Spin } from "antd"; import { Dropdown, Spin } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -36,20 +36,20 @@ export function ProductionListColumnCategory({ record, bodyshop }) {
setLoading(false); setLoading(false);
}; };
const menu = {
items: bodyshop.md_categories.map((item) => ({
key: item,
label: item,
})),
onClick: handleSetStatus,
style: {
maxHeight: "200px",
overflowY: "auto",
}
};
return ( return (
<Dropdown <Dropdown menu={menu} trigger={["click"]}>
menu={
<Menu
style={{ maxHeight: "200px", overflowY: "auto" }}
onClick={handleSetStatus}
items={bodyshop.md_categories.map((item) => ({
key: item,
label: item,
}))}
/>
}
trigger={["click"]}
>
<div style={{ width: "100%", height: "19px", cursor: "pointer" }}> <div style={{ width: "100%", height: "19px", cursor: "pointer" }}>
{record.category} {record.category}
{loading && <Spin />} {loading && <Spin />}

View File

@@ -1,5 +1,5 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Dropdown, Menu, Spin } from "antd"; import { Dropdown, Spin } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -45,20 +45,20 @@ export function ProductionListColumnStatus({
setLoading(false); setLoading(false);
}; };
const menu = {
items: bodyshop.md_ro_statuses.production_statuses.map((item) => ({
key: item,
label: item,
})),
onClick: handleSetStatus,
style: {
maxHeight: "200px",
overflowY: "auto",
}
};
return ( return (
<Dropdown <Dropdown menu={menu} trigger={["click"]}>
menu={
<Menu
style={{ maxHeight: "200px", overflowY: "auto" }}
onClick={handleSetStatus}
items={bodyshop.md_ro_statuses.production_statuses.map((item) => ({
key: item,
label: item,
}))}
/>
}
trigger={["click"]}
>
<div style={{ width: "100%", height: "19px", cursor: "pointer" }}> <div style={{ width: "100%", height: "19px", cursor: "pointer" }}>
{record.status} {record.status}
{loading && <Spin />} {loading && <Spin />}

View File

@@ -1,4 +1,4 @@
import { Button, Dropdown, Menu } from "antd"; import { Button, Dropdown } from "antd";
import React, { useState } from "react"; import React, { useState } from "react";
import { TemplateList } from "../../utils/TemplateConstants"; import { TemplateList } from "../../utils/TemplateConstants";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -28,58 +28,55 @@ export default connect(
export function ProductionListPrint({ bodyshop }) { export function ProductionListPrint({ bodyshop }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
return ( const menu = {
<Dropdown items: [
trigger="click" ...Object.keys(ProdTemplates).map((key) => ({
menu={ key: key,
<Menu label: ProdTemplates[key].title,
onClick={async (e) => { })),
setLoading(true); {
await GenerateDocument( key: "production_by_technician_one",
{ label: t("reportcenter.templates.production_by_technician_one"),
name: ProdTemplates[e.key].key, children: bodyshop.employees
// variables: { id: contract.id }, .filter((e) => e.active)
}, .map((e) => ({
{},
"p"
);
setLoading(false);
}}
items={[
...Object.keys(ProdTemplates).map((key) => ({
key: key,
label: ProdTemplates[key].title,
})),
{
key: "production_by_technician_one",
label: t("reportcenter.templates.production_by_technician_one"),
children: bodyshop.employees
.filter((e) => e.active)
.map((e) => ({
key: e.id, key: e.id,
label: `${e.first_name} ${e.last_name}`, label: `${e.first_name} ${e.last_name}`,
})), })),
}, },
{ {
key: "production_by_category_one", key: "production_by_category_one",
label: t("reportcenter.templates.production_by_category_one"), label: t("reportcenter.templates.production_by_category_one"),
children: bodyshop.md_categories.map((e) => ({ children: bodyshop.md_categories.map((e) => ({
key: e, key: e,
label: e, label: e,
})), })),
}, },
{ {
key: "production_by_repair_status_one", key: "production_by_repair_status_one",
label: t("reportcenter.templates.production_by_repair_status_one"), label: t("reportcenter.templates.production_by_repair_status_one"),
children: bodyshop.md_ro_statuses.production_statuses.map((e) => ({ children: bodyshop.md_ro_statuses.production_statuses.map((e) => ({
key: e, key: e,
label: e, label: e,
})), })),
},
],
onClick: async (e) => {
setLoading(true);
await GenerateDocument(
{
name: ProdTemplates[e.key].key,
// variables: { id: contract.id },
}, },
]} {},
/> "p"
} );
> setLoading(false);
},
}
return (
<Dropdown trigger="click" menu={menu}>
<Button loading={loading}>{t("general.labels.print")}</Button> <Button loading={loading}>{t("general.labels.print")}</Button>
</Dropdown> </Dropdown>
); );

View File

@@ -1,6 +1,6 @@
import {SyncOutlined} from "@ant-design/icons"; import {SyncOutlined} from "@ant-design/icons";
import {useSplitTreatments} from "@splitsoftware/splitio-react"; import {useSplitTreatments} from "@splitsoftware/splitio-react";
import {Button, Dropdown, Input, Menu, Space, Statistic, Table,} from "antd"; import {Button, Dropdown, Input, Space, Statistic, Table,} from "antd";
import {PageHeader} from "@ant-design/pro-layout"; import {PageHeader} from "@ant-design/pro-layout";
import React, {useMemo, useState} from "react"; import React, {useMemo, useState} from "react";
import ReactDragListView from "react-drag-listview"; import ReactDragListView from "react-drag-listview";
@@ -28,10 +28,10 @@ export function ProductionListTable({loading, data, refetch, bodyshop, technicia
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");
const { treatments: {Production_List_Status_Colors} } = useSplitTreatments({ const {treatments: {Production_List_Status_Colors}} = useSplitTreatments({
attributes: {}, attributes: {},
names: ["Production_List_Status_Colors"], names: ["Production_List_Status_Colors"],
splitKey: bodyshop.imexshopid, splitKey: bodyshop.imexshopid,
}); });
@@ -105,25 +105,28 @@ export function ProductionListTable({loading, data, refetch, bodyshop, technicia
setColumns(nextColumns); setColumns(nextColumns);
}; };
const headerItem = (col) => (
<Dropdown const headerItem = (col) => {
className="prod-header-dropdown" const menu = {
menu={ onClick: removeColumn,
<Menu items: [
onClick={removeColumn} {
items={[ key: col.key,
{ label: t("production.actions.removecolumn"),
key: col.key, },
label: t("production.actions.removecolumn"), ]
}, }
]}
/> return (
} <Dropdown
trigger={["contextMenu"]} className="prod-header-dropdown"
> menu={menu}
<span>{col.title}</span> trigger={["contextMenu"]}
</Dropdown> >
); <span>{col.title}</span>
</Dropdown>
)
};
const dataSource = const dataSource =
searchText === "" searchText === ""

View File

@@ -1,5 +1,5 @@
import { useMutation } from "@apollo/client"; import { useMutation } from "@apollo/client";
import { Dropdown, Menu, notification } from "antd"; import { Dropdown, notification } from "antd";
import dayjs from "../../utils/day"; import dayjs from "../../utils/day";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -55,17 +55,15 @@ export function ScheduleBlockDay({
} }
}; };
const menu = ( const menu = {
<Menu items: [
onClick={handleMenu} {
items={[ key: "block",
{ label: t("appointments.actions.block"),
key: "block", },
label: t("appointments.actions.block"), ],
}, onClick: handleMenu,
]} }
/>
);
return ( return (
<Dropdown <Dropdown

View File

@@ -1,98 +1,88 @@
import { DownOutlined } from "@ant-design/icons"; import {DownOutlined} from "@ant-design/icons";
import { useMutation } from "@apollo/client"; import {useMutation} from "@apollo/client";
import { Dropdown, Menu } from "antd"; import {Dropdown} from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import {useTranslation} from "react-i18next";
import { connect } from "react-redux"; import {connect} from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import {useLocation, useNavigate} from "react-router-dom";
import { createStructuredSelector } from "reselect"; import {createStructuredSelector} from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils"; import {logImEXEvent} from "../../firebase/firebase.utils";
import { import {INSERT_TEMPLATE, QUERY_TEMPLATES_BY_NAME_FOR_DUPE,} from "../../graphql/templates.queries";
INSERT_TEMPLATE, import {selectBodyshop} from "../../redux/user/user.selectors";
QUERY_TEMPLATES_BY_NAME_FOR_DUPE,
} from "../../graphql/templates.queries";
import { selectBodyshop } from "../../redux/user/user.selectors";
import client from "../../utils/GraphQLClient"; import client from "../../utils/GraphQLClient";
import { TemplateList } from "../../utils/TemplateConstants"; import {TemplateList} from "../../utils/TemplateConstants";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
export default connect(mapStateToProps, null)(ShopTemplateAddComponent); export default connect(mapStateToProps, null)(ShopTemplateAddComponent);
export function ShopTemplateAddComponent({ export function ShopTemplateAddComponent({ bodyshop, shopTemplateList, refetch}) {
bodyshop, const {t} = useTranslation();
shopTemplateList, const search = queryString.parse(useLocation().search);
refetch, const history = useNavigate();
}) { const [insertTemplate] = useMutation(INSERT_TEMPLATE);
const { t } = useTranslation();
const search = queryString.parse(useLocation().search);
const history = useNavigate();
const [insertTemplate] = useMutation(INSERT_TEMPLATE);
const shopTemplateKeys = shopTemplateList.map((template) => template.name); const shopTemplateKeys = shopTemplateList.map((template) => template.name);
const availableTemplateKeys = Object.keys(TemplateList()).filter( const availableTemplateKeys = Object.keys(TemplateList()).filter(
(tkey) => !shopTemplateKeys.includes(tkey) (tkey) => !shopTemplateKeys.includes(tkey)
); );
const handleAdd = async (item) => { const handleAdd = async (item) => {
logImEXEvent("shop_template_add"); logImEXEvent("shop_template_add");
const defaultTemplateData = await client.query({ const defaultTemplateData = await client.query({
query: QUERY_TEMPLATES_BY_NAME_FOR_DUPE, query: QUERY_TEMPLATES_BY_NAME_FOR_DUPE,
variables: { name: item.key }, variables: {name: item.key},
}); });
const template = defaultTemplateData.data.templates.filter( const template = defaultTemplateData.data.templates.filter(
(t) => t.bodyshopid === null (t) => t.bodyshopid === null
)[0]; )[0];
const result = await insertTemplate({ const result = await insertTemplate({
variables: { variables: {
template: { template: {
name: item.key, name: item.key,
bodyshopid: bodyshop.id, bodyshopid: bodyshop.id,
jsontemplate: template && template.jsontemplate, jsontemplate: template && template.jsontemplate,
html: template && template.html, html: template && template.html,
query: template && template.query, query: template && template.query,
}, },
}, },
}); });
const returningId = result.data.insert_templates.returning[0].id; const returningId = result.data.insert_templates.returning[0].id;
search.customTemplateId = returningId; search.customTemplateId = returningId;
history({ search: queryString.stringify(search) }); history({search: queryString.stringify(search)});
if (!!refetch) refetch(); if (!!refetch) refetch();
}; };
const TemplateListGenerated = TemplateList(); const TemplateListGenerated = TemplateList();
const menu = ( const menu = {
<Menu onClick: handleAdd,
onClick={handleAdd}
items={ items: availableTemplateKeys.length > 0
availableTemplateKeys.length > 0 ? availableTemplateKeys.map((tkey) => ({
? availableTemplateKeys.map((tkey) => ({ key: tkey,
key: tkey, label: TemplateListGenerated[tkey].title,
label: TemplateListGenerated[tkey].title,
})) }))
: [ : [
{ {
key: "no-templates", key: "no-templates",
label: t("bodyshop.labels.notemplatesavailable"), label: t("bodyshop.labels.notemplatesavailable"),
disabled: true, disabled: true,
}, },
] ]
} };
/>
);
return ( return (
<Dropdown menu={menu}> <Dropdown menu={menu}>
<span> <span>
{t("bodyshop.actions.addtemplate")} <DownOutlined /> {t("bodyshop.actions.addtemplate")} <DownOutlined/>
</span> </span>
</Dropdown> </Dropdown>
); );
} }

View File

@@ -1,136 +1,118 @@
import { import {Button, Col, Dropdown, Form, Row, Space, Typography,} from "antd";
Button,
Col,
Dropdown,
Form,
Menu,
Row,
Space,
Typography,
} from "antd";
import {PageHeader} from "@ant-design/pro-layout"; import {PageHeader} from "@ant-design/pro-layout";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import {useTranslation} from "react-i18next";
import { connect } from "react-redux"; import {connect} from "react-redux";
import ContractConvertToRo from "../../components/contract-convert-to-ro/contract-convert-to-ro.component"; import ContractConvertToRo from "../../components/contract-convert-to-ro/contract-convert-to-ro.component";
import ContractCourtesyCarBlock from "../../components/contract-courtesy-car-block/contract-courtesy-car-block.component"; import ContractCourtesyCarBlock
from "../../components/contract-courtesy-car-block/contract-courtesy-car-block.component";
import ContractFormComponent from "../../components/contract-form/contract-form.component"; import ContractFormComponent from "../../components/contract-form/contract-form.component";
import ContractJobBlock from "../../components/contract-job-block/contract-job-block.component"; import ContractJobBlock from "../../components/contract-job-block/contract-job-block.component";
import { setModalContext } from "../../redux/modals/modals.actions"; import {setModalContext} from "../../redux/modals/modals.actions";
import { GenerateDocument } from "../../utils/RenderTemplate"; import {GenerateDocument} from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants"; import {TemplateList} from "../../utils/TemplateConstants";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setCourtesyCarReturnModalContext: (context) => setCourtesyCarReturnModalContext: (context) =>
dispatch(setModalContext({ context: context, modal: "courtesyCarReturn" })), dispatch(setModalContext({context: context, modal: "courtesyCarReturn"})),
}); });
export function ContractDetailPage({ export function ContractDetailPage({contract, job, courtesyCar, setCourtesyCarReturnModalContext, refetch, form, saveLoading}) {
contract, const {t} = useTranslation();
job, return (
courtesyCar, <div>
setCourtesyCarReturnModalContext, <Row align="middle">
refetch, <Typography.Title></Typography.Title>
form, </Row>
saveLoading, <PageHeader
}) { title={t("contracts.labels.agreement", {
const { t } = useTranslation(); agreement_num: contract && contract.agreementnumber,
return ( status: t(contract && contract.status),
<div> })}
<Row align="middle"> extra={
<Typography.Title></Typography.Title> <Form.Item shouldUpdate>
</Row> {() => {
<PageHeader const menu = {
title={t("contracts.labels.agreement", { onClick: (e) => {
agreement_num: contract && contract.agreementnumber, GenerateDocument(
status: t(contract && contract.status), {
})} name: TemplateList("courtesycarcontract")[e.key].key,
extra={ variables: {id: contract.id},
<Form.Item shouldUpdate> },
{() => { {},
return ( "p"
<Space> );
<Button },
type="primary" items: [
htmlType="submit" {
loading={saveLoading} key: "courtesy_car_contract",
> label: t("contracts.actions.printcontract"),
{t("general.actions.save")} },
</Button> {
<Button key: "courtesy_car_terms",
disabled={ label: t("printcenter.courtesycarcontract.courtesy_car_terms"),
!!!contract || },
(contract && contract.status !== "contracts.status.out") {
} key: "courtesy_car_impound",
onClick={() => { label: t("printcenter.courtesycarcontract.courtesy_car_impound"),
setCourtesyCarReturnModalContext({ },
actions: { refetch }, ]
context: { };
contractId: contract.id,
courtesyCarId: courtesyCar.id,
},
});
}}
>
{t("courtesycars.actions.return")}
</Button>
<Dropdown
trigger="click"
menu={
<Menu
onClick={(e) => {
GenerateDocument(
{
name: TemplateList("courtesycarcontract")[e.key].key,
variables: { id: contract.id },
},
{},
"p"
);
}}
items={[
{
key: "courtesy_car_contract",
label: t("contracts.actions.printcontract"),
},
{
key: "courtesy_car_terms",
label: t("printcenter.courtesycarcontract.courtesy_car_terms"),
},
{
key: "courtesy_car_impound",
label: t("printcenter.courtesycarcontract.courtesy_car_impound"),
},
]}
/>
}
>
<Button>{t("general.labels.print")}</Button>
</Dropdown>
<ContractConvertToRo return (
contract={contract} <Space>
disabled={form.isFieldsTouched()} <Button
/> type="primary"
</Space> htmlType="submit"
); loading={saveLoading}
}} >
</Form.Item> {t("general.actions.save")}
} </Button>
/> <Button
<Row gutter={[16, 16]}> disabled={
<Col sm={24} md={12}> !!!contract ||
<ContractJobBlock job={job} /> (contract && contract.status !== "contracts.status.out")
</Col> }
<Col sm={24} md={12}> onClick={() => {
<ContractCourtesyCarBlock courtesyCar={courtesyCar} /> setCourtesyCarReturnModalContext({
</Col> actions: {refetch},
<Col span={24}> context: {
<ContractFormComponent form={form} /> contractId: contract.id,
</Col> courtesyCarId: courtesyCar.id,
</Row> },
</div> });
); }}
>
{t("courtesycars.actions.return")}
</Button>
<Dropdown trigger="click" menu={menu}>
<Button>{t("general.labels.print")}</Button>
</Dropdown>
<ContractConvertToRo
contract={contract}
disabled={form.isFieldsTouched()}
/>
</Space>
);
}}
</Form.Item>
}
/>
<Row gutter={[16, 16]}>
<Col sm={24} md={12}>
<ContractJobBlock job={job}/>
</Col>
<Col sm={24} md={12}>
<ContractCourtesyCarBlock courtesyCar={courtesyCar}/>
</Col>
<Col span={24}>
<ContractFormComponent form={form}/>
</Col>
</Row>
</div>
);
} }
export default connect(null, mapDispatchToProps)(ContractDetailPage); export default connect(null, mapDispatchToProps)(ContractDetailPage);