302 lines
13 KiB
JavaScript
302 lines
13 KiB
JavaScript
import { DeleteFilled, HolderOutlined } from "@ant-design/icons";
|
|
import { Button, Col, Form, Input, Row, Select, Space, Switch } from "antd";
|
|
import { useMemo } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
|
import ConfigListEmptyState from "../layout-form-row/config-list-empty-state.component.jsx";
|
|
import InlineValidatedFormRow from "../layout-form-row/inline-validated-form-row.component.jsx";
|
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
|
import {
|
|
INLINE_TITLE_GROUP_STYLE,
|
|
INLINE_TITLE_HANDLE_STYLE,
|
|
INLINE_TITLE_INPUT_STYLE,
|
|
INLINE_TITLE_LABEL_STYLE,
|
|
INLINE_TITLE_ROW_STYLE,
|
|
INLINE_TITLE_SEPARATOR_STYLE,
|
|
INLINE_TITLE_SWITCH_GROUP_STYLE
|
|
} from "../layout-form-row/inline-form-row-title.utils.js";
|
|
import i18n from "i18next";
|
|
|
|
const predefinedPartTypes = ["PAN", "PAC", "PAR", "PAL", "PAA", "PAM", "PAP", "PAS", "PASL", "PAG"];
|
|
const predefinedModLbrTypes = [
|
|
"LAA",
|
|
"LAB",
|
|
"LAD",
|
|
"LAE",
|
|
"LAF",
|
|
"LAG",
|
|
"LAM",
|
|
"LAR",
|
|
"LAS",
|
|
"LAU",
|
|
"LA1",
|
|
"LA2",
|
|
"LA3",
|
|
"LA4"
|
|
];
|
|
|
|
const getFieldType = (field) => {
|
|
if (["line_desc", "part_number"].includes(field)) return "string";
|
|
if (["act_price", "part_qty", "mod_lb_hrs"].includes(field)) return "number";
|
|
if (["part_type", "mod_lbr_ty"].includes(field)) return "predefined";
|
|
return null;
|
|
};
|
|
|
|
const fieldSelectOptions = [
|
|
{ label: i18n.t("joblines.fields.line_desc"), value: "line_desc" },
|
|
{ label: i18n.t("joblines.fields.part_type"), value: "part_type" },
|
|
{ label: i18n.t("joblines.fields.act_price"), value: "act_price" },
|
|
{ label: i18n.t("joblines.fields.part_qty"), value: "part_qty" },
|
|
{ label: i18n.t("joblines.fields.mod_lbr_ty"), value: "mod_lbr_ty" },
|
|
|
|
{
|
|
label: `${i18n.t("joblines.fields.oem_partno")} / ${i18n.t("joblines.fields.alt_partno")}`,
|
|
value: "part_number"
|
|
},
|
|
{ label: i18n.t("joblines.fields.op_code_desc"), value: "op_code_desc" }
|
|
];
|
|
export default function ShopInfoPartsScan({ form }) {
|
|
const { t } = useTranslation();
|
|
|
|
const watchedFields = Form.useWatch("md_parts_scan", form);
|
|
|
|
const operationOptions = useMemo(
|
|
() => ({
|
|
string: [
|
|
{ label: t("bodyshop.operations.contains"), value: "contains" },
|
|
{ label: t("bodyshop.operations.equals"), value: "equals" },
|
|
{ label: t("bodyshop.operations.starts_with"), value: "startsWith" },
|
|
{ label: t("bodyshop.operations.ends_with"), value: "endsWith" }
|
|
],
|
|
number: [
|
|
{ label: t("bodyshop.operations.equals"), value: "=" },
|
|
{ label: t("bodyshop.operations.greater_than"), value: ">" },
|
|
{ label: t("bodyshop.operations.less_than"), value: "<" }
|
|
]
|
|
}),
|
|
[t]
|
|
);
|
|
|
|
return (
|
|
<div>
|
|
<Form.List name={["md_parts_scan"]}>
|
|
{(fields, { add, remove, move }) => (
|
|
<LayoutFormRow
|
|
header={t("bodyshop.labels.md_parts_scan")}
|
|
actions={[
|
|
<Button
|
|
key="add-parts-scan-rule"
|
|
type="primary"
|
|
block
|
|
onClick={() =>
|
|
add({
|
|
field: "line_desc",
|
|
operation: "contains",
|
|
mark_critical: true,
|
|
caseInsensitive: true
|
|
})
|
|
}
|
|
>
|
|
{t("bodyshop.actions.addpartsrule")}
|
|
</Button>
|
|
]}
|
|
>
|
|
<div>
|
|
{fields.length === 0 ? (
|
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.addpartsrule")} />
|
|
) : (
|
|
fields.map((field, index) => {
|
|
const selectedField = watchedFields?.[index]?.field || "line_desc";
|
|
const fieldType = getFieldType(selectedField);
|
|
|
|
return (
|
|
<Form.Item noStyle key={field.key}>
|
|
<InlineValidatedFormRow
|
|
form={form}
|
|
errorNames={[["md_parts_scan", field.name, "field"]]}
|
|
noDivider
|
|
title={
|
|
<div style={INLINE_TITLE_ROW_STYLE}>
|
|
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("bodyshop.fields.md_parts_scan.field")}</div>
|
|
<Form.Item
|
|
noStyle
|
|
name={[field.name, "field"]}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required", {
|
|
label: t("bodyshop.fields.md_parts_scan.field")
|
|
})
|
|
}
|
|
]}
|
|
>
|
|
<Select
|
|
options={fieldSelectOptions}
|
|
onChange={() => {
|
|
form.setFields([
|
|
{ name: ["md_parts_scan", index, "operation"], value: "contains" },
|
|
{ name: ["md_parts_scan", index, "value"], value: undefined }
|
|
]);
|
|
}}
|
|
style={{
|
|
width: "100%"
|
|
}}
|
|
styles={{
|
|
selector: INLINE_TITLE_INPUT_STYLE
|
|
}}
|
|
size="small"
|
|
/>
|
|
</Form.Item>
|
|
</div>
|
|
{fieldType === "string" && (
|
|
<>
|
|
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
|
<div style={INLINE_TITLE_SWITCH_GROUP_STYLE}>
|
|
<div style={INLINE_TITLE_LABEL_STYLE}>
|
|
{t("bodyshop.fields.md_parts_scan.caseInsensitive")}
|
|
</div>
|
|
<Form.Item noStyle name={[field.name, "caseInsensitive"]} valuePropName="checked">
|
|
<Switch />
|
|
</Form.Item>
|
|
</div>
|
|
</>
|
|
)}
|
|
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
|
<div style={INLINE_TITLE_SWITCH_GROUP_STYLE}>
|
|
<div style={INLINE_TITLE_LABEL_STYLE}>
|
|
{t("bodyshop.fields.md_parts_scan.mark_critical")}
|
|
</div>
|
|
<Form.Item noStyle name={[field.name, "mark_critical"]} valuePropName="checked">
|
|
<Switch />
|
|
</Form.Item>
|
|
</div>
|
|
</div>
|
|
}
|
|
wrapTitle
|
|
extra={
|
|
<Space align="center" size="small">
|
|
<Button
|
|
type="text"
|
|
danger
|
|
icon={<DeleteFilled />}
|
|
onClick={() => {
|
|
remove(field.name);
|
|
}}
|
|
/>
|
|
<FormListMoveArrows
|
|
move={move}
|
|
index={index}
|
|
total={fields.length}
|
|
orientation="horizontal"
|
|
/>
|
|
</Space>
|
|
}
|
|
>
|
|
<Row gutter={[16, 16]} align="middle">
|
|
{/* Operation */}
|
|
{fieldType !== "predefined" && fieldType && (
|
|
<Col span={6}>
|
|
<Form.Item
|
|
label={t("bodyshop.fields.md_parts_scan.operation")}
|
|
name={[field.name, "operation"]}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required", {
|
|
label: t("bodyshop.fields.md_parts_scan.operation")
|
|
})
|
|
}
|
|
]}
|
|
>
|
|
<Select options={operationOptions[fieldType]} />
|
|
</Form.Item>
|
|
</Col>
|
|
)}
|
|
|
|
{/* Value */}
|
|
{fieldType && (
|
|
<Col span={6}>
|
|
<Form.Item
|
|
label={t("bodyshop.fields.md_parts_scan.value")}
|
|
name={[field.name, "value"]}
|
|
rules={[
|
|
{
|
|
required: true,
|
|
message: t("general.validation.required", {
|
|
label: t("bodyshop.fields.md_parts_scan.value")
|
|
})
|
|
}
|
|
]}
|
|
>
|
|
{fieldType === "predefined" ? (
|
|
<Select
|
|
options={
|
|
selectedField === "part_type"
|
|
? predefinedPartTypes.map((type) => ({
|
|
label: type,
|
|
value: type
|
|
}))
|
|
: predefinedModLbrTypes.map((type) => ({
|
|
label: type,
|
|
value: type
|
|
}))
|
|
}
|
|
/>
|
|
) : (
|
|
<Input />
|
|
)}
|
|
</Form.Item>
|
|
</Col>
|
|
)}
|
|
|
|
{/* Update Field */}
|
|
<Col span={4}>
|
|
<Form.Item
|
|
label={t("bodyshop.fields.md_parts_scan.update_field")}
|
|
name={[field.name, "update_field"]}
|
|
>
|
|
<Select
|
|
options={fieldSelectOptions}
|
|
allowClear
|
|
onClear={() =>
|
|
form.setFields([{ name: ["md_parts_scan", index, "update_field"], value: null }])
|
|
}
|
|
/>
|
|
</Form.Item>
|
|
</Col>
|
|
|
|
{/* Update Field */}
|
|
<Col span={4}>
|
|
<Form.Item
|
|
label={t("bodyshop.fields.md_parts_scan.update_value")}
|
|
name={[field.name, "update_value"]}
|
|
dependencies={[["md_parts_scan", index, "update_field"]]}
|
|
tooltip={t("bodyshop.tooltips.md_parts_scan.update_value_tooltip")}
|
|
rules={[
|
|
{
|
|
required: form.getFieldValue(["md_parts_scan", index, "update_field"]),
|
|
message: t("general.validation.required", {
|
|
label: t("bodyshop.fields.md_parts_scan.update_value")
|
|
})
|
|
}
|
|
]}
|
|
>
|
|
<Input />
|
|
</Form.Item>
|
|
</Col>
|
|
</Row>
|
|
</InlineValidatedFormRow>
|
|
</Form.Item>
|
|
);
|
|
})
|
|
)}
|
|
</div>
|
|
</LayoutFormRow>
|
|
)}
|
|
</Form.List>
|
|
</div>
|
|
);
|
|
}
|