Allow for Component Token Overrides.

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2023-12-28 17:33:21 -05:00
parent e5d8cc2bea
commit 79dce5d069
57 changed files with 1890 additions and 1861 deletions

View File

@@ -15,7 +15,7 @@ const BillLineSearchSelect = (
disabled={disabled}
ref={ref}
showSearch
dropdownMatchSelectWidth={false}
popupMatchSelectWidth={false}
// optionFilterProp="line_desc"
filterOption={(inputValue, option) => {
return (

View File

@@ -1,5 +1,5 @@
import {HomeFilled} from "@ant-design/icons";
import { Breadcrumb, Row, Col } from "antd";
import {Breadcrumb, Col, Row} from "antd";
import React from "react";
import {connect} from "react-redux";
import {Link} from "react-router-dom";
@@ -23,28 +23,36 @@ export function BreadCrumbs({ breadcrumbs, bodyshop }) {
names: ["OpenSearch"],
splitKey: bodyshop && bodyshop.imexshopid,
});
// TODO - Client Update - Technically key is not doing anything here
return (
<Row className="breadcrumb-container">
<Col xs={24} sm={24} md={16}>
<Breadcrumb separator=">">
<Breadcrumb.Item>
<Breadcrumb
separator=">"
items={[
{
key: "home",
title: (
<Link to={`/manage/`}>
<HomeFilled/>{" "}
{(bodyshop && bodyshop.shopname && `(${bodyshop.shopname})`) ||
""}
</Link>
</Breadcrumb.Item>
{breadcrumbs.map((item) =>
item.link ? (
<Breadcrumb.Item key={item.label}>
<Link to={item.link}>{item.label} </Link>
</Breadcrumb.Item>
) : (
<Breadcrumb.Item key={item.label}>{item.label}</Breadcrumb.Item>
)
)}
</Breadcrumb>
),
},
...breadcrumbs.map((item) =>
item.link
? {
key: item.label,
title: <Link to={item.link}>{item.label}</Link>,
}
: {
key: item.label,
title: item.label,
}
),
]}
/>
</Col>
<Col xs={24} sm={24} md={8}>
{OpenSearch.treatment === "on" ? <GlobalSearchOs/> : <GlobalSearch/>}
@@ -52,4 +60,5 @@ export function BreadCrumbs({ breadcrumbs, bodyshop }) {
</Row>
);
}
export default connect(mapStateToProps, null)(BreadCrumbs);

View File

@@ -16,19 +16,19 @@ const mapDispatchToProps = (dispatch) => ({
});
export function ChatPresetsComponent({ bodyshop, setMessage, className }) {
const menuItems = bodyshop.md_messaging_presets.map((i, idx) => ({
key: idx,
label: i.label,
onClick: () => setMessage(i.text),
}));
const menu = (
<Menu>
{bodyshop.md_messaging_presets.map((i, idx) => (
<Menu.Item onClick={() => setMessage(i.text)} key={idx}>
{i.label}
</Menu.Item>
))}
</Menu>
<Menu items={menuItems} />
);
return (
<div className={className}>
<Dropdown trigger={["click"]} overlay={menu}>
<Dropdown trigger={["click"]} menu={menu}>
<PlusCircleOutlined />
</Dropdown>
</div>

View File

@@ -19,7 +19,7 @@ export default function ChatTagRoComponent({
<Select
showSearch
autoFocus
dropdownMatchSelectWidth
popupMatchSelectWidth
placeholder={t("general.labels.search")}
filterOption={false}
onSearch={handleSearch}

View File

@@ -18,20 +18,20 @@ export function ContractsRatesChangeButton({ disabled, form, bodyshop }) {
form.setFieldsValue(rate);
};
const menuItems = bodyshop.md_ccc_rates.map((i, idx) => ({
key: idx,
label: i.label,
value: i,
}));
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.md_ccc_rates.map((rate, idx) => (
<Menu.Item value={rate} key={idx}>
{rate.label}
</Menu.Item>
))}
</Menu>
<Menu onClick={handleClick} items={menuItems} />
</div>
);
return (
<Dropdown overlay={menu} disabled={disabled}>
<Dropdown menu={menu} disabled={disabled}>
<a
className="ant-dropdown-link"
href=" #"

View File

@@ -178,6 +178,25 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
(t(c.status) || "").toLowerCase().includes(searchText.toLowerCase())
)
: courtesycars;
const menuItems = [
{
key: "courtesycar_inventory",
label: t("printcenter.courtesycarcontract.courtesy_car_inventory"),
onClick: () =>
GenerateDocument(
{
name: TemplateList("courtesycar").courtesy_car_inventory.key,
variables: {
//id: contract.id
},
},
{},
"p"
),
},
];
return (
<Card
title={t("menus.header.courtesycars")}
@@ -188,26 +207,8 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
</Button>
<Dropdown
trigger="click"
overlay={
<Menu>
<Menu.Item
onClick={() =>
GenerateDocument(
{
name: TemplateList("courtesycar").courtesy_car_inventory
.key,
variables: {
//id: contract.id
},
},
{},
"p"
)
}
>
{t("printcenter.courtesycarcontract.courtesy_car_inventory")}
</Menu.Item>
</Menu>
menu={
<Menu items={menuItems} />
}
>
<Button>{t("general.labels.print")}</Button>

View File

@@ -123,18 +123,16 @@ export function DashboardGridComponent({ currentUser, bodyshop }) {
[data]
);
const existingLayoutKeys = state.items.map((i) => i.i);
const menuItems = Object.keys(componentList).map((key) => ({
key: key,
label: componentList[key].label,
value: key,
disabled: existingLayoutKeys.includes(key),
}));
const addComponentOverlay = (
<Menu onClick={handleAddComponent}>
{Object.keys(componentList).map((key) => (
<Menu.Item
key={key}
value={key}
disabled={existingLayoutKeys.includes(key)}
>
{componentList[key].label}
</Menu.Item>
))}
</Menu>
<Menu onClick={handleAddComponent} items={menuItems} />
);
if (error) return <AlertComponent message={error.message} type="error" />;
@@ -147,7 +145,7 @@ export function DashboardGridComponent({ currentUser, bodyshop }) {
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Dropdown overlay={addComponentOverlay} trigger={["click"]}>
<Dropdown menu={addComponentOverlay} trigger={["click"]}>
<Button>{t("dashboard.actions.addcomponent")}</Button>
</Dropdown>
</Space>

View File

@@ -22,20 +22,22 @@ export default connect(mapStateToProps, mapDispatchToProps)(DmsLogEvents);
export function DmsLogEvents({ socket, logs, bodyshop }) {
return (
<Timeline pending
<Timeline
pending
reverse={true}
>
{logs.map((log, idx) => (
<Timeline.Item key={idx} color={LogLevelHierarchy(log.level)}>
items={logs.map((log, idx) => ({
key: idx,
color: LogLevelHierarchy(log.level),
label: (
<Space wrap align="start" style={{}}>
<Tag color={LogLevelHierarchy(log.level)}>{log.level}</Tag>
<span>{dayjs(log.timestamp).format("MM/DD/YYYY HH:mm:ss")}</span>
<Divider type="vertical" />
<span>{log.message}</span>
</Space>
</Timeline.Item>
))}
</Timeline>
),
}))}
/>
);
}

View File

@@ -292,36 +292,23 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
<div>
{t("jobs.fields.dms.payer.controlnumber")}{" "}
<Dropdown
overlay={
<Menu>
{bodyshop.cdk_configuration.controllist &&
bodyshop.cdk_configuration.controllist.map(
(key, idx) => (
<Menu.Item
key={idx}
onClick={() => {
menu={<Menu
items={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;
payers: form.getFieldValue("payers").map((row, mapIndex) => {
if (index !== mapIndex) return row;
return {
...row,
controlnumber:
key.controlnumber,
controlnumber: key.controlnumber,
};
}),
});
}}
>
{key.name}
</Menu.Item>
)
)}
</Menu>
}
},
}))}
/>}
>
<a href=" #" onClick={(e) => e.preventDefault()}>
<DownOutlined/>

View File

@@ -1,26 +1,12 @@
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, Menu, Select, Space, Tabs, Upload,} from "antd";
import _ from "lodash";
import React from "react";
import {useTranslation} from "react-i18next";
import {connect} from "react-redux";
import {createStructuredSelector} from "reselect";
import {selectEmailConfig} from "../../redux/email/email.selectors";
import {
selectBodyshop,
selectCurrentUser,
} from "../../redux/user/user.selectors";
import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
import {CreateExplorerLinkForJob} from "../../utils/localmedia";
import EmailDocumentsComponent from "../email-documents/email-documents.component";
@@ -65,40 +51,44 @@ export function EmailOverlayComponent({
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.employees
<Menu
onClick={handleClick}
items={[
...bodyshop.employees
.filter((e) => e.user_email)
.map((e, idx) => (
<Menu.Item value={e.user_email} key={idx}>
{`${e.first_name} ${e.last_name}`}
</Menu.Item>
))}
{bodyshop.md_to_emails.map((e, idx) => (
<Menu.Item value={e.emails} key={idx + "group"}>
{e.label}
</Menu.Item>
))}
</Menu>
</div>
.map((e, idx) => ({
key: idx,
label: `${e.first_name} ${e.last_name}`,
value: e.user_email,
})),
...bodyshop.md_to_emails.map((e, idx) => ({
key: idx + "group",
label: e.label,
value: e.emails,
})),
]}
/>
);
const menuCC = (
<div>
<Menu onClick={handle_CC_Click}>
{bodyshop.employees
<Menu
onClick={handle_CC_Click}
items={[
...bodyshop.employees
.filter((e) => e.user_email)
.map((e, idx) => (
<Menu.Item value={e.user_email} key={idx}>
{`${e.first_name} ${e.last_name}`}
</Menu.Item>
))}
{bodyshop.md_to_emails.map((e, idx) => (
<Menu.Item value={e.emails} key={idx + "group"}>
{e.label}
</Menu.Item>
))}
</Menu>
.map((e, idx) => ({
key: idx,
label: `${e.first_name} ${e.last_name}`,
value: e.user_email,
})),
...bodyshop.md_to_emails.map((e, idx) => ({
key: idx + "group",
label: e.label,
value: e.emails,
})),
]}
/>
</div>
);
@@ -129,7 +119,7 @@ export function EmailOverlayComponent({
label={
<Space>
{t("emails.fields.to")}
<Dropdown overlay={menu}>
<Dropdown menu={menu}>
<a
className="ant-dropdown-link"
href=" #"
@@ -154,7 +144,7 @@ export function EmailOverlayComponent({
label={
<Space>
{t("emails.fields.cc")}
<Dropdown overlay={menuCC}>
<Dropdown menu={menuCC}>
<a
className="ant-dropdown-link"
href=" #"
@@ -203,15 +193,24 @@ export function EmailOverlayComponent({
}}
</Form.Item>
<Tabs>
<Tabs.TabPane tab={t("emails.labels.documents")} key="documents">
<Tabs
defaultActiveKey="documents"
items={[
{
key: "documents",
tab: t("emails.labels.documents"),
children: (
<EmailDocumentsComponent
selectedMediaState={selectedMediaState}
form={form}
/>
</Tabs.TabPane>
<Tabs.TabPane tab={t("emails.labels.attachments")} key="attachments">
),
},
{
key: "attachments",
tab: t("emails.labels.attachments"),
children: (
<>
{bodyshop.uselocalmediaserver && emailConfig.jobid && (
<a href={CreateExplorerLinkForJob({jobid: emailConfig.jobid})}>
<Button>{t("documents.labels.openinexplorer")}</Button>
@@ -260,8 +259,11 @@ export function EmailOverlayComponent({
</>
</Upload.Dragger>
</Form.Item>
</Tabs.TabPane>
</Tabs>
</>
),
},
]}
/>
</div>
);
}

View File

@@ -38,17 +38,20 @@ export function JobAltTransportChange({ bodyshop, job }) {
}
};
const menu = (
<Menu selectedKeys={[job && job.alt_transport]} onClick={onClick}>
{bodyshop.appt_alt_transport &&
bodyshop.appt_alt_transport.map((alt) => (
<Menu.Item key={alt}>{alt}</Menu.Item>
))}
<Menu.Divider />
<Menu.Item key={"null"}>{t("general.actions.clear")}</Menu.Item>
</Menu>
<Menu
selectedKeys={[job && job.alt_transport]}
onClick={onClick}
items={[
...(bodyshop.appt_alt_transport || []).map((alt) => ({
key: alt,
label: alt,
})),
{ key: "null", label: t("general.actions.clear") },
]}
/>
);
return (
<Dropdown overlay={menu}>
<Dropdown menu={menu}>
<a href=" #" onClick={(e) => e.preventDefault()}>
<DownOutlined />
</a>

View File

@@ -45,20 +45,23 @@ export function ScheduleEventColor({ bodyshop, event }) {
?.label;
const menu = (
<Menu selectedKeys={[event.color]} onClick={onClick}>
{bodyshop.appt_colors &&
bodyshop.appt_colors.map((color) => (
<Menu.Item style={{ color: color.color.hex }} key={color.color.hex}>
{color.label}
</Menu.Item>
))}
<Menu.Divider />
<Menu.Item key={"null"}>{t("general.actions.clear")}</Menu.Item>
</Menu>
<Menu
selectedKeys={[event.color]}
onClick={onClick}
items={[
...(bodyshop.appt_colors || []).map((color) => ({
key: color.color.hex,
label: color.label,
style: { color: color.color.hex },
})),
{ key: "divider", label: <hr />, disabled: true },
{ key: "null", label: t("general.actions.clear") },
]}
/>
);
return (
<Dropdown overlay={menu}>
<Dropdown menu={menu}>
<a href=" #" onClick={(e) => e.preventDefault()}>
{selectedColor}
<DownOutlined />

View File

@@ -185,10 +185,14 @@ export function ScheduleEventComponent({
) : null}
{event.job ? (
<Dropdown
overlay={
<Menu>
<Menu.Item
onClick={() => {
menu={
<Menu
items={[
{
key: "email",
label: t("general.labels.email"),
disabled: event.arrived,
onClick: () => {
const Template = TemplateList("job").appointment_reminder;
GenerateDocument(
{
@@ -202,13 +206,13 @@ export function ScheduleEventComponent({
"e",
event.job && event.job.id
);
}}
disabled={event.arrived}
>
{t("general.labels.email")}
</Menu.Item>
<Menu.Item
onClick={() => {
},
},
{
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({
@@ -228,12 +232,10 @@ export function ScheduleEventComponent({
message: t("messaging.error.invalidphone"),
});
}
}}
disabled={event.arrived || !bodyshop.messagingservicesid}
>
{t("general.labels.sms")}
</Menu.Item>
</Menu>
},
},
]}
/>
}
>
<Button>{t("appointments.actions.sendreminder")}</Button>

View File

@@ -10,110 +10,179 @@ export default function JobDetailCardsDatesComponent({ loading, data }) {
return (
<CardTemplate loading={loading} title={t("jobs.labels.cards.dates")}>
{data ? (
<Timeline>
{!(
data.actual_in ||
data.scheduled_completion ||
data.scheduled_in ||
data.actual_completion ||
data.scheduled_delivery ||
data.actual_delivery ||
data.date_estimated ||
data.date_open ||
data.date_scheduled ||
data.date_invoiced ||
data.date_exported
) ? (
<div>{t("jobs.errors.nodates")}</div>
) : null}
{data.date_last_contacted ? (
<Timeline.Item>
<Timeline
items={[
...(data.date_last_contacted
? [
{
key: "date_last_contacted",
label: (
<>
<label>{t("jobs.fields.date_last_contacted")}: </label>
<DateTimeFormatter>{data.date_last_contacted}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_open ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.date_open
? [
{
key: "date_open",
label: (
<>
<label>{t("jobs.fields.date_open")}: </label>
<DateTimeFormatter>{data.date_open}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_estimated ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.date_estimated
? [
{
key: "date_estimated",
label: (
<>
<label>{t("jobs.fields.date_estimated")}: </label>
<DateTimeFormatter>{data.date_estimated}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_scheduled ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.date_scheduled
? [
{
key: "date_scheduled",
label: (
<>
<label>{t("jobs.fields.date_scheduled")}: </label>
<DateTimeFormatter>{data.date_scheduled}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.scheduled_in ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.scheduled_in
? [
{
key: "scheduled_in",
label: (
<>
<label>{t("jobs.fields.scheduled_in")}: </label>
<DateTimeFormatter>{data.scheduled_in}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.actual_in ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.actual_in
? [
{
key: "actual_in",
label: (
<>
<label>{t("jobs.fields.actual_in")}: </label>
<DateTimeFormatter>{data.actual_in}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_repairstarted ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.date_repairstarted
? [
{
key: "date_repairstarted",
label: (
<>
<label>{t("jobs.fields.date_repairstarted")}: </label>
<DateTimeFormatter>{data.date_repairstarted}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.scheduled_completion ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.scheduled_completion
? [
{
key: "scheduled_completion",
label: (
<>
<label>{t("jobs.fields.scheduled_completion")}: </label>
<DateTimeFormatter>{data.scheduled_completion}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.actual_completion ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.actual_completion
? [
{
key: "actual_completion",
label: (
<>
<label>{t("jobs.fields.actual_completion")}: </label>
<DateTimeFormatter>{data.actual_completion}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.scheduled_delivery ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.scheduled_delivery
? [
{
key: "scheduled_delivery",
label: (
<>
<label>{t("jobs.fields.scheduled_delivery")}: </label>
<DateTimeFormatter>{data.scheduled_delivery}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.actual_delivery ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.actual_delivery
? [
{
key: "actual_delivery",
label: (
<>
<label>{t("jobs.fields.actual_delivery")}: </label>
<DateTimeFormatter>{data.actual_delivery}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_invoiced ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.date_invoiced
? [
{
key: "date_invoiced",
label: (
<>
<label>{t("jobs.fields.date_invoiced")}: </label>
<DateTimeFormatter>{data.date_invoiced}</DateTimeFormatter>
</Timeline.Item>
) : null}
{data.date_exported ? (
<Timeline.Item>
</>
),
},
]
: []),
...(data.date_exported
? [
{
key: "date_exported",
label: (
<>
<label>{t("jobs.fields.date_exported")}: </label>
<DateTimeFormatter>{data.date_exported}</DateTimeFormatter>
</Timeline.Item>
) : null}
</Timeline>
) : null}
</>
),
},
]
: []),
]}
/>) : null}
</CardTemplate>
);
}

View File

@@ -27,10 +27,12 @@ export default function JobLinesExpander({ jobline, jobid }) {
<Typography.Title level={4}>
{t("parts_orders.labels.parts_orders")}
</Typography.Title>
<Timeline>
{data.parts_order_lines.length > 0 ? (
data.parts_order_lines.map((line) => (
<Timeline.Item key={line.id}>
<Timeline
items={
data.parts_order_lines.length > 0
? data.parts_order_lines.map((line) => ({
key: line.id,
label: (
<Space split={<Divider type="vertical"/>} wrap>
<Link
to={`/manage/jobs/${jobid}?partsorderid=${line.parts_order.id}`}
@@ -40,21 +42,24 @@ export default function JobLinesExpander({ jobline, jobid }) {
<DateFormatter>{line.parts_order.order_date}</DateFormatter>
{line.parts_order.vendor.name}
</Space>
</Timeline.Item>
))
) : (
<Timeline.Item>
{t("parts_orders.labels.notyetordered")}
</Timeline.Item>
)}
</Timeline>
</Col>
),
}))
: [
{
key: "no-orders",
label: t("parts_orders.labels.notyetordered"),
},
]
}
/> </Col>
<Col md={24} lg={12}>
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
<Timeline>
{data.billlines.length > 0 ? (
data.billlines.map((line) => (
<Timeline.Item key={line.id}>
<Timeline
items={
data.billlines.length > 0
? data.billlines.map((line) => ({
key: line.id,
label: (
<Row wrap>
<Col span={4}>
<Link
@@ -64,30 +69,26 @@ export default function JobLinesExpander({ jobline, jobid }) {
</Link>
</Col>
<Col span={4}>
<span>
{`${t("billlines.fields.actual_price")}: `}
<CurrencyFormatter>{line.actual_price}</CurrencyFormatter>
</span>
<span>{`${t("billlines.fields.actual_price")}: `}<CurrencyFormatter>{line.actual_price}</CurrencyFormatter></span>
</Col>
<Col span={4}>
<span>
{`${t("billlines.fields.actual_cost")}: `}
<CurrencyFormatter>{line.actual_cost}</CurrencyFormatter>
</span>
<span>{`${t("billlines.fields.actual_cost")}: `}<CurrencyFormatter>{line.actual_cost}</CurrencyFormatter></span>
</Col>
<Col span={4}>
<DateFormatter>{line.bill.date}</DateFormatter>
</Col>
<Col span={4}> {line.bill.vendor.name}</Col>
</Row>
</Timeline.Item>
))
) : (
<Timeline.Item>
{t("parts_orders.labels.notyetordered")}
</Timeline.Item>
)}
</Timeline>
),
}))
: [
{
key: "no-orders",
label: t("parts_orders.labels.notyetordered"),
},
]
}
/>
</Col>
</Row>
);

View File

@@ -411,14 +411,17 @@ export function JobLinesComponent({
};
const markMenu = (
<Menu onClick={handleMark}>
<Menu.Item key="PAA">{t("joblines.fields.part_types.PAA")}</Menu.Item>
<Menu.Item key="PAN">{t("joblines.fields.part_types.PAN")}</Menu.Item>
<Menu.Item key="PAL">{t("joblines.fields.part_types.PAL")}</Menu.Item>
<Menu.Item key="PAS">{t("joblines.fields.part_types.PAS")}</Menu.Item>
<Menu.Divider />
<Menu.Item key="clear">{t("general.labels.clear")}</Menu.Item>
</Menu>
<Menu
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") },
{ key: "divider", label: <hr />, disabled: true },
{ key: "clear", label: t("general.labels.clear") },
]}
/>
);
return (
@@ -549,7 +552,7 @@ export function JobLinesComponent({
>
<FilterFilled /> {t("jobs.actions.filterpartsonly")}
</Button>
<Dropdown overlay={markMenu} trigger={["click"]}>
<Dropdown menu={markMenu} trigger={["click"]}>
<Button>{t("jobs.actions.mark")}</Button>
</Dropdown>
<Button

View File

@@ -57,7 +57,7 @@ export function JobLineLocationPopup({ bodyshop, jobline, disabled }) {
<Select
autoFocus
allowClear
dropdownMatchSelectWidth={100}
popupMatchSelectWidth={100}
value={location}
onClear={() => setLocation(null)}
onSelect={handleChange}

View File

@@ -57,7 +57,7 @@ export function JobLineStatusPopup({ bodyshop, jobline, disabled }) {
<Select
autoFocus
allowClear
dropdownMatchSelectWidth={100}
popupMatchSelectWidth={100}
value={status}
onSelect={handleChange}
onBlur={handleSave}

View File

@@ -29,22 +29,18 @@ export function JoblinePresetButton({ bodyshop, form }) {
1
),
}}
>
{bodyshop.md_jobline_presets.map((i, idx) => (
<Menu.Item
onClick={() => handleSelect(i)}
key={idx}
style={{ breakInside: "avoid" }}
>
{i.label}
</Menu.Item>
))}
</Menu>
items={bodyshop.md_jobline_presets.map((i, idx) => ({
key: idx,
label: i.label,
style: { breakInside: "avoid" },
onClick: () => handleSelect(i),
}))}
/>
);
return (
<div>
<Dropdown trigger={["click"]} overlay={menu}>
<Dropdown trigger={["click"]} menu={menu}>
<a
className="ant-dropdown-link"
href="# "

View File

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

View File

@@ -86,24 +86,27 @@ export function JobsChangeStatus({ job, bodyshop, jobRO, insertAuditTrail }) {
onClick={(e) => {
updateJobStatus(e.key);
}}
>
{availableStatuses.map((item) => (
<Menu.Item key={item}>{item}</Menu.Item>
))}
{job.converted && (
<>
<Menu.Divider />
{otherStages.map((item, idx) => (
<Menu.Item key={item}>{item}</Menu.Item>
))}
</>
)}
</Menu>
items={[
...availableStatuses.map((item) => ({
key: item,
label: item,
})),
...(job.converted
? [
{ key: "divider", label: <hr />, disabled: true },
...otherStages.map((item) => ({
key: item,
label: item,
})),
]
: []),
]}
/>
);
return (
<Dropdown
overlay={statusmenu}
menu={statusmenu}
trigger={["click"]}
key="changestatus"
disabled={jobRO || !job.converted}

View File

@@ -63,17 +63,18 @@ export function JobsCloseAutoAllocate({ bodyshop, joblines, form, disabled }) {
};
const overlay = (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
<Menu onClick={handleMenuClick}>
{bodyshop.md_responsibility_centers.dms_defaults.map((mapping) => (
<Menu.Item disabled={disabled} key={mapping.name}>
{mapping.name}
</Menu.Item>
))}
</Menu>
<Menu
onClick={handleMenuClick}
items={bodyshop.md_responsibility_centers.dms_defaults.map((mapping) => ({
key: mapping.name,
label: mapping.name,
disabled: disabled,
}))}
/>
);
return bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? (
<Dropdown overlay={overlay}>
<Dropdown menu={overlay}>
<Button disabled={disabled}>{t("jobs.actions.dmsautoallocate")}</Button>
</Dropdown>
) : (

View File

@@ -16,19 +16,18 @@ export function JobsDetailChangeEstimator({ disabled, form, bodyshop }) {
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.md_estimators.map((est, idx) => (
<Menu.Item value={est} key={idx}>
{`${est.est_ct_fn} ${est.est_ct_ln}`}
</Menu.Item>
))}
</Menu>
</div>
<Menu
onClick={handleClick}
items={bodyshop.md_estimators.map((est, idx) => ({
key: idx,
label: `${est.est_ct_fn} ${est.est_ct_ln}`,
value: est,
}))}
/>
);
return (
<Dropdown overlay={menu} disabled={disabled}>
<Dropdown menu={menu} disabled={disabled}>
<a
className="ant-dropdown-link"
href=" #"

View File

@@ -21,17 +21,17 @@ export function JobsDetailChangeFilehandler({ disabled, form, bodyshop }) {
style={{
columnCount: Math.floor(bodyshop.md_filehandlers.length / 10) + 1,
}}
>
{bodyshop.md_filehandlers.map((est, idx) => (
<Menu.Item value={est} key={idx} style={{ breakInside: "avoid" }}>
{`${est.ins_ct_fn} ${est.ins_ct_ln}`}
</Menu.Item>
))}
</Menu>
items={bodyshop.md_filehandlers.map((est, idx) => ({
key: idx,
label: `${est.ins_ct_fn} ${est.ins_ct_ln}`,
value: est,
style: { breakInside: "avoid" },
}))}
/>
);
return (
<Dropdown overlay={menu} disabled={disabled}>
<Dropdown menu={menu} disabled={disabled}>
<a
className="ant-dropdown-link"
href=" #"

View File

@@ -560,7 +560,7 @@ export function JobsDetailHeaderActions({
</Menu>
);
return (
<Dropdown overlay={statusmenu} trigger={["click"]} key="changestatus">
<Dropdown menu={statusmenu} trigger={["click"]} key="changestatus">
<Button>
<span>{t("general.labels.actions")}</span>

View File

@@ -19,19 +19,18 @@ export function JobsDetailRatesChangeButton({ disabled, form, bodyshop }) {
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.md_labor_rates.map((rate, idx) => (
<Menu.Item value={rate} key={idx}>
{rate.rate_label}
</Menu.Item>
))}
</Menu>
</div>
<Menu
onClick={handleClick}
items={bodyshop.md_labor_rates.map((rate, idx) => ({
key: idx,
label: rate.rate_label,
value: rate,
}))}
/>
);
return (
<Dropdown overlay={menu} disabled={disabled}>
<Dropdown menu={menu} disabled={disabled}>
<a
className="ant-dropdown-link"
href=" #"

View File

@@ -26,22 +26,18 @@ export function NotesPresetButton({ bodyshop, form }) {
style={{
columnCount: Math.floor(bodyshop.md_notes_presets.length / 10) + 1,
}}
>
{bodyshop.md_notes_presets.map((i, idx) => (
<Menu.Item
onClick={() => handleSelect(i)}
key={idx}
style={{ breakInside: "avoid" }}
>
{i.label}
</Menu.Item>
))}
</Menu>
items={bodyshop.md_notes_presets.map((i, idx) => ({
key: idx,
label: i.label,
style: { breakInside: "avoid" },
onClick: () => handleSelect(i),
}))}
/>
);
return (
<div>
<Dropdown trigger={["click"]} overlay={menu}>
<Dropdown trigger={["click"]} menu={menu}>
<a
className="ant-dropdown-link"
href="# "

View File

@@ -87,7 +87,7 @@ export default function PartsOrderModalPriceChange({ form, field }) {
/>
);
return (
<Dropdown overlay={menu} trigger="click">
<Dropdown menu={menu} trigger="click">
<Space>
%
<DownOutlined />

View File

@@ -40,15 +40,14 @@ export function PartsOrderModalComponent({bodyshop, vendorList, sendTypeState, i
};
const menu = (
<div>
<Menu onClick={handleClick}>
{bodyshop.md_parts_order_comment.map((comment, idx) => (
<Menu.Item value={comment.comment} key={idx}>
{comment.label}
</Menu.Item>
))}
</Menu>
</div>
<Menu
onClick={handleClick}
items={bodyshop.md_parts_order_comment.map((comment, idx) => ({
key: idx,
label: comment.label,
value: comment.comment,
}))}
/>
);
return (
@@ -286,7 +285,7 @@ export function PartsOrderModalComponent({bodyshop, vendorList, sendTypeState, i
label={
<Space>
{t("parts_orders.fields.comments")}
<Dropdown overlay={menu}>
<Dropdown menu={menu}>
<a
className="ant-dropdown-link"
href=" #"

View File

@@ -53,19 +53,18 @@ export function ProductionColumnsComponent({
style={{
columnCount: Math.max(Math.floor(cols.length / 10), 1),
}}
>
{cols
items={cols
.filter((i) => !columnKeys.includes(i.key))
.map((item) => (
<Menu.Item key={item.key} style={{ breakInside: "avoid" }}>
{item.title}
</Menu.Item>
))}
</Menu>
.map((item) => ({
key: item.key,
label: item.title,
style: { breakInside: "avoid" },
}))}
/>
);
return (
<div>
<Dropdown overlay={menu}>
<Dropdown menu={menu}>
<Button>{t("production.actions.addcolumns")}</Button>
</Dropdown>
</div>

View File

@@ -53,14 +53,18 @@ export function ProductionListColumnAlert({ record, insertAuditTrail }) {
return (
<Dropdown
overlay={
<Menu>
<Menu.Item key="toggleAlert" onClick={handleAlertToggle}>
{record.production_vars && record.production_vars.alert
menu={
<Menu
items={[
{
key: "toggleAlert",
label: record.production_vars && record.production_vars.alert
? t("production.labels.alertoff")
: t("production.labels.alerton")}
</Menu.Item>
</Menu>
: t("production.labels.alerton"),
onClick: handleAlertToggle,
},
]}
/>
}
trigger={["contextMenu"]}
>

View File

@@ -31,24 +31,28 @@ export default function ProductionListColumnBodyPriority({ record }) {
return (
<Dropdown
overlay={
<Menu onClick={handleSetBodyPriority}>
<Menu.Item key="clearBodyPriority">
{t("production.actions.bodypriority-clear")}
</Menu.Item>
<Menu.SubMenu
key="set"
title={t("production.actions.bodypriority-set")}
>
{new Array(15).fill().map((value, index) => (
<Menu.Item key={index + 1}>
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>
</Menu.Item>
))}
</Menu.SubMenu>
</Menu>
),
})),
},
]}
/>
}
trigger={["click"]}
>

View File

@@ -55,7 +55,7 @@ export default function ProductionListDate({
(dayjs().add(1, "day").isSame(dayjs(record[field]), "day") &&
"production-completion-soon"));
}
// TODO - Client Update = Why is the overlay a card?
return (
<Dropdown
trigger={["click"]}

View File

@@ -31,24 +31,28 @@ export default function ProductionListColumnDetailPriority({ record }) {
return (
<Dropdown
overlay={
<Menu onClick={handleSetDetailPriority}>
<Menu.Item key="clearDetailPriority">
{t("production.actions.detailpriority-clear")}
</Menu.Item>
<Menu.SubMenu
key="set"
title={t("production.actions.detailpriority-set")}
>
{new Array(15).fill().map((value, index) => (
<Menu.Item key={index + 1}>
menu={
<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>
</Menu.Item>
))}
</Menu.SubMenu>
</Menu>
),
})),
},
]}
/>
}
trigger={["click"]}
>

View File

@@ -89,6 +89,7 @@ export function ProductionLastContacted({ currentUser, record }) {
}
}, [visible, form, record.date_last_contacted]);
// TODO - Client Update - Why is this a card?
return (
<div>
<Dropdown

View File

@@ -31,24 +31,28 @@ export default function ProductionListColumnPaintPriority({ record }) {
return (
<Dropdown
overlay={
<Menu onClick={handleSetPaintPriority}>
<Menu.Item key="clearPaintPriority">
{t("production.actions.paintpriority-clear")}
</Menu.Item>
<Menu.SubMenu
key="set"
title={t("production.actions.paintpriority-set")}
>
{new Array(15).fill().map((value, index) => (
<Menu.Item key={index + 1}>
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>
</Menu.Item>
))}
</Menu.SubMenu>
</Menu>
),
})),
},
]}
/>
}
trigger={["click"]}
>

View File

@@ -38,15 +38,15 @@ export function ProductionListColumnCategory({ record, bodyshop }) {
return (
<Dropdown
overlay={
menu={
<Menu
style={{ maxHeight: "200px", overflowY: "auto" }}
onClick={handleSetStatus}
>
{bodyshop.md_categories.map((item) => (
<Menu.Item key={item}>{item}</Menu.Item>
))}
</Menu>
items={bodyshop.md_categories.map((item) => ({
key: item,
label: item,
}))}
/>
}
trigger={["click"]}
>

View File

@@ -47,15 +47,15 @@ export function ProductionListColumnStatus({
return (
<Dropdown
overlay={
menu={
<Menu
style={{ maxHeight: "200px", overflowY: "auto" }}
onClick={handleSetStatus}
>
{bodyshop.md_ro_statuses.production_statuses.map((item) => (
<Menu.Item key={item}>{item}</Menu.Item>
))}
</Menu>
items={bodyshop.md_ro_statuses.production_statuses.map((item) => ({
key: item,
label: item,
}))}
/>
}
trigger={["click"]}
>

View File

@@ -31,16 +31,13 @@ export function ProductionListPrint({ bodyshop }) {
return (
<Dropdown
trigger="click"
overlay={
<Menu>
{Object.keys(ProdTemplates).map((key) => (
<Menu.Item
key={key}
onClick={async () => {
menu={
<Menu
onClick={async (e) => {
setLoading(true);
await GenerateDocument(
{
name: ProdTemplates[key].key,
name: ProdTemplates[e.key].key,
// variables: { id: contract.id },
},
{},
@@ -48,82 +45,39 @@ export function ProductionListPrint({ bodyshop }) {
);
setLoading(false);
}}
>
{ProdTemplates[key].title}
</Menu.Item>
))}
<Menu.SubMenu
title={t("reportcenter.templates.production_by_technician_one")}
>
{bodyshop.employees
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) => (
<Menu.Item
key={e.id}
onClick={async () => {
setLoading(true);
await GenerateDocument(
{
name: production_by_technician_one.key,
variables: { id: e.id },
.map((e) => ({
key: e.id,
label: `${e.first_name} ${e.last_name}`,
})),
},
{},
"p"
);
setLoading(false);
}}
>
{e.first_name} {e.last_name}
</Menu.Item>
))}
</Menu.SubMenu>
<Menu.SubMenu
title={t("reportcenter.templates.production_by_category_one")}
>
{bodyshop.md_categories.map((e) => (
<Menu.Item
key={e}
onClick={async () => {
setLoading(true);
await GenerateDocument(
{
name: production_by_category_one.key,
variables: { category: e },
key: "production_by_category_one",
label: t("reportcenter.templates.production_by_category_one"),
children: bodyshop.md_categories.map((e) => ({
key: e,
label: e,
})),
},
{},
"p"
);
setLoading(false);
}}
>
{e}
</Menu.Item>
))}
</Menu.SubMenu>
<Menu.SubMenu
title={t("reportcenter.templates.production_by_repair_status_one")}
>
{bodyshop.md_ro_statuses.production_statuses.map((e) => (
<Menu.Item
key={e}
onClick={async () => {
setLoading(true);
await GenerateDocument(
{
name: production_by_repair_status_one.key,
variables: { status: e },
key: "production_by_repair_status_one",
label: t("reportcenter.templates.production_by_repair_status_one"),
children: bodyshop.md_ro_statuses.production_statuses.map((e) => ({
key: e,
label: e,
})),
},
{},
"p"
);
setLoading(false);
}}
>
{e}
</Menu.Item>
))}
</Menu.SubMenu>
</Menu>
]}
/>
}
>
<Button loading={loading}>{t("general.labels.print")}</Button>

View File

@@ -115,7 +115,7 @@ export function ProductionListTable({
onSelect={handleSelect}
placeholder={t("production.labels.selectview")}
optionLabelProp="label"
dropdownMatchSelectWidth={false}
popupMatchSelectWidth={false}
defaultValue={defaultView}
>
{bodyshop.production_config.map((config) => (

View File

@@ -108,12 +108,16 @@ export function ProductionListTable({loading, data, refetch, bodyshop, technicia
const headerItem = (col) => (
<Dropdown
className="prod-header-dropdown"
overlay={
<Menu onClick={removeColumn}>
<Menu.Item key={col.key}>
{t("production.actions.removecolumn")}
</Menu.Item>
</Menu>
menu={
<Menu
onClick={removeColumn}
items={[
{
key: col.key,
label: t("production.actions.removecolumn"),
},
]}
/>
}
trigger={["contextMenu"]}
>

View File

@@ -56,14 +56,20 @@ export function ScheduleBlockDay({
};
const menu = (
<Menu onClick={handleMenu}>
<Menu.Item key="block">{t("appointments.actions.block")}</Menu.Item>
</Menu>
<Menu
onClick={handleMenu}
items={[
{
key: "block",
label: t("appointments.actions.block"),
},
]}
/>
);
return (
<Dropdown
overlay={menu}
menu={menu}
disabled={alreadyBlocked}
trigger={["contextMenu"]}
>

View File

@@ -21,28 +21,25 @@ export default function ScheduleExistingAppointmentsList({
return (
<div>
{t("appointments.labels.priorappointments")}
<Timeline>
{existingAppointments.data
? existingAppointments.data.appointments.map((item) => {
return (
<Timeline.Item
key={item.id}
color={
item.canceled ? "red" : item.arrived ? "green" : "blue"
}
>
<Timeline
items={
existingAppointments.data
? existingAppointments.data.appointments.map((item) => ({
key: item.id,
color: item.canceled ? "red" : item.arrived ? "green" : "blue",
label: (
<>
{item.canceled
? t("appointments.labels.cancelledappointment")
: item.arrived
? t("appointments.labels.arrivedon")
: t("appointments.labels.scheduledfor")}
<DateTimeFormatter>{item.start}</DateTimeFormatter>
</Timeline.Item>
);
})
: null}
</Timeline>
</div>
</>
),
}))
: []
}
/></div>
);
}

View File

@@ -88,6 +88,8 @@ export default function ScoreboardEntryEdit({ entry }) {
</Card>
);
// TODO Client Update, why is this a card
return (
<div>
<Dropdown open={visible} overlay={popContent}>

View File

@@ -58,47 +58,63 @@ export function ShopInfoComponent({bodyshop, form, saveLoading}) {
search: `?tab=${search.tab}&subtab=${key}`,
})
}
>
<Tabs.TabPane key="general" tab={t("bodyshop.labels.shopinfo")}>
<ShopInfoGeneral form={form}/>
</Tabs.TabPane>
<Tabs.TabPane key="speedprint" tab={t("bodyshop.labels.speedprint")}>
<ShopInfoSpeedPrint form={form}/>
</Tabs.TabPane>
<Tabs.TabPane key="rbac" tab={t("bodyshop.labels.rbac")}>
<ShopInfoRbacComponent form={form}/>
</Tabs.TabPane>
<Tabs.TabPane key="roStatus" tab={t("bodyshop.labels.jobstatuses")}>
<ShopInfoROStatusComponent form={form}/>
</Tabs.TabPane>
<Tabs.TabPane key="scheduling" tab={t("bodyshop.labels.scheduling")}>
<ShopInfoSchedulingComponent form={form}/>
</Tabs.TabPane>
<Tabs.TabPane
key="orderStatus"
tab={t("bodyshop.labels.orderstatuses")}
>
<ShopInfoOrderStatusComponent form={form}/>
</Tabs.TabPane>
<Tabs.TabPane
key="responsibilityCenters"
tab={t("bodyshop.labels.responsibilitycenters.title")}
>
<ShopInfoResponsibilityCenterComponent form={form}/>
</Tabs.TabPane>
<Tabs.TabPane key="checklists" tab={t("bodyshop.labels.checklists")}>
<ShopInfoIntakeChecklistComponent form={form}/>
</Tabs.TabPane>
<Tabs.TabPane key="laborrates" tab={t("bodyshop.labels.laborrates")}>
<ShopInfoLaborRates form={form}/>
</Tabs.TabPane>
{CriticalPartsScanning.treatment === "on" && (
<Tabs.TabPane key="partsscan" tab={t("bodyshop.labels.partsscan")}>
<ShopInfoPartsScan form={form}/>
</Tabs.TabPane>
)}
</Tabs>
items={[
{
key: "general",
tab: t("bodyshop.labels.shopinfo"),
children: <ShopInfoGeneral form={form}/>,
},
{
key: "speedprint",
tab: t("bodyshop.labels.speedprint"),
children: <ShopInfoSpeedPrint form={form}/>,
},
{
key: "rbac",
tab: t("bodyshop.labels.rbac"),
children: <ShopInfoRbacComponent form={form}/>,
},
{
key: "roStatus",
tab: t("bodyshop.labels.jobstatuses"),
children: <ShopInfoROStatusComponent form={form}/>,
},
{
key: "scheduling",
tab: t("bodyshop.labels.scheduling"),
children: <ShopInfoSchedulingComponent form={form}/>,
},
{
key: "orderStatus",
tab: t("bodyshop.labels.orderstatuses"),
children: <ShopInfoOrderStatusComponent form={form}/>,
},
{
key: "responsibilityCenters",
tab: t("bodyshop.labels.responsibilitycenters.title"),
children: <ShopInfoResponsibilityCenterComponent form={form}/>,
},
{
key: "checklists",
tab: t("bodyshop.labels.checklists"),
children: <ShopInfoIntakeChecklistComponent form={form}/>,
},
{
key: "laborrates",
tab: t("bodyshop.labels.laborrates"),
children: <ShopInfoLaborRates form={form}/>,
},
...(CriticalPartsScanning.treatment === "on"
? [
{
key: "partsscan",
tab: t("bodyshop.labels.partsscan"),
children: <ShopInfoPartsScan form={form}/>,
},
]
: []),
]}
/>
</Card>
);
}

View File

@@ -69,19 +69,27 @@ export function ShopTemplateAddComponent({
};
const TemplateListGenerated = TemplateList();
const menu = (
<Menu onClick={handleAdd}>
{availableTemplateKeys.length > 0 ? (
availableTemplateKeys.map((tkey) => (
<Menu.Item key={tkey}>{TemplateListGenerated[tkey].title}</Menu.Item>
))
) : (
<div>{t("bodyshop.labels.notemplatesavailable")}</div>
)}
</Menu>
<Menu
onClick={handleAdd}
items={
availableTemplateKeys.length > 0
? availableTemplateKeys.map((tkey) => ({
key: tkey,
label: TemplateListGenerated[tkey].title,
}))
: [
{
key: "no-templates",
label: t("bodyshop.labels.notemplatesavailable"),
disabled: true,
},
]
}
/>
);
return (
<Dropdown overlay={menu}>
<Dropdown menu={menu}>
<span>
{t("bodyshop.actions.addtemplate")} <DownOutlined />
</span>

View File

@@ -35,7 +35,7 @@ export default function ShopTemplatesListContainer({ visibleState }) {
};
return (
<Drawer
(<Drawer
placement="left"
width="25%"
open={visible}
@@ -64,7 +64,7 @@ export default function ShopTemplatesListContainer({ visibleState }) {
]}
>
<Skeleton title={false} loading={item.loading} active>
<div style={{ display: "flex", flexDirection: "column" }}>
<div rootStyle={{ display: "flex", flexDirection: "column" }}>
<div>{TemplateList()[item.name].title}</div>
<div>{TemplateList()[item.name].description}</div>
<div>{TemplateList()[item.name].drivingid}</div>
@@ -74,6 +74,6 @@ export default function ShopTemplatesListContainer({ visibleState }) {
)}
/>
</div>
</Drawer>
</Drawer>)
);
}

View File

@@ -6,7 +6,7 @@ import queryString from "query-string";
import React from "react";
import {useTranslation} from "react-i18next";
import {connect} from "react-redux";
import { useNavigate, useLocation } from "react-router-dom";
import {useLocation, useNavigate} from "react-router-dom";
import {createStructuredSelector} from "reselect";
import {GET_JOB_BY_PK} from "../../graphql/jobs.queries";
import {setModalContext} from "../../redux/modals/modals.actions";
@@ -106,33 +106,46 @@ export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
>
<JobsDetailHeader job={data.jobs_by_pk} disabled/>
<Divider type="horizontal"/>
<Tabs size="large">
<Tabs.TabPane key="lines" tab={t("jobs.labels.lines")}>
<Tabs
size="large"
defaultActiveKey="lines"
items={[
{
key: "lines",
tab: t("jobs.labels.lines"),
children: (
<JobLinesContainer
jobId={selected}
joblines={data.jobs_by_pk.joblines}
job={data.jobs_by_pk}
refetch={refetch}
/>
</Tabs.TabPane>
<Tabs.TabPane key="documents" tab={t("jobs.labels.documents")}>
{bodyshop.uselocalmediaserver ? (
),
},
{
key: "documents",
tab: t("jobs.labels.documents"),
children: bodyshop.uselocalmediaserver ? (
<JobsDocumentsLocalGallery
job={data ? data.jobs_by_pk : null}
/>
) : (
<JobsDocumentsGalleryContainer jobId={searchParams.selected}/>
)}
</Tabs.TabPane>
<Tabs.TabPane key="notes" tab={t("jobs.labels.notes")}>
<JobNotesContainer jobId={searchParams.selected} />
</Tabs.TabPane>
</Tabs>
),
},
{
key: "notes",
tab: t("jobs.labels.notes"),
children: <JobNotesContainer jobId={searchParams.selected}/>,
},
]}
/>
</PageHeader>
) : null}
</Drawer>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps

View File

@@ -40,50 +40,60 @@ export function TechSider({ technician, techLogout }) {
collapsed={collapsed}
onCollapse={onCollapse}
>
<Menu theme="dark" defaultSelectedKeys={["1"]} mode="inline">
<Menu.Item
key="1"
disabled={!!technician}
icon={<Icon component={FiLogIn} />}
>
<Link to={`/tech/login`}>{t("menus.tech.login")}</Link>
</Menu.Item>
<Menu.Item key="2" disabled={!!!technician} icon={<SearchOutlined />}>
<Link to={`/tech/joblookup`}>{t("menus.tech.joblookup")}</Link>
</Menu.Item>
<Menu.Item
key="3"
disabled={!!!technician}
icon={<Icon component={FaBusinessTime} />}
>
<Link to={`/tech/jobclock`}>{t("menus.tech.jobclockin")}</Link>
</Menu.Item>
<Menu.Item
key="4"
disabled={!!!technician}
icon={<Icon component={MdTimer} />}
>
<Link to={`/tech/shiftclock`}>{t("menus.tech.shiftclockin")}</Link>
</Menu.Item>
<Menu.Item key="5" disabled={!!!technician} icon={<ScheduleOutlined />}>
<Link to={`/tech/list`}>{t("menus.tech.productionlist")}</Link>
</Menu.Item>
<Menu.Item
key="6"
disabled={!!!technician}
icon={<Icon component={BsKanban} />}
>
<Link to={`/tech/board`}> {t("menus.tech.productionboard")}</Link>
</Menu.Item>
<Menu.Item
key="7"
disabled={!!!technician}
onClick={() => techLogout()}
icon={<Icon component={FiLogOut} />}
>
{t("menus.tech.logout")}
</Menu.Item>
</Menu>
<Menu
theme="dark"
defaultSelectedKeys={["1"]}
mode="inline"
onClick={(e) => {
if (e.key === "7") {
techLogout();
}
}}
items={[
{
key: "1",
icon: <Icon component={FiLogIn} />,
disabled: !!technician,
label: <Link to={`/tech/login`}>{t("menus.tech.login")}</Link>,
},
{
key: "2",
icon: <SearchOutlined />,
disabled: !!!technician,
label: <Link to={`/tech/joblookup`}>{t("menus.tech.joblookup")}</Link>,
},
{
key: "3",
icon: <Icon component={FaBusinessTime} />,
disabled: !!!technician,
label: <Link to={`/tech/jobclock`}>{t("menus.tech.jobclockin")}</Link>,
},
{
key: "4",
icon: <Icon component={MdTimer} />,
disabled: !!!technician,
label: <Link to={`/tech/shiftclock`}>{t("menus.tech.shiftclockin")}</Link>,
},
{
key: "5",
icon: <ScheduleOutlined />,
disabled: !!!technician,
label: <Link to={`/tech/list`}>{t("menus.tech.productionlist")}</Link>,
},
{
key: "6",
icon: <Icon component={BsKanban} />,
disabled: !!!technician,
label: <Link to={`/tech/board`}>{t("menus.tech.productionboard")}</Link>,
},
{
key: "7",
icon: <Icon component={FiLogOut} />,
disabled: !!!technician,
label: t("menus.tech.logout"),
},
]}
/>
</Sider>
);
}

View File

@@ -36,7 +36,7 @@ const VendorSearchSelect = (
style={{
width: "100%",
}}
dropdownMatchSelectWidth={false}
popupMatchSelectWidth={false}
onChange={setOption}
optionFilterProp="name"
onSelect={onSelect}

View File

@@ -122,9 +122,8 @@ class Header extends React.Component {
mode={isMobile ? 'inline' : 'horizontal'}
defaultSelectedKeys={['sub0']}
theme="dark"
>
{navChildren}
</Menu>
items={navChildren}
/>
</TweenOne>
</div>
</TweenOne>

View File

@@ -77,58 +77,33 @@ export function ContractDetailPage({
</Button>
<Dropdown
trigger="click"
overlay={
<Menu>
<Menu.Item
onClick={() =>
menu={
<Menu
onClick={(e) => {
GenerateDocument(
{
name: TemplateList("courtesycarcontract")
.courtesy_car_contract.key,
name: TemplateList("courtesycarcontract")[e.key].key,
variables: { id: contract.id },
},
{},
"p"
)
}
>
{t("contracts.actions.printcontract")}
</Menu.Item>
<Menu.Item
onClick={() =>
GenerateDocument(
);
}}
items={[
{
name: TemplateList("courtesycarcontract")
.courtesy_car_terms.key,
variables: { id: contract.id },
key: "courtesy_car_contract",
label: t("contracts.actions.printcontract"),
},
{},
"p"
)
}
>
{t(
"printcenter.courtesycarcontract.courtesy_car_terms"
)}
</Menu.Item>
<Menu.Item
onClick={() =>
GenerateDocument(
{
name: TemplateList("courtesycarcontract")
.courtesy_car_impound.key,
variables: { id: contract.id },
key: "courtesy_car_terms",
label: t("printcenter.courtesycarcontract.courtesy_car_terms"),
},
{},
"p"
)
}
>
{t(
"printcenter.courtesycarcontract.courtesy_car_impound"
)}
</Menu.Item>
</Menu>
{
key: "courtesy_car_impound",
label: t("printcenter.courtesycarcontract.courtesy_car_impound"),
},
]}
/>
}
>
<Button>{t("general.labels.print")}</Button>

View File

@@ -258,131 +258,93 @@ export function JobsDetailPage({
defaultActiveKey={search.tab}
onChange={(key) => history({ search: `?tab=${key}` })}
tabBarStyle={{ fontWeight: "bold", borderBottom: "10px" }}
>
<Tabs.TabPane
forceRender
tab={
<span>
<Icon component={FaShieldAlt} />
{t("menus.jobsdetail.general")}
</span>
}
key="general"
>
<JobsDetailGeneral job={job} form={form} />
</Tabs.TabPane>
<Tabs.TabPane
forceRender
tab={
<span>
<BarsOutlined />
{t("menus.jobsdetail.repairdata")}
</span>
}
key="repairdata"
>
items={[
{
key: "general",
tab: (
<span><Icon component={FaShieldAlt} />{t("menus.jobsdetail.general")}</span>
),
forceRender: true,
children: <JobsDetailGeneral job={job} form={form} />,
},
{
key: "repairdata",
tab: (
<span><BarsOutlined />{t("menus.jobsdetail.repairdata")}</span>
),
forceRender: true,
children: (
<JobsLinesContainer
job={job}
joblines={job.joblines}
refetch={refetch}
form={form}
/>
</Tabs.TabPane>
<Tabs.TabPane
forceRender
tab={
<span>
<DollarCircleOutlined />
{t("menus.jobsdetail.rates")}
</span>
}
key="rates"
>
<JobsDetailRates job={job} form={form} />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<DollarCircleOutlined />
{t("menus.jobsdetail.totals")}
</span>
}
key="totals"
>
<JobsDetailTotals job={job} refetch={refetch} />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<ToolFilled />
{t("menus.jobsdetail.partssublet")}
</span>
}
key="partssublet"
>
<JobsDetailPliContainer job={job} />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<Icon component={FaHardHat} />
{t("menus.jobsdetail.labor")}
</span>
}
key="labor"
>
<JobsDetailLaborContainer job={job} jobId={job.id} />
</Tabs.TabPane>
<Tabs.TabPane
forceRender
tab={
<span>
<CalendarFilled />
{t("menus.jobsdetail.dates")}
</span>
}
key="dates"
>
<JobsDetailDatesComponent job={job} />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<FileImageFilled />
{t("jobs.labels.documents")}
</span>
}
key="documents"
>
{bodyshop.uselocalmediaserver ? (
),
},
{
key: "rates",
tab: (
<span><DollarCircleOutlined />{t("menus.jobsdetail.rates")}</span>
),
forceRender: true,
children: <JobsDetailRates job={job} form={form} />,
},
{
key: "totals",
tab: (
<span><DollarCircleOutlined />{t("menus.jobsdetail.totals")}</span>
),
children: <JobsDetailTotals job={job} refetch={refetch} />,
},
{
key: "partssublet",
tab: (
<span><ToolFilled />{t("menus.jobsdetail.partssublet")}</span>
),
children: <JobsDetailPliContainer job={job} />,
},
{
key: "labor",
tab: (
<span><Icon component={FaHardHat} />{t("menus.jobsdetail.labor")}</span>
),
children: <JobsDetailLaborContainer job={job} jobId={job.id} />,
},
{
key: "dates",
tab: (
<span><CalendarFilled />{t("menus.jobsdetail.dates")}</span>
),
forceRender: true,
children: <JobsDetailDatesComponent job={job} />,
},
{
key: "documents",
tab: (
<span><FileImageFilled />{t("jobs.labels.documents")}</span>
),
children: bodyshop.uselocalmediaserver ? (
<JobsDocumentsLocalGallery job={job} />
) : (
<JobsDocumentsGalleryContainer jobId={job.id} />
)}
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<Icon component={FaRegStickyNote} />
{t("jobs.labels.notes")}
</span>
}
key="notes"
>
<JobNotesContainer jobId={job.id} />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<HistoryOutlined />
{t("jobs.labels.audit")}
</span>
}
key="audit"
>
<JobAuditTrail jobId={job.id} />
</Tabs.TabPane>
</Tabs>
),
},
{
key: "notes",
tab: (
<span><Icon component={FaRegStickyNote} />{t("jobs.labels.notes")}</span>
),
children: <JobNotesContainer jobId={job.id} />,
},
{
key: "audit",
tab: (<span><HistoryOutlined />{t("jobs.labels.audit")}</span>
),
children: <JobAuditTrail jobId={job.id} />,
},
]}
/>
</Form>
</div>
);

View File

@@ -53,7 +53,7 @@ export function PhonebookContainer({ setBreadcrumbs, setSelectedHeader }) {
: "100%";
return (
<RbacWrapper action="phonebook:view">
(<RbacWrapper action="phonebook:view">
<PhonebookPage />
<Drawer
width={drawerPercentage}
@@ -61,11 +61,11 @@ export function PhonebookContainer({ setBreadcrumbs, setSelectedHeader }) {
delete search.phonebookentry;
navigate({ search: queryString.stringify(search) });
}}
visible={phonebookentry}
open={phonebookentry}
>
<PhonebookFormContainer />
</Drawer>
</RbacWrapper>
</RbacWrapper>)
);
}
export default connect(null, mapDispatchToProps)(PhonebookContainer);

View File

@@ -74,44 +74,30 @@ export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
search: queryString.stringify(searchParams),
});
}}
>
<Tabs.TabPane
tab={
<span>
<Icon component={FaShieldAlt} />
{t("scoreboard.labels.jobs")}
</span>
}
destroyInactiveTabPane
key="sb"
>
<ScoreboardDisplay />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<FieldTimeOutlined />
{t("scoreboard.labels.timeticketsemployee")}
</span>
}
destroyInactiveTabPane
key="tickets"
>
<ScoreboardTimeTickets />
</Tabs.TabPane>
<Tabs.TabPane
tab={
<span>
<FieldTimeOutlined />
{t("scoreboard.labels.allemployeetimetickets")}
</span>
}
destroyInactiveTabPane
key="ticketsstats"
>
<ScoreboardTimeTicketsStats />
</Tabs.TabPane>
</Tabs>
items={[
{
key: "sb",
tab: (<span><Icon component={FaShieldAlt} />{t("scoreboard.labels.jobs")}</span>
),
forceRender: true,
children: <ScoreboardDisplay />,
},
{
key: "tickets",
tab: (<span><FieldTimeOutlined />{t("scoreboard.labels.timeticketsemployee")}</span>
),
forceRender: true,
children: <ScoreboardTimeTickets />,
},
{
key: "ticketsstats",
tab: (<span><FieldTimeOutlined />{t("scoreboard.labels.allemployeetimetickets")}</span>
),
forceRender: true,
children: <ScoreboardTimeTicketsStats />,
},
]}
/>
</RbacWrapper>
</FeatureWrapper>
);

View File

@@ -26,19 +26,18 @@ export default function ShopVendorPageComponent() {
: "100%";
return (
<div>
(<div>
<VendorsListContainer />
<Drawer
width={drawerPercentage}
onClose={() => {
searchParams.delete("selectedvendor");
navigate({ search: searchParams.toString() });
}}
visible={selectedvendor}
open={selectedvendor}
>
<VendorsFormContainer />
</Drawer>
</div>
</div>)
);
}

View File

@@ -47,22 +47,31 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
return (
<RbacWrapper action="shop:config">
<Tabs
defaultActiveKey={search.tab}
activeKey={search.tab}
onChange={(key) => history({ search: `?tab=${key}` })}
>
<Tabs.TabPane tab={t("bodyshop.labels.shopinfo")} key="info">
<ShopInfoContainer />
</Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.employees")} key="employees">
<ShopEmployeesContainer />
</Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.licensing")} key="licensing">
<ShopInfoUsersComponent />
</Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.csiq")} key="csiq">
<ShopCsiConfig />
</Tabs.TabPane>
</Tabs>
tabs={[
{
key: "info",
tab: t("bodyshop.labels.shopinfo"),
children: <ShopInfoContainer />,
},
{
key: "employees",
tab: t("bodyshop.labels.employees"),
children: <ShopEmployeesContainer />,
},
{
key: "licensing",
tab: t("bodyshop.labels.licensing"),
children: <ShopInfoUsersComponent />,
},
{
key: "csiq",
tab: t("bodyshop.labels.csiq"),
children: <ShopCsiConfig />,
},
]}
/>
</RbacWrapper>
);
}