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} disabled={disabled}
ref={ref} ref={ref}
showSearch showSearch
dropdownMatchSelectWidth={false} popupMatchSelectWidth={false}
// optionFilterProp="line_desc" // optionFilterProp="line_desc"
filterOption={(inputValue, option) => { filterOption={(inputValue, option) => {
return ( return (

View File

@@ -1,55 +1,64 @@
import { HomeFilled } from "@ant-design/icons"; import {HomeFilled} from "@ant-design/icons";
import { Breadcrumb, Row, Col } from "antd"; import {Breadcrumb, Col, Row} from "antd";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import {connect} from "react-redux";
import { Link } from "react-router-dom"; import {Link} from "react-router-dom";
import { createStructuredSelector } from "reselect"; import {createStructuredSelector} from "reselect";
import { selectBreadcrumbs } from "../../redux/application/application.selectors"; import {selectBreadcrumbs} from "../../redux/application/application.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {selectBodyshop} from "../../redux/user/user.selectors";
import GlobalSearch from "../global-search/global-search.component"; import GlobalSearch from "../global-search/global-search.component";
import GlobalSearchOs from "../global-search/global-search-os.component"; import GlobalSearchOs from "../global-search/global-search-os.component";
import "./breadcrumbs.styles.scss"; import "./breadcrumbs.styles.scss";
import { useSplitTreatments } from "@splitsoftware/splitio-react"; import {useSplitTreatments} from "@splitsoftware/splitio-react";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
breadcrumbs: selectBreadcrumbs, breadcrumbs: selectBreadcrumbs,
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
export function BreadCrumbs({ breadcrumbs, bodyshop }) { export function BreadCrumbs({breadcrumbs, bodyshop}) {
const { treatments: {OpenSearch} } = useSplitTreatments({ const {treatments: {OpenSearch}} = useSplitTreatments({
attributes: {}, attributes: {},
names: ["OpenSearch"], names: ["OpenSearch"],
splitKey: bodyshop && bodyshop.imexshopid, splitKey: bodyshop && bodyshop.imexshopid,
}); });
// TODO - Client Update - Technically key is not doing anything here
return ( return (
<Row className="breadcrumb-container"> <Row className="breadcrumb-container">
<Col xs={24} sm={24} md={16}> <Col xs={24} sm={24} md={16}>
<Breadcrumb separator=">"> <Breadcrumb
<Breadcrumb.Item> separator=">"
items={[
{
key: "home",
title: (
<Link to={`/manage/`}> <Link to={`/manage/`}>
<HomeFilled />{" "} <HomeFilled/>{" "}
{(bodyshop && bodyshop.shopname && `(${bodyshop.shopname})`) || {(bodyshop && bodyshop.shopname && `(${bodyshop.shopname})`) ||
""} ""}
</Link> </Link>
</Breadcrumb.Item> ),
{breadcrumbs.map((item) => },
item.link ? ( ...breadcrumbs.map((item) =>
<Breadcrumb.Item key={item.label}> item.link
<Link to={item.link}>{item.label} </Link> ? {
</Breadcrumb.Item> key: item.label,
) : ( title: <Link to={item.link}>{item.label}</Link>,
<Breadcrumb.Item key={item.label}>{item.label}</Breadcrumb.Item> }
) : {
)} key: item.label,
</Breadcrumb> title: item.label,
}
),
]}
/>
</Col> </Col>
<Col xs={24} sm={24} md={8}> <Col xs={24} sm={24} md={8}>
{OpenSearch.treatment === "on" ? <GlobalSearchOs /> : <GlobalSearch />} {OpenSearch.treatment === "on" ? <GlobalSearchOs/> : <GlobalSearch/>}
</Col> </Col>
</Row> </Row>
); );
} }
export default connect(mapStateToProps, null)(BreadCrumbs); export default connect(mapStateToProps, null)(BreadCrumbs);

View File

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

View File

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

View File

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

View File

@@ -178,6 +178,25 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
(t(c.status) || "").toLowerCase().includes(searchText.toLowerCase()) (t(c.status) || "").toLowerCase().includes(searchText.toLowerCase())
) )
: courtesycars; : 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 ( return (
<Card <Card
title={t("menus.header.courtesycars")} title={t("menus.header.courtesycars")}
@@ -188,26 +207,8 @@ export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
</Button> </Button>
<Dropdown <Dropdown
trigger="click" trigger="click"
overlay={ menu={
<Menu> <Menu items={menuItems} />
<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>
} }
> >
<Button>{t("general.labels.print")}</Button> <Button>{t("general.labels.print")}</Button>

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
import { DeleteFilled, DownOutlined } from "@ant-design/icons"; import {DeleteFilled, DownOutlined} from "@ant-design/icons";
import { import {
Button, Button,
Card, Card,
@@ -17,11 +17,11 @@ import {
import Dinero from "dinero.js"; import Dinero from "dinero.js";
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";
import { connect } from "react-redux"; import {connect} from "react-redux";
import { createStructuredSelector } from "reselect"; import {createStructuredSelector} from "reselect";
import { determineDmsType } from "../../pages/dms/dms.container"; import {determineDmsType} from "../../pages/dms/dms.container";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {selectBodyshop} from "../../redux/user/user.selectors";
import i18n from "../../translations/i18n"; import i18n from "../../translations/i18n";
import DmsCdkMakes from "../dms-cdk-makes/dms-cdk-makes.component"; import DmsCdkMakes from "../dms-cdk-makes/dms-cdk-makes.component";
import DmsCdkMakesRefetch from "../dms-cdk-makes/dms-cdk-makes.refetch.component"; import DmsCdkMakesRefetch from "../dms-cdk-makes/dms-cdk-makes.refetch.component";
@@ -37,9 +37,9 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export default connect(mapStateToProps, mapDispatchToProps)(DmsPostForm); export default connect(mapStateToProps, mapDispatchToProps)(DmsPostForm);
export function DmsPostForm({ bodyshop, socket, job, logsRef }) { export function DmsPostForm({bodyshop, socket, job, logsRef}) {
const [form] = Form.useForm(); const [form] = Form.useForm();
const { t } = useTranslation(); const {t} = useTranslation();
const handlePayerSelect = (value, index) => { const handlePayerSelect = (value, index) => {
form.setFieldsValue({ form.setFieldsValue({
@@ -119,7 +119,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
}, },
]} ]}
> >
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="kmin" name="kmin"
@@ -132,7 +132,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
}, },
]} ]}
> >
<InputNumber disabled /> <InputNumber disabled/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="kmout" name="kmout"
@@ -145,13 +145,13 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
}, },
]} ]}
> >
<InputNumber disabled /> <InputNumber disabled/>
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
{bodyshop.cdk_dealerid && ( {bodyshop.cdk_dealerid && (
<div> <div>
<LayoutFormRow style={{ justifyContent: "center" }} grow> <LayoutFormRow style={{justifyContent: "center"}} grow>
<Form.Item <Form.Item
name="dms_make" name="dms_make"
label={t("jobs.fields.dms.dms_make")} label={t("jobs.fields.dms.dms_make")}
@@ -161,7 +161,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
}, },
]} ]}
> >
<Input disabled /> <Input disabled/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="dms_model" name="dms_model"
@@ -172,31 +172,31 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
}, },
]} ]}
> >
<Input disabled /> <Input disabled/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="inservicedate" name="inservicedate"
label={t("jobs.fields.dms.inservicedate")} label={t("jobs.fields.dms.inservicedate")}
> >
<FormDatePicker /> <FormDatePicker/>
</Form.Item> </Form.Item>
</LayoutFormRow> </LayoutFormRow>
<Space> <Space>
<DmsCdkMakes form={form} socket={socket} job={job} /> <DmsCdkMakes form={form} socket={socket} job={job}/>
<DmsCdkMakesRefetch /> <DmsCdkMakesRefetch/>
<Form.Item <Form.Item
name="dms_unsold" name="dms_unsold"
label={t("jobs.fields.dms.dms_unsold")} label={t("jobs.fields.dms.dms_unsold")}
initialValue={false} initialValue={false}
> >
<Switch /> <Switch/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
name="dms_model_override" name="dms_model_override"
label={t("jobs.fields.dms.dms_model_override")} label={t("jobs.fields.dms.dms_model_override")}
initialValue={false} initialValue={false}
> >
<Switch /> <Switch/>
</Form.Item> </Form.Item>
</Space> </Space>
</div> </div>
@@ -210,10 +210,10 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
}, },
]} ]}
> >
<Input.TextArea maxLength={240} /> <Input.TextArea maxLength={240}/>
</Form.Item> </Form.Item>
<Divider /> <Divider/>
<Space size="large" wrap align="center"> <Space size="large" wrap align="center">
<Statistic <Statistic
title={t("jobs.fields.ded_amt")} title={t("jobs.fields.ded_amt")}
@@ -231,7 +231,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
/> />
</Space> </Space>
<Form.List name={["payers"]}> <Form.List name={["payers"]}>
{(fields, { add, remove }) => { {(fields, {add, remove}) => {
return ( return (
<div> <div>
{fields.map((field, index) => ( {fields.map((field, index) => (
@@ -248,7 +248,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
]} ]}
> >
<Select <Select
style={{ minWidth: "15rem" }} style={{minWidth: "15rem"}}
onSelect={(value) => handlePayerSelect(value, index)} onSelect={(value) => handlePayerSelect(value, index)}
> >
{bodyshop.cdk_configuration && {bodyshop.cdk_configuration &&
@@ -271,7 +271,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
}, },
]} ]}
> >
<Input disabled /> <Input disabled/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@@ -284,7 +284,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
}, },
]} ]}
> >
<CurrencyInput min={0} /> <CurrencyInput min={0}/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
@@ -292,39 +292,26 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
<div> <div>
{t("jobs.fields.dms.payer.controlnumber")}{" "} {t("jobs.fields.dms.payer.controlnumber")}{" "}
<Dropdown <Dropdown
overlay={ menu={<Menu
<Menu> items={bodyshop.cdk_configuration.controllist?.map((key, idx) => ({
{bodyshop.cdk_configuration.controllist && key: idx,
bodyshop.cdk_configuration.controllist.map( label: key.name,
(key, idx) => ( onClick: () => {
<Menu.Item
key={idx}
onClick={() => {
form.setFieldsValue({ form.setFieldsValue({
payers: form payers: form.getFieldValue("payers").map((row, mapIndex) => {
.getFieldValue("payers") if (index !== mapIndex) return row;
.map((row, mapIndex) => {
if (index !== mapIndex)
return row;
return { return {
...row, ...row,
controlnumber: controlnumber: key.controlnumber,
key.controlnumber,
}; };
}), }),
}); });
}} },
> }))}
{key.name} />}
</Menu.Item>
)
)}
</Menu>
}
> >
<a href=" #" onClick={(e) => e.preventDefault()}> <a href=" #" onClick={(e) => e.preventDefault()}>
<DownOutlined /> <DownOutlined/>
</a> </a>
</Dropdown> </Dropdown>
</div> </div>
@@ -337,7 +324,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
}, },
]} ]}
> >
<Input /> <Input/>
</Form.Item> </Form.Item>
<Form.Item shouldUpdate> <Form.Item shouldUpdate>
@@ -393,7 +380,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
onClick={() => { onClick={() => {
if (fields.length < 3) add(); if (fields.length < 3) add();
}} }}
style={{ width: "100%" }} style={{width: "100%"}}
> >
{t("jobs.actions.dms.addpayer")} {t("jobs.actions.dms.addpayer")}
</Button> </Button>
@@ -411,7 +398,7 @@ export function DmsPostForm({ bodyshop, socket, job, logsRef }) {
payers && payers &&
payers.forEach((payer) => { payers.forEach((payer) => {
totalAllocated = totalAllocated.add( totalAllocated = totalAllocated.add(
Dinero({ amount: Math.round((payer?.amount || 0) * 100) }) Dinero({amount: Math.round((payer?.amount || 0) * 100)})
); );
}); });

View File

@@ -1,27 +1,13 @@
import { UploadOutlined, UserAddOutlined } from "@ant-design/icons"; import {UploadOutlined, UserAddOutlined} from "@ant-design/icons";
import { import {Button, Divider, Dropdown, Form, Input, Menu, Select, Space, Tabs, Upload,} from "antd";
Button,
Divider,
Dropdown,
Form,
Input,
Menu,
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";
import { connect } from "react-redux"; import {connect} from "react-redux";
import { createStructuredSelector } from "reselect"; import {createStructuredSelector} from "reselect";
import { selectEmailConfig } from "../../redux/email/email.selectors"; import {selectEmailConfig} from "../../redux/email/email.selectors";
import { import {selectBodyshop, selectCurrentUser,} from "../../redux/user/user.selectors";
selectBodyshop, import {CreateExplorerLinkForJob} from "../../utils/localmedia";
selectCurrentUser,
} from "../../redux/user/user.selectors";
import { CreateExplorerLinkForJob } from "../../utils/localmedia";
import EmailDocumentsComponent from "../email-documents/email-documents.component"; import EmailDocumentsComponent from "../email-documents/email-documents.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
@@ -43,9 +29,9 @@ export function EmailOverlayComponent({
selectedMediaState, selectedMediaState,
bodyshop, bodyshop,
currentUser, currentUser,
}) { }) {
const { t } = useTranslation(); const {t} = useTranslation();
const handleClick = ({ item, key, keyPath }) => { const handleClick = ({item, key, keyPath}) => {
const email = item.props.value; const email = item.props.value;
form.setFieldsValue({ form.setFieldsValue({
to: _.uniq([ to: _.uniq([
@@ -54,7 +40,7 @@ export function EmailOverlayComponent({
]), ]),
}); });
}; };
const handle_CC_Click = ({ item, key, keyPath }) => { const handle_CC_Click = ({item, key, keyPath}) => {
const email = item.props.value; const email = item.props.value;
form.setFieldsValue({ form.setFieldsValue({
cc: _.uniq([ cc: _.uniq([
@@ -65,40 +51,44 @@ export function EmailOverlayComponent({
}; };
const menu = ( const menu = (
<div> <Menu
<Menu onClick={handleClick}> onClick={handleClick}
{bodyshop.employees items={[
...bodyshop.employees
.filter((e) => e.user_email) .filter((e) => e.user_email)
.map((e, idx) => ( .map((e, idx) => ({
<Menu.Item value={e.user_email} key={idx}> key: idx,
{`${e.first_name} ${e.last_name}`} label: `${e.first_name} ${e.last_name}`,
</Menu.Item> value: e.user_email,
))} })),
{bodyshop.md_to_emails.map((e, idx) => ( ...bodyshop.md_to_emails.map((e, idx) => ({
<Menu.Item value={e.emails} key={idx + "group"}> key: idx + "group",
{e.label} label: e.label,
</Menu.Item> value: e.emails,
))} })),
</Menu> ]}
</div> />
); );
const menuCC = ( const menuCC = (
<div> <div>
<Menu onClick={handle_CC_Click}> <Menu
{bodyshop.employees onClick={handle_CC_Click}
items={[
...bodyshop.employees
.filter((e) => e.user_email) .filter((e) => e.user_email)
.map((e, idx) => ( .map((e, idx) => ({
<Menu.Item value={e.user_email} key={idx}> key: idx,
{`${e.first_name} ${e.last_name}`} label: `${e.first_name} ${e.last_name}`,
</Menu.Item> value: e.user_email,
))} })),
{bodyshop.md_to_emails.map((e, idx) => ( ...bodyshop.md_to_emails.map((e, idx) => ({
<Menu.Item value={e.emails} key={idx + "group"}> key: idx + "group",
{e.label} label: e.label,
</Menu.Item> value: e.emails,
))} })),
</Menu> ]}
/>
</div> </div>
); );
@@ -129,13 +119,13 @@ export function EmailOverlayComponent({
label={ label={
<Space> <Space>
{t("emails.fields.to")} {t("emails.fields.to")}
<Dropdown overlay={menu}> <Dropdown menu={menu}>
<a <a
className="ant-dropdown-link" className="ant-dropdown-link"
href=" #" href=" #"
onClick={(e) => e.preventDefault()} onClick={(e) => e.preventDefault()}
> >
<UserAddOutlined /> <UserAddOutlined/>
</a> </a>
</Dropdown> </Dropdown>
</Space> </Space>
@@ -148,26 +138,26 @@ export function EmailOverlayComponent({
}, },
]} ]}
> >
<Select mode="tags" tokenSeparators={[",", ";"]} /> <Select mode="tags" tokenSeparators={[",", ";"]}/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={ label={
<Space> <Space>
{t("emails.fields.cc")} {t("emails.fields.cc")}
<Dropdown overlay={menuCC}> <Dropdown menu={menuCC}>
<a <a
className="ant-dropdown-link" className="ant-dropdown-link"
href=" #" href=" #"
onClick={(e) => e.preventDefault()} onClick={(e) => e.preventDefault()}
> >
<UserAddOutlined /> <UserAddOutlined/>
</a> </a>
</Dropdown> </Dropdown>
</Space> </Space>
} }
name="cc" name="cc"
> >
<Select mode="tags" tokenSeparators={[",", ";"]} /> <Select mode="tags" tokenSeparators={[",", ";"]}/>
</Form.Item> </Form.Item>
<Form.Item <Form.Item
label={t("emails.fields.subject")} label={t("emails.fields.subject")}
@@ -179,7 +169,7 @@ export function EmailOverlayComponent({
}, },
]} ]}
> >
<Input /> <Input/>
</Form.Item> </Form.Item>
<Divider>{t("emails.labels.preview")}</Divider> <Divider>{t("emails.labels.preview")}</Divider>
@@ -197,23 +187,32 @@ export function EmailOverlayComponent({
backgroundColor: "lightgray", backgroundColor: "lightgray",
borderLeft: "6px solid #2196F3", borderLeft: "6px solid #2196F3",
}} }}
dangerouslySetInnerHTML={{ __html: form.getFieldValue("html") }} dangerouslySetInnerHTML={{__html: form.getFieldValue("html")}}
/> />
); );
}} }}
</Form.Item> </Form.Item>
<Tabs> <Tabs
<Tabs.TabPane tab={t("emails.labels.documents")} key="documents"> defaultActiveKey="documents"
items={[
{
key: "documents",
tab: t("emails.labels.documents"),
children: (
<EmailDocumentsComponent <EmailDocumentsComponent
selectedMediaState={selectedMediaState} selectedMediaState={selectedMediaState}
form={form} 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 && ( {bodyshop.uselocalmediaserver && emailConfig.jobid && (
<a href={CreateExplorerLinkForJob({ jobid: emailConfig.jobid })}> <a href={CreateExplorerLinkForJob({jobid: emailConfig.jobid})}>
<Button>{t("documents.labels.openinexplorer")}</Button> <Button>{t("documents.labels.openinexplorer")}</Button>
</a> </a>
)} )}
@@ -227,7 +226,7 @@ export function EmailOverlayComponent({
return e && e.fileList; return e && e.fileList;
}} }}
rules={[ rules={[
({ getFieldValue }) => ({ ({getFieldValue}) => ({
validator(rule, value) { validator(rule, value) {
const totalSize = value.reduce( const totalSize = value.reduce(
(acc, val) => (acc = acc + val.size), (acc, val) => (acc = acc + val.size),
@@ -252,7 +251,7 @@ export function EmailOverlayComponent({
> >
<> <>
<p className="ant-upload-drag-icon"> <p className="ant-upload-drag-icon">
<UploadOutlined /> <UploadOutlined/>
</p> </p>
<p className="ant-upload-text"> <p className="ant-upload-text">
Click or drag files to this area to upload. Click or drag files to this area to upload.
@@ -260,8 +259,11 @@ export function EmailOverlayComponent({
</> </>
</Upload.Dragger> </Upload.Dragger>
</Form.Item> </Form.Item>
</Tabs.TabPane> </>
</Tabs> ),
},
]}
/>
</div> </div>
); );
} }

View File

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

View File

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

View File

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

View File

@@ -1,119 +1,188 @@
import { Timeline } from "antd"; import {Timeline} from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import {useTranslation} from "react-i18next";
import { DateTimeFormatter } from "../../utils/DateFormatter"; import {DateTimeFormatter} from "../../utils/DateFormatter";
import CardTemplate from "./job-detail-cards.template.component"; import CardTemplate from "./job-detail-cards.template.component";
export default function JobDetailCardsDatesComponent({ loading, data }) { export default function JobDetailCardsDatesComponent({loading, data}) {
const { t } = useTranslation(); const {t} = useTranslation();
return ( return (
<CardTemplate loading={loading} title={t("jobs.labels.cards.dates")}> <CardTemplate loading={loading} title={t("jobs.labels.cards.dates")}>
{data ? ( {data ? (
<Timeline> <Timeline
{!( items={[
data.actual_in || ...(data.date_last_contacted
data.scheduled_completion || ? [
data.scheduled_in || {
data.actual_completion || key: "date_last_contacted",
data.scheduled_delivery || label: (
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>
<label>{t("jobs.fields.date_last_contacted")}: </label> <label>{t("jobs.fields.date_last_contacted")}: </label>
<DateTimeFormatter>{data.date_last_contacted}</DateTimeFormatter> <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> <label>{t("jobs.fields.date_open")}: </label>
<DateTimeFormatter>{data.date_open}</DateTimeFormatter> <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> <label>{t("jobs.fields.date_estimated")}: </label>
<DateTimeFormatter>{data.date_estimated}</DateTimeFormatter> <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> <label>{t("jobs.fields.date_scheduled")}: </label>
<DateTimeFormatter>{data.date_scheduled}</DateTimeFormatter> <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> <label>{t("jobs.fields.scheduled_in")}: </label>
<DateTimeFormatter>{data.scheduled_in}</DateTimeFormatter> <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> <label>{t("jobs.fields.actual_in")}: </label>
<DateTimeFormatter>{data.actual_in}</DateTimeFormatter> <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> <label>{t("jobs.fields.date_repairstarted")}: </label>
<DateTimeFormatter>{data.date_repairstarted}</DateTimeFormatter> <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> <label>{t("jobs.fields.scheduled_completion")}: </label>
<DateTimeFormatter>{data.scheduled_completion}</DateTimeFormatter> <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> <label>{t("jobs.fields.actual_completion")}: </label>
<DateTimeFormatter>{data.actual_completion}</DateTimeFormatter> <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> <label>{t("jobs.fields.scheduled_delivery")}: </label>
<DateTimeFormatter>{data.scheduled_delivery}</DateTimeFormatter> <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> <label>{t("jobs.fields.actual_delivery")}: </label>
<DateTimeFormatter>{data.actual_delivery}</DateTimeFormatter> <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> <label>{t("jobs.fields.date_invoiced")}: </label>
<DateTimeFormatter>{data.date_invoiced}</DateTimeFormatter> <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> <label>{t("jobs.fields.date_exported")}: </label>
<DateTimeFormatter>{data.date_exported}</DateTimeFormatter> <DateTimeFormatter>{data.date_exported}</DateTimeFormatter>
</Timeline.Item> </>
) : null} ),
</Timeline> },
) : null} ]
: []),
]}
/>) : null}
</CardTemplate> </CardTemplate>
); );
} }

View File

@@ -1,16 +1,16 @@
import { useQuery } from "@apollo/client"; import {useQuery} from "@apollo/client";
import { Col, Divider, Row, Skeleton, Space, Timeline, Typography } from "antd"; import {Col, Divider, Row, Skeleton, Space, Timeline, Typography} from "antd";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import {useTranslation} from "react-i18next";
import { Link } from "react-router-dom"; import {Link} from "react-router-dom";
import { GET_JOB_LINE_ORDERS } from "../../graphql/jobs.queries"; import {GET_JOB_LINE_ORDERS} from "../../graphql/jobs.queries";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter } from "../../utils/DateFormatter"; import {DateFormatter} from "../../utils/DateFormatter";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
export default function JobLinesExpander({ jobline, jobid }) { export default function JobLinesExpander({jobline, jobid}) {
const { t } = useTranslation(); const {t} = useTranslation();
const { loading, error, data } = useQuery(GET_JOB_LINE_ORDERS, { const {loading, error, data} = useQuery(GET_JOB_LINE_ORDERS, {
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
variables: { variables: {
@@ -18,8 +18,8 @@ export default function JobLinesExpander({ jobline, jobid }) {
}, },
}); });
if (loading) return <Skeleton />; if (loading) return <Skeleton/>;
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error"/>;
return ( return (
<Row> <Row>
@@ -27,11 +27,13 @@ export default function JobLinesExpander({ jobline, jobid }) {
<Typography.Title level={4}> <Typography.Title level={4}>
{t("parts_orders.labels.parts_orders")} {t("parts_orders.labels.parts_orders")}
</Typography.Title> </Typography.Title>
<Timeline> <Timeline
{data.parts_order_lines.length > 0 ? ( items={
data.parts_order_lines.map((line) => ( data.parts_order_lines.length > 0
<Timeline.Item key={line.id}> ? data.parts_order_lines.map((line) => ({
<Space split={<Divider type="vertical" />} wrap> key: line.id,
label: (
<Space split={<Divider type="vertical"/>} wrap>
<Link <Link
to={`/manage/jobs/${jobid}?partsorderid=${line.parts_order.id}`} 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> <DateFormatter>{line.parts_order.order_date}</DateFormatter>
{line.parts_order.vendor.name} {line.parts_order.vendor.name}
</Space> </Space>
</Timeline.Item> ),
)) }))
) : ( : [
<Timeline.Item> {
{t("parts_orders.labels.notyetordered")} key: "no-orders",
</Timeline.Item> label: t("parts_orders.labels.notyetordered"),
)} },
</Timeline> ]
</Col> }
/> </Col>
<Col md={24} lg={12}> <Col md={24} lg={12}>
<Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title> <Typography.Title level={4}>{t("bills.labels.bills")}</Typography.Title>
<Timeline> <Timeline
{data.billlines.length > 0 ? ( items={
data.billlines.map((line) => ( data.billlines.length > 0
<Timeline.Item key={line.id}> ? data.billlines.map((line) => ({
key: line.id,
label: (
<Row wrap> <Row wrap>
<Col span={4}> <Col span={4}>
<Link <Link
@@ -64,30 +69,26 @@ export default function JobLinesExpander({ jobline, jobid }) {
</Link> </Link>
</Col> </Col>
<Col span={4}> <Col span={4}>
<span> <span>{`${t("billlines.fields.actual_price")}: `}<CurrencyFormatter>{line.actual_price}</CurrencyFormatter></span>
{`${t("billlines.fields.actual_price")}: `}
<CurrencyFormatter>{line.actual_price}</CurrencyFormatter>
</span>
</Col> </Col>
<Col span={4}> <Col span={4}>
<span> <span>{`${t("billlines.fields.actual_cost")}: `}<CurrencyFormatter>{line.actual_cost}</CurrencyFormatter></span>
{`${t("billlines.fields.actual_cost")}: `}
<CurrencyFormatter>{line.actual_cost}</CurrencyFormatter>
</span>
</Col> </Col>
<Col span={4}> <Col span={4}>
<DateFormatter>{line.bill.date}</DateFormatter> <DateFormatter>{line.bill.date}</DateFormatter>
</Col> </Col>
<Col span={4}> {line.bill.vendor.name}</Col> <Col span={4}> {line.bill.vendor.name}</Col>
</Row> </Row>
</Timeline.Item> ),
)) }))
) : ( : [
<Timeline.Item> {
{t("parts_orders.labels.notyetordered")} key: "no-orders",
</Timeline.Item> label: t("parts_orders.labels.notyetordered"),
)} },
</Timeline> ]
}
/>
</Col> </Col>
</Row> </Row>
); );

View File

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

View File

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

View File

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

View File

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

View File

@@ -45,15 +45,15 @@ export function JobsAdminStatus({ insertAuditTrail, bodyshop, job }) {
onClick={(e) => { onClick={(e) => {
updateJobStatus(e.key); updateJobStatus(e.key);
}} }}
> items={bodyshop.md_ro_statuses.statuses.map((item) => ({
{bodyshop.md_ro_statuses.statuses.map((item) => ( key: item,
<Menu.Item key={item}>{item}</Menu.Item> label: item,
))} }))}
</Menu> />
); );
return ( return (
<Dropdown overlay={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

@@ -86,24 +86,27 @@ export function JobsChangeStatus({ job, bodyshop, jobRO, insertAuditTrail }) {
onClick={(e) => { onClick={(e) => {
updateJobStatus(e.key); updateJobStatus(e.key);
}} }}
> items={[
{availableStatuses.map((item) => ( ...availableStatuses.map((item) => ({
<Menu.Item key={item}>{item}</Menu.Item> key: item,
))} label: item,
{job.converted && ( })),
<> ...(job.converted
<Menu.Divider /> ? [
{otherStages.map((item, idx) => ( { key: "divider", label: <hr />, disabled: true },
<Menu.Item key={item}>{item}</Menu.Item> ...otherStages.map((item) => ({
))} key: item,
</> label: item,
)} })),
</Menu> ]
: []),
]}
/>
); );
return ( return (
<Dropdown <Dropdown
overlay={statusmenu} menu={statusmenu}
trigger={["click"]} trigger={["click"]}
key="changestatus" key="changestatus"
disabled={jobRO || !job.converted} 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) && ( const overlay = (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
<Menu onClick={handleMenuClick}> <Menu
{bodyshop.md_responsibility_centers.dms_defaults.map((mapping) => ( onClick={handleMenuClick}
<Menu.Item disabled={disabled} key={mapping.name}> items={bodyshop.md_responsibility_centers.dms_defaults.map((mapping) => ({
{mapping.name} key: mapping.name,
</Menu.Item> label: mapping.name,
))} disabled: disabled,
</Menu> }))}
/>
); );
return bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? ( return bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber ? (
<Dropdown overlay={overlay}> <Dropdown menu={overlay}>
<Button disabled={disabled}>{t("jobs.actions.dmsautoallocate")}</Button> <Button disabled={disabled}>{t("jobs.actions.dmsautoallocate")}</Button>
</Dropdown> </Dropdown>
) : ( ) : (

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -31,24 +31,28 @@ export default function ProductionListColumnBodyPriority({ record }) {
return ( return (
<Dropdown <Dropdown
overlay={ menu={
<Menu onClick={handleSetBodyPriority}> <Menu
<Menu.Item key="clearBodyPriority"> onClick={handleSetBodyPriority}
{t("production.actions.bodypriority-clear")} items={[
</Menu.Item> {
<Menu.SubMenu key: "clearBodyPriority",
key="set" label: t("production.actions.bodypriority-clear"),
title={t("production.actions.bodypriority-set")} },
> {
{new Array(15).fill().map((value, index) => ( key: "set",
<Menu.Item key={index + 1}> label: t("production.actions.bodypriority-set"),
children: new Array(15).fill().map((value, index) => ({
key: index + 1,
label: (
<div style={{ marginLeft: "2rem", marginRight: "2rem" }}> <div style={{ marginLeft: "2rem", marginRight: "2rem" }}>
{index + 1} {index + 1}
</div> </div>
</Menu.Item> ),
))} })),
</Menu.SubMenu> },
</Menu> ]}
/>
} }
trigger={["click"]} trigger={["click"]}
> >

View File

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

View File

@@ -31,24 +31,28 @@ export default function ProductionListColumnDetailPriority({ record }) {
return ( return (
<Dropdown <Dropdown
overlay={ menu={
<Menu onClick={handleSetDetailPriority}> <Menu
<Menu.Item key="clearDetailPriority"> onClick={handleSetDetailPriority}
{t("production.actions.detailpriority-clear")} items={[
</Menu.Item> {
<Menu.SubMenu key: "clearDetailPriority",
key="set" label: t("production.actions.detailpriority-clear"),
title={t("production.actions.detailpriority-set")} },
> {
{new Array(15).fill().map((value, index) => ( key: "set",
<Menu.Item key={index + 1}> label: t("production.actions.detailpriority-set"),
children: new Array(15).fill().map((value, index) => ({
key: index + 1,
label: (
<div style={{ marginLeft: "2rem", marginRight: "2rem" }}> <div style={{ marginLeft: "2rem", marginRight: "2rem" }}>
{index + 1} {index + 1}
</div> </div>
</Menu.Item> ),
))} })),
</Menu.SubMenu> },
</Menu> ]}
/>
} }
trigger={["click"]} trigger={["click"]}
> >

View File

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

View File

@@ -31,24 +31,28 @@ export default function ProductionListColumnPaintPriority({ record }) {
return ( return (
<Dropdown <Dropdown
overlay={ menu={
<Menu onClick={handleSetPaintPriority}> <Menu
<Menu.Item key="clearPaintPriority"> onClick={handleSetPaintPriority}
{t("production.actions.paintpriority-clear")} items={[
</Menu.Item> {
<Menu.SubMenu key: "clearPaintPriority",
key="set" label: t("production.actions.paintpriority-clear"),
title={t("production.actions.paintpriority-set")} },
> {
{new Array(15).fill().map((value, index) => ( key: "set",
<Menu.Item key={index + 1}> label: t("production.actions.paintpriority-set"),
children: new Array(15).fill().map((value, index) => ({
key: index + 1,
label: (
<div style={{ marginLeft: "2rem", marginRight: "2rem" }}> <div style={{ marginLeft: "2rem", marginRight: "2rem" }}>
{index + 1} {index + 1}
</div> </div>
</Menu.Item> ),
))} })),
</Menu.SubMenu> },
</Menu> ]}
/>
} }
trigger={["click"]} trigger={["click"]}
> >

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,15 +1,15 @@
import React from "react"; import React from "react";
import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import { Timeline } from "antd"; import {Timeline} from "antd";
import { useTranslation } from "react-i18next"; import {useTranslation} from "react-i18next";
import { DateTimeFormatter } from "../../utils/DateFormatter"; import {DateTimeFormatter} from "../../utils/DateFormatter";
export default function ScheduleExistingAppointmentsList({ export default function ScheduleExistingAppointmentsList({
existingAppointments, existingAppointments,
}) { }) {
const { t } = useTranslation(); const {t} = useTranslation();
if (existingAppointments.loading) return <LoadingSpinner />; if (existingAppointments.loading) return <LoadingSpinner/>;
if (existingAppointments.error) if (existingAppointments.error)
return ( return (
<AlertComponent <AlertComponent
@@ -21,28 +21,25 @@ export default function ScheduleExistingAppointmentsList({
return ( return (
<div> <div>
{t("appointments.labels.priorappointments")} {t("appointments.labels.priorappointments")}
<Timeline> <Timeline
{existingAppointments.data items={
? existingAppointments.data.appointments.map((item) => { existingAppointments.data
return ( ? existingAppointments.data.appointments.map((item) => ({
<Timeline.Item key: item.id,
key={item.id} color: item.canceled ? "red" : item.arrived ? "green" : "blue",
color={ label: (
item.canceled ? "red" : item.arrived ? "green" : "blue" <>
}
>
{item.canceled {item.canceled
? t("appointments.labels.cancelledappointment") ? t("appointments.labels.cancelledappointment")
: item.arrived : item.arrived
? t("appointments.labels.arrivedon") ? t("appointments.labels.arrivedon")
: t("appointments.labels.scheduledfor")} : t("appointments.labels.scheduledfor")}
<DateTimeFormatter>{item.start}</DateTimeFormatter> <DateTimeFormatter>{item.start}</DateTimeFormatter>
</Timeline.Item> </>
); ),
}) }))
: null} : []
</Timeline> }
</div> /></div>
); );
} }

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,16 +1,16 @@
import { PrinterFilled } from "@ant-design/icons"; import {PrinterFilled} from "@ant-design/icons";
import { useQuery } from "@apollo/client"; import {useQuery} from "@apollo/client";
import { Button, Divider, Drawer, Grid, Tabs } from "antd"; import {Button, Divider, Drawer, Grid, Tabs} from "antd";
import {PageHeader} from "@ant-design/pro-layout"; import {PageHeader} from "@ant-design/pro-layout";
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 { GET_JOB_BY_PK } from "../../graphql/jobs.queries"; import {GET_JOB_BY_PK} from "../../graphql/jobs.queries";
import { setModalContext } from "../../redux/modals/modals.actions"; import {setModalContext} from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {selectBodyshop} from "../../redux/user/user.selectors";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import JobLinesContainer from "../job-detail-lines/job-lines.container"; import JobLinesContainer from "../job-detail-lines/job-lines.container";
import JobsDetailHeader from "../jobs-detail-header/jobs-detail-header.component"; import JobsDetailHeader from "../jobs-detail-header/jobs-detail-header.component";
@@ -19,11 +19,11 @@ import JobsDocumentsLocalGallery from "../jobs-documents-local-gallery/jobs-docu
import JobNotesContainer from "../jobs-notes/jobs-notes.container"; import JobNotesContainer from "../jobs-notes/jobs-notes.container";
import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component";
const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop }); const mapStateToProps = createStructuredSelector({bodyshop: selectBodyshop});
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setPrintCenterContext: (context) => setPrintCenterContext: (context) =>
dispatch(setModalContext({ context: context, modal: "printCenter" })), dispatch(setModalContext({context: context, modal: "printCenter"})),
}); });
// const colBreakPoints = { // const colBreakPoints = {
@@ -35,7 +35,7 @@ const mapDispatchToProps = (dispatch) => ({
// }, // },
// }; // };
export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) { export function TechLookupJobsDrawer({bodyshop, setPrintCenterContext}) {
const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1]) .filter((screen) => !!screen[1])
.slice(-1)[0]; .slice(-1)[0];
@@ -52,17 +52,17 @@ export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
? bpoints[selectedBreakpoint[0]] ? bpoints[selectedBreakpoint[0]]
: "100%"; : "100%";
const searchParams =queryString.parse(useLocation().search); const searchParams = queryString.parse(useLocation().search);
const { selected } = searchParams; const {selected} = searchParams;
const history = useNavigate(); const history = useNavigate();
const { loading, error, data, refetch } = useQuery(GET_JOB_BY_PK, { const {loading, error, data, refetch} = useQuery(GET_JOB_BY_PK, {
variables: { id: selected }, variables: {id: selected},
skip: !selected, skip: !selected,
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
const { t } = useTranslation(); const {t} = useTranslation();
const handleDrawerClose = () => { const handleDrawerClose = () => {
delete searchParams.selected; delete searchParams.selected;
history({ history({
@@ -80,8 +80,8 @@ export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
placement="right" placement="right"
onClose={handleDrawerClose} onClose={handleDrawerClose}
> >
{loading ? <LoadingSpinner /> : null} {loading ? <LoadingSpinner/> : null}
{error ? <AlertComponent message={error.message} type="error" /> : null} {error ? <AlertComponent message={error.message} type="error"/> : null}
{data ? ( {data ? (
<PageHeader <PageHeader
onBack={() => window.history.back()} onBack={() => window.history.back()}
@@ -90,7 +90,7 @@ export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
<Button <Button
onClick={() => { onClick={() => {
setPrintCenterContext({ setPrintCenterContext({
actions: { refetch: refetch }, actions: {refetch: refetch},
context: { context: {
id: data.jobs_by_pk.id, id: data.jobs_by_pk.id,
job: data.jobs_by_pk, job: data.jobs_by_pk,
@@ -99,40 +99,53 @@ export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
}); });
}} }}
> >
<PrinterFilled /> <PrinterFilled/>
{t("jobs.actions.printCenter")} {t("jobs.actions.printCenter")}
</Button> </Button>
} }
> >
<JobsDetailHeader job={data.jobs_by_pk} disabled /> <JobsDetailHeader job={data.jobs_by_pk} disabled/>
<Divider type="horizontal" /> <Divider type="horizontal"/>
<Tabs size="large"> <Tabs
<Tabs.TabPane key="lines" tab={t("jobs.labels.lines")}> size="large"
defaultActiveKey="lines"
items={[
{
key: "lines",
tab: t("jobs.labels.lines"),
children: (
<JobLinesContainer <JobLinesContainer
jobId={selected} jobId={selected}
joblines={data.jobs_by_pk.joblines} joblines={data.jobs_by_pk.joblines}
job={data.jobs_by_pk} job={data.jobs_by_pk}
refetch={refetch} 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 <JobsDocumentsLocalGallery
job={data ? data.jobs_by_pk : null} job={data ? data.jobs_by_pk : null}
/> />
) : ( ) : (
<JobsDocumentsGalleryContainer jobId={searchParams.selected} /> <JobsDocumentsGalleryContainer jobId={searchParams.selected}/>
)} ),
</Tabs.TabPane> },
<Tabs.TabPane key="notes" tab={t("jobs.labels.notes")}> {
<JobNotesContainer jobId={searchParams.selected} /> key: "notes",
</Tabs.TabPane> tab: t("jobs.labels.notes"),
</Tabs> children: <JobNotesContainer jobId={searchParams.selected}/>,
},
]}
/>
</PageHeader> </PageHeader>
) : null} ) : null}
</Drawer> </Drawer>
); );
} }
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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