IO-3624 Polish config empty states and admin cards
This commit is contained in:
@@ -0,0 +1,11 @@
|
|||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
|
export default function ConfigListEmptyState({ actionLabel, minHeight = 96 }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="imex-form-row-empty-state" style={{ minHeight }}>
|
||||||
|
{t("general.labels.click_to_begin", { action: actionLabel })}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,15 +1,19 @@
|
|||||||
export const inlineFormRowTitleStyles = Object.freeze({
|
export const inlineFormRowTitleStyles = Object.freeze({
|
||||||
input: Object.freeze({
|
input: Object.freeze({
|
||||||
background: "var(--imex-form-title-input-bg)",
|
background: "transparent",
|
||||||
border: "1px solid var(--imex-form-title-input-border)",
|
border: "none",
|
||||||
borderRadius: 6,
|
borderRadius: 0,
|
||||||
paddingInline: 10,
|
boxShadow: "none",
|
||||||
paddingBlock: 4,
|
paddingInline: 0,
|
||||||
lineHeight: 1.3
|
paddingBlock: 0,
|
||||||
|
lineHeight: 1.35,
|
||||||
|
flex: "1 1 auto",
|
||||||
|
minWidth: 0,
|
||||||
|
width: "100%"
|
||||||
}),
|
}),
|
||||||
row: Object.freeze({
|
row: Object.freeze({
|
||||||
display: "flex",
|
display: "flex",
|
||||||
gap: 4,
|
gap: 6,
|
||||||
flexWrap: "wrap",
|
flexWrap: "wrap",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
@@ -18,25 +22,37 @@ export const inlineFormRowTitleStyles = Object.freeze({
|
|||||||
group: Object.freeze({
|
group: Object.freeze({
|
||||||
display: "flex",
|
display: "flex",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
gap: 6,
|
gap: 8,
|
||||||
minWidth: 0
|
paddingInline: 8,
|
||||||
|
paddingBlock: 4,
|
||||||
|
borderRadius: 10,
|
||||||
|
border: "1px solid var(--imex-form-title-group-border)",
|
||||||
|
background: "var(--imex-form-title-group-bg)",
|
||||||
|
minWidth: 0,
|
||||||
|
flex: "1 1 0"
|
||||||
}),
|
}),
|
||||||
label: Object.freeze({
|
label: Object.freeze({
|
||||||
color: "var(--ant-color-text)",
|
color: "var(--ant-color-text-secondary)",
|
||||||
fontSize: "var(--ant-font-size)",
|
fontSize: 12,
|
||||||
fontWeight: 500,
|
fontWeight: 600,
|
||||||
whiteSpace: "nowrap"
|
lineHeight: 1,
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
paddingInline: 6,
|
||||||
|
paddingBlock: 3,
|
||||||
|
borderRadius: 999,
|
||||||
|
border: "1px solid var(--imex-form-title-label-border)",
|
||||||
|
background: "var(--imex-form-title-label-bg)"
|
||||||
}),
|
}),
|
||||||
handle: Object.freeze({
|
handle: Object.freeze({
|
||||||
color: "var(--ant-color-text-tertiary)",
|
color: "var(--ant-color-text-tertiary)",
|
||||||
fontSize: 14,
|
fontSize: 14,
|
||||||
flex: "0 0 auto",
|
flex: "0 0 auto",
|
||||||
marginRight: 4
|
marginRight: 2
|
||||||
}),
|
}),
|
||||||
separator: Object.freeze({
|
separator: Object.freeze({
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 18,
|
height: 16,
|
||||||
background: "color-mix(in srgb, var(--imex-form-surface-border) 78%, transparent)",
|
background: "color-mix(in srgb, var(--imex-form-surface-border) 58%, transparent)",
|
||||||
borderRadius: 999,
|
borderRadius: 999,
|
||||||
flex: "0 0 auto",
|
flex: "0 0 auto",
|
||||||
marginInline: 2
|
marginInline: 2
|
||||||
@@ -52,6 +68,10 @@ export const inlineFormRowTitleStyles = Object.freeze({
|
|||||||
export const INLINE_TITLE_INPUT_STYLE = inlineFormRowTitleStyles.input;
|
export const INLINE_TITLE_INPUT_STYLE = inlineFormRowTitleStyles.input;
|
||||||
export const INLINE_TITLE_ROW_STYLE = inlineFormRowTitleStyles.row;
|
export const INLINE_TITLE_ROW_STYLE = inlineFormRowTitleStyles.row;
|
||||||
export const INLINE_TITLE_GROUP_STYLE = inlineFormRowTitleStyles.group;
|
export const INLINE_TITLE_GROUP_STYLE = inlineFormRowTitleStyles.group;
|
||||||
|
export const INLINE_TITLE_SWITCH_GROUP_STYLE = Object.freeze({
|
||||||
|
...inlineFormRowTitleStyles.group,
|
||||||
|
flex: "0 0 auto"
|
||||||
|
});
|
||||||
export const INLINE_TITLE_LABEL_STYLE = inlineFormRowTitleStyles.label;
|
export const INLINE_TITLE_LABEL_STYLE = inlineFormRowTitleStyles.label;
|
||||||
export const INLINE_TITLE_HANDLE_STYLE = inlineFormRowTitleStyles.handle;
|
export const INLINE_TITLE_HANDLE_STYLE = inlineFormRowTitleStyles.handle;
|
||||||
export const INLINE_TITLE_SEPARATOR_STYLE = inlineFormRowTitleStyles.separator;
|
export const INLINE_TITLE_SEPARATOR_STYLE = inlineFormRowTitleStyles.separator;
|
||||||
|
|||||||
@@ -15,6 +15,10 @@
|
|||||||
--imex-form-surface-border: #d9d9d9; /* matches AntD-ish border */
|
--imex-form-surface-border: #d9d9d9; /* matches AntD-ish border */
|
||||||
--imex-form-title-input-bg: rgba(255, 255, 255, 0.96);
|
--imex-form-title-input-bg: rgba(255, 255, 255, 0.96);
|
||||||
--imex-form-title-input-border: rgba(0, 0, 0, 0.08);
|
--imex-form-title-input-border: rgba(0, 0, 0, 0.08);
|
||||||
|
--imex-form-title-group-bg: rgba(255, 255, 255, 0.72);
|
||||||
|
--imex-form-title-group-border: rgba(0, 0, 0, 0.08);
|
||||||
|
--imex-form-title-label-bg: rgba(0, 0, 0, 0.04);
|
||||||
|
--imex-form-title-label-border: rgba(0, 0, 0, 0.06);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pick the selector that matches your app and remove the rest */
|
/* Pick the selector that matches your app and remove the rest */
|
||||||
@@ -24,6 +28,10 @@ html[data-theme="dark"] {
|
|||||||
--imex-form-surface-border: rgba(5, 5, 5, 0.12);
|
--imex-form-surface-border: rgba(5, 5, 5, 0.12);
|
||||||
--imex-form-title-input-bg: rgba(255, 255, 255, 0.12);
|
--imex-form-title-input-bg: rgba(255, 255, 255, 0.12);
|
||||||
--imex-form-title-input-border: rgba(255, 255, 255, 0.2);
|
--imex-form-title-input-border: rgba(255, 255, 255, 0.2);
|
||||||
|
--imex-form-title-group-bg: rgba(255, 255, 255, 0.08);
|
||||||
|
--imex-form-title-group-border: rgba(255, 255, 255, 0.16);
|
||||||
|
--imex-form-title-label-bg: rgba(255, 255, 255, 0.06);
|
||||||
|
--imex-form-title-label-border: rgba(255, 255, 255, 0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.imex-form-row {
|
.imex-form-row {
|
||||||
@@ -114,6 +122,20 @@ html[data-theme="dark"] {
|
|||||||
background: var(--imex-form-surface);
|
background: var(--imex-form-surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ant-card-actions {
|
||||||
|
background: var(--imex-form-surface-head);
|
||||||
|
border-top-color: var(--imex-form-surface-border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-actions > li {
|
||||||
|
margin: 10px 0;
|
||||||
|
padding-inline: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-actions .ant-btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.ant-form-item:last-child {
|
.ant-form-item:last-child {
|
||||||
margin-bottom: 4px;
|
margin-bottom: 4px;
|
||||||
}
|
}
|
||||||
@@ -156,3 +178,14 @@ html[data-theme="dark"] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.imex-form-row-empty-state {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 24px 16px;
|
||||||
|
text-align: center;
|
||||||
|
color: var(--ant-color-text-description);
|
||||||
|
font-size: var(--ant-font-size);
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import dayjs from "../../utils/day";
|
|||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component.jsx";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
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 LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import {
|
import {
|
||||||
INLINE_TITLE_GROUP_STYLE,
|
INLINE_TITLE_GROUP_STYLE,
|
||||||
@@ -35,6 +36,7 @@ import {
|
|||||||
INLINE_TITLE_LABEL_STYLE,
|
INLINE_TITLE_LABEL_STYLE,
|
||||||
INLINE_TITLE_ROW_STYLE,
|
INLINE_TITLE_ROW_STYLE,
|
||||||
INLINE_TITLE_SEPARATOR_STYLE,
|
INLINE_TITLE_SEPARATOR_STYLE,
|
||||||
|
INLINE_TITLE_SWITCH_GROUP_STYLE,
|
||||||
INLINE_TITLE_TEXT_STYLE
|
INLINE_TITLE_TEXT_STYLE
|
||||||
} from "../layout-form-row/inline-form-row-title.utils.js";
|
} from "../layout-form-row/inline-form-row-title.utils.js";
|
||||||
import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component";
|
import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component";
|
||||||
@@ -166,6 +168,8 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
|
|||||||
key: "actions",
|
key: "actions",
|
||||||
render: (text, record) => (
|
render: (text, record) => (
|
||||||
<Button
|
<Button
|
||||||
|
type="text"
|
||||||
|
danger
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await deleteVacation({
|
await deleteVacation({
|
||||||
variables: { id: record.id },
|
variables: { id: record.id },
|
||||||
@@ -195,8 +199,8 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
|
|||||||
<Card
|
<Card
|
||||||
title={employeeCardTitle}
|
title={employeeCardTitle}
|
||||||
extra={
|
extra={
|
||||||
<Button type="primary" onClick={() => form.submit()}>
|
<Button type="primary" onClick={() => form.submit()} style={{ minWidth: 170 }}>
|
||||||
{t("general.actions.save")}
|
{t("employees.actions.save_employee")}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -229,8 +233,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
|
|||||||
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
...INLINE_TITLE_SWITCH_GROUP_STYLE
|
||||||
flex: "0 0 auto"
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.labels.active")}</div>
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.labels.active")}</div>
|
||||||
@@ -241,8 +244,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
|
|||||||
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
...INLINE_TITLE_SWITCH_GROUP_STYLE
|
||||||
flex: "0 0 auto"
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.fields.flat_rate")}</div>
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.fields.flat_rate")}</div>
|
||||||
@@ -396,147 +398,141 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
|
|||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow title={t("bodyshop.labels.employee_rates")}>
|
<Form.List name={["rates"]}>
|
||||||
<Form.List name={["rates"]}>
|
{(fields, { add, remove, move }) => {
|
||||||
{(fields, { add, remove, move }) => {
|
return (
|
||||||
return (
|
<LayoutFormRow
|
||||||
|
title={t("bodyshop.labels.employee_rates")}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-rate"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add();
|
||||||
|
}}
|
||||||
|
id="add-employee-rate-button"
|
||||||
|
>
|
||||||
|
<span id="new-employee-rate">{t("employees.actions.addrate")}</span>
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
{fields.map((field, index) => {
|
{fields.length === 0 ? (
|
||||||
return (
|
<ConfigListEmptyState actionLabel={t("employees.actions.addrate")} />
|
||||||
<Form.Item key={field.key} style={{ padding: 0, margin: 2 }}>
|
) : (
|
||||||
<LayoutFormRow
|
fields.map((field, index) => {
|
||||||
noDivider
|
return (
|
||||||
titleOnly
|
<Form.Item key={field.key} style={{ padding: 0, margin: 2 }}>
|
||||||
title={
|
<LayoutFormRow
|
||||||
<div style={INLINE_TITLE_ROW_STYLE}>
|
noDivider
|
||||||
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
title={
|
||||||
<div
|
<div style={INLINE_TITLE_ROW_STYLE}>
|
||||||
style={{
|
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
||||||
flex: "1 1 260px"
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.fields.cost_center")}</div>
|
||||||
}}
|
<Form.Item
|
||||||
>
|
noStyle
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.fields.cost_center")}</div>
|
name={[field.name, "cost_center"]}
|
||||||
<Form.Item
|
rules={[
|
||||||
noStyle
|
{
|
||||||
name={[field.name, "cost_center"]}
|
required: true
|
||||||
rules={[
|
}
|
||||||
{
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
size="small"
|
|
||||||
options={[
|
|
||||||
{ value: "timetickets.labels.shift", label: t("timetickets.labels.shift") },
|
|
||||||
...(bodyshop.cdk_dealerid ||
|
|
||||||
bodyshop.pbs_serialnumber ||
|
|
||||||
bodyshop.rr_dealerid ||
|
|
||||||
Enhanced_Payroll.treatment === "on"
|
|
||||||
? CiecaSelect(false, true)
|
|
||||||
: bodyshop.md_responsibility_centers.costs.map((c) => ({
|
|
||||||
value: c.name,
|
|
||||||
label: c.name
|
|
||||||
})))
|
|
||||||
]}
|
]}
|
||||||
style={{ width: "100%" }}
|
>
|
||||||
styles={{
|
<Select
|
||||||
selector: INLINE_TITLE_INPUT_STYLE
|
size="small"
|
||||||
}}
|
options={[
|
||||||
/>
|
{ value: "timetickets.labels.shift", label: t("timetickets.labels.shift") },
|
||||||
</Form.Item>
|
...(bodyshop.cdk_dealerid ||
|
||||||
|
bodyshop.pbs_serialnumber ||
|
||||||
|
bodyshop.rr_dealerid ||
|
||||||
|
Enhanced_Payroll.treatment === "on"
|
||||||
|
? CiecaSelect(false, true)
|
||||||
|
: bodyshop.md_responsibility_centers.costs.map((c) => ({
|
||||||
|
value: c.name,
|
||||||
|
label: c.name
|
||||||
|
})))
|
||||||
|
]}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
styles={{
|
||||||
|
selector: INLINE_TITLE_INPUT_STYLE
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
}
|
||||||
<div
|
wrapTitle
|
||||||
style={{
|
extra={
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<Space align="center" size="small">
|
||||||
flex: "0 1 190px"
|
<Button
|
||||||
}}
|
type="text"
|
||||||
>
|
danger
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employees.fields.rate")}</div>
|
icon={<DeleteFilled />}
|
||||||
<Form.Item
|
onClick={() => {
|
||||||
noStyle
|
remove(field.name);
|
||||||
name={[field.name, "rate"]}
|
}}
|
||||||
rules={[
|
/>
|
||||||
{
|
<FormListMoveArrows
|
||||||
required: true
|
move={move}
|
||||||
}
|
index={index}
|
||||||
]}
|
total={fields.length}
|
||||||
>
|
orientation="horizontal"
|
||||||
<InputNumber
|
/>
|
||||||
min={0}
|
</Space>
|
||||||
precision={2}
|
}
|
||||||
size="small"
|
>
|
||||||
style={{
|
<Form.Item
|
||||||
...INLINE_TITLE_INPUT_STYLE,
|
label={t("employees.fields.rate")}
|
||||||
width: "100%"
|
name={[field.name, "rate"]}
|
||||||
}}
|
rules={[
|
||||||
/>
|
{
|
||||||
</Form.Item>
|
required: true
|
||||||
</div>
|
}
|
||||||
</div>
|
]}
|
||||||
}
|
style={{ marginBottom: 0 }}
|
||||||
wrapTitle
|
>
|
||||||
extra={
|
<InputNumber min={0} precision={2} style={{ width: "100%" }} />
|
||||||
<Space align="center" size="small">
|
</Form.Item>
|
||||||
<Button
|
</LayoutFormRow>
|
||||||
type="text"
|
</Form.Item>
|
||||||
icon={<DeleteFilled />}
|
);
|
||||||
onClick={() => {
|
})
|
||||||
remove(field.name);
|
)}
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormListMoveArrows
|
|
||||||
move={move}
|
|
||||||
index={index}
|
|
||||||
total={fields.length}
|
|
||||||
orientation="horizontal"
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<Form.Item>
|
|
||||||
<Button
|
|
||||||
type="dashed"
|
|
||||||
onClick={() => {
|
|
||||||
add();
|
|
||||||
}}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
id="add-employee-rate-button"
|
|
||||||
>
|
|
||||||
<span id="new-employee-rate">{t("employees.actions.newrate")}</span>
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</LayoutFormRow>
|
||||||
}}
|
);
|
||||||
</Form.List>
|
}}
|
||||||
</LayoutFormRow>
|
</Form.List>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
||||||
<LayoutFormRow title={t("bodyshop.labels.employee_vacation")}>
|
<LayoutFormRow
|
||||||
<div>
|
title={t("bodyshop.labels.employee_vacation")}
|
||||||
<ResponsiveTable
|
actions={[
|
||||||
columns={columns}
|
<ShopEmployeeAddVacation
|
||||||
mobileColumnKeys={["start", "length", "actions"]}
|
key="add-vacation"
|
||||||
rowKey={"id"}
|
employee={data && data.employees_by_pk}
|
||||||
dataSource={data?.employees_by_pk?.employee_vacations ?? []}
|
buttonProps={{
|
||||||
pagination={false}
|
type: "primary",
|
||||||
|
block: true
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<div style={{ marginTop: 12 }}>
|
]}
|
||||||
<ShopEmployeeAddVacation
|
>
|
||||||
employee={data && data.employees_by_pk}
|
{(data?.employees_by_pk?.employee_vacations ?? []).length === 0 ? (
|
||||||
buttonProps={{
|
<ConfigListEmptyState actionLabel={t("employees.actions.addvacation")} />
|
||||||
type: "dashed",
|
) : (
|
||||||
block: true
|
<div>
|
||||||
}}
|
<ResponsiveTable
|
||||||
|
columns={columns}
|
||||||
|
mobileColumnKeys={["start", "length", "actions"]}
|
||||||
|
rowKey={"id"}
|
||||||
|
dataSource={data?.employees_by_pk?.employee_vacations ?? []}
|
||||||
|
pagination={false}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ import { useState } from "react";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
import { alphaSort } from "../../utils/sorters";
|
import { alphaSort } from "../../utils/sorters";
|
||||||
|
import ConfigListEmptyState from "../layout-form-row/config-list-empty-state.component.jsx";
|
||||||
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import ResponsiveTable from "../responsive-table/responsive-table.component";
|
import ResponsiveTable from "../responsive-table/responsive-table.component";
|
||||||
|
|
||||||
export default function ShopEmployeesListComponent({ loading, employees }) {
|
export default function ShopEmployeesListComponent({ loading, employees }) {
|
||||||
@@ -16,13 +18,28 @@ export default function ShopEmployeesListComponent({ loading, employees }) {
|
|||||||
filteredInfo: { text: "" }
|
filteredInfo: { text: "" }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const navigateToEmployee = (employeeId) => {
|
||||||
|
history({
|
||||||
|
search: queryString.stringify({
|
||||||
|
...search,
|
||||||
|
employeeId
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearEmployeeSelection = () => {
|
||||||
|
const { employeeId, ...nextSearch } = search;
|
||||||
|
void employeeId;
|
||||||
|
history({
|
||||||
|
search: queryString.stringify(nextSearch)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleOnRowClick = (record) => {
|
const handleOnRowClick = (record) => {
|
||||||
if (record) {
|
if (record) {
|
||||||
search.employeeId = record.id;
|
navigateToEmployee(record.id);
|
||||||
history({ search: queryString.stringify(search) });
|
|
||||||
} else {
|
} else {
|
||||||
delete search.employeeId;
|
clearEmployeeSelection();
|
||||||
history({ search: queryString.stringify(search) });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const handleTableChange = (pagination, filters, sorter) => {
|
const handleTableChange = (pagination, filters, sorter) => {
|
||||||
@@ -89,44 +106,39 @@ export default function ShopEmployeesListComponent({ loading, employees }) {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
return (
|
return (
|
||||||
<div>
|
<LayoutFormRow
|
||||||
<ResponsiveTable
|
title={t("bodyshop.labels.employees")}
|
||||||
title={() => {
|
actions={[
|
||||||
return (
|
<Button key="new-employee" type="primary" block onClick={() => navigateToEmployee("new")}>
|
||||||
<Button
|
{t("employees.actions.new")}
|
||||||
type="primary"
|
</Button>
|
||||||
onClick={() => {
|
]}
|
||||||
search.employeeId = "new";
|
>
|
||||||
history({ search: queryString.stringify(search) });
|
{employees.length === 0 ? (
|
||||||
}}
|
<ConfigListEmptyState actionLabel={t("employees.actions.new")} />
|
||||||
>
|
) : (
|
||||||
{t("employees.actions.new")}
|
<ResponsiveTable
|
||||||
</Button>
|
loading={loading}
|
||||||
);
|
pagination={{ placement: "top" }}
|
||||||
}}
|
columns={columns}
|
||||||
loading={loading}
|
mobileColumnKeys={["employee_number", "employee_name", "active"]}
|
||||||
pagination={{ placement: "top" }}
|
rowKey="id"
|
||||||
columns={columns}
|
dataSource={employees}
|
||||||
mobileColumnKeys={["employee_number", "employee_name", "active"]}
|
rowSelection={{
|
||||||
rowKey="id"
|
onSelect: (props) => navigateToEmployee(props.id),
|
||||||
dataSource={employees}
|
type: "radio",
|
||||||
rowSelection={{
|
selectedRowKeys: [search.employeeId]
|
||||||
onSelect: (props) => {
|
}}
|
||||||
search.employeeId = props.id;
|
onChange={handleTableChange}
|
||||||
history({ search: queryString.stringify(search) });
|
onRow={(record) => {
|
||||||
},
|
return {
|
||||||
type: "radio",
|
onClick: () => {
|
||||||
selectedRowKeys: [search.employeeId]
|
handleOnRowClick(record);
|
||||||
}}
|
}
|
||||||
onChange={handleTableChange}
|
};
|
||||||
onRow={(record) => {
|
}}
|
||||||
return {
|
/>
|
||||||
onClick: () => {
|
)}
|
||||||
handleOnRowClick(record);
|
</LayoutFormRow>
|
||||||
}
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,8 +163,14 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
|
|||||||
<Card
|
<Card
|
||||||
title={<ShopInfoSectionNavigator tabsRef={tabsRef} activeTabKey={activeTabKey} />}
|
title={<ShopInfoSectionNavigator tabsRef={tabsRef} activeTabKey={activeTabKey} />}
|
||||||
extra={
|
extra={
|
||||||
<Button type="primary" loading={saveLoading} onClick={() => form.submit()} id="shop-info-save-button">
|
<Button
|
||||||
{t("general.actions.save")}
|
type="primary"
|
||||||
|
loading={saveLoading}
|
||||||
|
onClick={() => form.submit()}
|
||||||
|
id="shop-info-save-button"
|
||||||
|
style={{ minWidth: 210 }}
|
||||||
|
>
|
||||||
|
{t("bodyshop.actions.save_shop_information")}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -5,6 +5,7 @@ import styled from "styled-components";
|
|||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
import ConfigFormTypes from "../config-form-components/config-form-types";
|
import ConfigFormTypes from "../config-form-components/config-form-types";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
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 LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import {
|
import {
|
||||||
INLINE_TITLE_GROUP_STYLE,
|
INLINE_TITLE_GROUP_STYLE,
|
||||||
@@ -12,7 +13,8 @@ import {
|
|||||||
INLINE_TITLE_INPUT_STYLE,
|
INLINE_TITLE_INPUT_STYLE,
|
||||||
INLINE_TITLE_LABEL_STYLE,
|
INLINE_TITLE_LABEL_STYLE,
|
||||||
INLINE_TITLE_ROW_STYLE,
|
INLINE_TITLE_ROW_STYLE,
|
||||||
INLINE_TITLE_SEPARATOR_STYLE
|
INLINE_TITLE_SEPARATOR_STYLE,
|
||||||
|
INLINE_TITLE_SWITCH_GROUP_STYLE
|
||||||
} from "../layout-form-row/inline-form-row-title.utils.js";
|
} from "../layout-form-row/inline-form-row-title.utils.js";
|
||||||
|
|
||||||
const SelectorDiv = styled.div`
|
const SelectorDiv = styled.div`
|
||||||
@@ -87,320 +89,318 @@ export default function ShopInfoIntakeChecklistComponent({ form }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</SelectorDiv>
|
</SelectorDiv>
|
||||||
<LayoutFormRow header={t("bodyshop.labels.intakechecklist")} id="intakechecklist">
|
<Form.List name={["intakechecklist", "form"]}>
|
||||||
<Form.List name={["intakechecklist", "form"]}>
|
{(fields, { add, remove, move }) => {
|
||||||
{(fields, { add, remove, move }) => {
|
return (
|
||||||
return (
|
<LayoutFormRow
|
||||||
|
header={t("bodyshop.labels.intakechecklist")}
|
||||||
|
id="intakechecklist"
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-intake-checklist-item"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("bodyshop.actions.add_intake_checklist_item")}
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
{fields.map((field, index) => {
|
{fields.length === 0 ? (
|
||||||
return (
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.add_intake_checklist_item")} />
|
||||||
<Form.Item key={field.key}>
|
) : (
|
||||||
<LayoutFormRow
|
fields.map((field, index) => {
|
||||||
noDivider
|
return (
|
||||||
title={
|
<Form.Item key={field.key}>
|
||||||
<div style={INLINE_TITLE_ROW_STYLE}>
|
<LayoutFormRow
|
||||||
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
noDivider
|
||||||
<div
|
title={
|
||||||
style={{
|
<div style={INLINE_TITLE_ROW_STYLE}>
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
||||||
flex: "1 1 320px"
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
||||||
}}
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("jobs.fields.intake.name")}</div>
|
||||||
>
|
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("jobs.fields.intake.name")}</div>
|
|
||||||
<Form.Item
|
|
||||||
noStyle
|
|
||||||
name={[field.name, "name"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
size="small"
|
|
||||||
placeholder={t("jobs.fields.intake.name")}
|
|
||||||
style={{
|
|
||||||
...INLINE_TITLE_INPUT_STYLE,
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
|
||||||
flex: "0 0 auto"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("jobs.fields.intake.required")}</div>
|
|
||||||
<Form.Item noStyle name={[field.name, "required"]} valuePropName="checked">
|
|
||||||
<Switch />
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
wrapTitle
|
|
||||||
extra={
|
|
||||||
<Space align="center" size="small">
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<DeleteFilled />}
|
|
||||||
onClick={() => {
|
|
||||||
remove(field.name);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormListMoveArrows
|
|
||||||
move={move}
|
|
||||||
index={index}
|
|
||||||
total={fields.length}
|
|
||||||
orientation="horizontal"
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.intake.type")}
|
|
||||||
key={`${index}type`}
|
|
||||||
name={[field.name, "type"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Select options={Object.keys(ConfigFormTypes).map((i) => ({ value: i, label: i }))} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.intake.label")}
|
|
||||||
key={`${index}label`}
|
|
||||||
name={[field.name, "label"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item shouldUpdate>
|
|
||||||
{() => {
|
|
||||||
if (form.getFieldValue(["intakechecklist", "form", index, "type"]) !== "slider")
|
|
||||||
return null;
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.intake.min")}
|
noStyle
|
||||||
key={`${index}min`}
|
name={[field.name, "name"]}
|
||||||
name={[field.name, "min"]}
|
|
||||||
dependencies={[[field.name, "type"]]}
|
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true
|
required: true
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber />
|
<Input
|
||||||
|
size="small"
|
||||||
|
placeholder={t("jobs.fields.intake.name")}
|
||||||
|
style={{
|
||||||
|
...INLINE_TITLE_INPUT_STYLE,
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</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("jobs.fields.intake.required")}</div>
|
||||||
|
<Form.Item noStyle name={[field.name, "required"]} 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>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.intake.type")}
|
||||||
|
key={`${index}type`}
|
||||||
|
name={[field.name, "type"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select options={Object.keys(ConfigFormTypes).map((i) => ({ value: i, label: i }))} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.intake.label")}
|
||||||
|
key={`${index}label`}
|
||||||
|
name={[field.name, "label"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item shouldUpdate>
|
||||||
|
{() => {
|
||||||
|
if (form.getFieldValue(["intakechecklist", "form", index, "type"]) !== "slider")
|
||||||
|
return null;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.intake.min")}
|
||||||
|
key={`${index}min`}
|
||||||
|
name={[field.name, "min"]}
|
||||||
|
dependencies={[[field.name, "type"]]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("jobs.fields.intake.max")}
|
||||||
|
key={`${index}max`}
|
||||||
|
name={[field.name, "max"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber />
|
||||||
|
</Form.Item>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.Item>
|
||||||
|
</LayoutFormRow>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</LayoutFormRow>
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
</Form.List>
|
||||||
|
<Form.List name={["deliverchecklist", "form"]}>
|
||||||
|
{(fields, { add, remove, move }) => {
|
||||||
|
return (
|
||||||
|
<LayoutFormRow
|
||||||
|
header={t("bodyshop.labels.deliverchecklist")}
|
||||||
|
id="deliverchecklist"
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-delivery-checklist-item"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("bodyshop.actions.add_delivery_checklist_item")}
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{fields.length === 0 ? (
|
||||||
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.add_delivery_checklist_item")} />
|
||||||
|
) : (
|
||||||
|
fields.map((field, index) => {
|
||||||
|
return (
|
||||||
|
<Form.Item key={field.key}>
|
||||||
|
<LayoutFormRow
|
||||||
|
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("jobs.fields.intake.name")}</div>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.intake.max")}
|
noStyle
|
||||||
key={`${index}max`}
|
name={[field.name, "name"]}
|
||||||
name={[field.name, "max"]}
|
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true
|
required: true
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber />
|
<Input
|
||||||
|
size="small"
|
||||||
|
placeholder={t("jobs.fields.intake.name")}
|
||||||
|
style={{
|
||||||
|
...INLINE_TITLE_INPUT_STYLE,
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</div>
|
||||||
);
|
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
||||||
}}
|
<div style={INLINE_TITLE_SWITCH_GROUP_STYLE}>
|
||||||
</Form.Item>
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("jobs.fields.intake.required")}</div>
|
||||||
</LayoutFormRow>
|
<Form.Item noStyle name={[field.name, "required"]} valuePropName="checked">
|
||||||
</Form.Item>
|
<Switch />
|
||||||
);
|
</Form.Item>
|
||||||
})}
|
</div>
|
||||||
<Form.Item>
|
|
||||||
<Button
|
|
||||||
type="dashed"
|
|
||||||
onClick={() => {
|
|
||||||
add();
|
|
||||||
}}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
|
||||||
{t("general.actions.add")}
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Form.List>
|
|
||||||
</LayoutFormRow>
|
|
||||||
<LayoutFormRow header={t("bodyshop.labels.deliverchecklist")} id="deliverchecklist">
|
|
||||||
<Form.List name={["deliverchecklist", "form"]}>
|
|
||||||
{(fields, { add, remove, move }) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{fields.map((field, index) => {
|
|
||||||
return (
|
|
||||||
<Form.Item key={field.key}>
|
|
||||||
<LayoutFormRow
|
|
||||||
noDivider
|
|
||||||
title={
|
|
||||||
<div style={INLINE_TITLE_ROW_STYLE}>
|
|
||||||
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
|
||||||
flex: "1 1 320px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("jobs.fields.intake.name")}</div>
|
|
||||||
<Form.Item
|
|
||||||
noStyle
|
|
||||||
name={[field.name, "name"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
size="small"
|
|
||||||
placeholder={t("jobs.fields.intake.name")}
|
|
||||||
style={{
|
|
||||||
...INLINE_TITLE_INPUT_STYLE,
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
</div>
|
||||||
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
}
|
||||||
<div
|
wrapTitle
|
||||||
style={{
|
extra={
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<Space align="center" size="small">
|
||||||
flex: "0 0 auto"
|
<Button
|
||||||
}}
|
type="text"
|
||||||
>
|
danger
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("jobs.fields.intake.required")}</div>
|
icon={<DeleteFilled />}
|
||||||
<Form.Item noStyle name={[field.name, "required"]} valuePropName="checked">
|
onClick={() => {
|
||||||
<Switch />
|
remove(field.name);
|
||||||
</Form.Item>
|
}}
|
||||||
</div>
|
/>
|
||||||
</div>
|
<FormListMoveArrows
|
||||||
}
|
move={move}
|
||||||
wrapTitle
|
index={index}
|
||||||
extra={
|
total={fields.length}
|
||||||
<Space align="center" size="small">
|
orientation="horizontal"
|
||||||
<Button
|
/>
|
||||||
type="text"
|
</Space>
|
||||||
icon={<DeleteFilled />}
|
}
|
||||||
onClick={() => {
|
|
||||||
remove(field.name);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormListMoveArrows
|
|
||||||
move={move}
|
|
||||||
index={index}
|
|
||||||
total={fields.length}
|
|
||||||
orientation="horizontal"
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.intake.type")}
|
|
||||||
key={`${index}typed`}
|
|
||||||
name={[field.name, "type"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<Select options={Object.keys(ConfigFormTypes).map((i) => ({ value: i, label: i }))} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.intake.type")}
|
||||||
|
key={`${index}typed`}
|
||||||
|
name={[field.name, "type"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select options={Object.keys(ConfigFormTypes).map((i) => ({ value: i, label: i }))} />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.intake.label")}
|
label={t("jobs.fields.intake.label")}
|
||||||
key={`${index}labeld`}
|
key={`${index}labeld`}
|
||||||
name={[field.name, "label"]}
|
name={[field.name, "label"]}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true
|
required: true
|
||||||
//message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
|
||||||
<Form.Item shouldUpdate>
|
<Form.Item shouldUpdate>
|
||||||
{() => {
|
{() => {
|
||||||
if (form.getFieldValue(["deliverchecklist", "form", index, "type"]) !== "slider")
|
if (form.getFieldValue(["deliverchecklist", "form", index, "type"]) !== "slider")
|
||||||
return null;
|
return null;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.intake.min")}
|
label={t("jobs.fields.intake.min")}
|
||||||
key={`${index}mind`}
|
key={`${index}mind`}
|
||||||
name={[field.name, "min"]}
|
name={[field.name, "min"]}
|
||||||
dependencies={[[field.name, "type"]]}
|
dependencies={[[field.name, "type"]]}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: form.getFieldValue([field.name, "type"]) === "slider"
|
required: form.getFieldValue([field.name, "type"]) === "slider"
|
||||||
//message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label={t("jobs.fields.intake.max")}
|
label={t("jobs.fields.intake.max")}
|
||||||
key={`${index}maxd`}
|
key={`${index}maxd`}
|
||||||
name={[field.name, "max"]}
|
name={[field.name, "max"]}
|
||||||
dependencies={[[field.name, "type"]]}
|
dependencies={[[field.name, "type"]]}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: form.getFieldValue([field.name, "type"]) === "slider"
|
required: form.getFieldValue([field.name, "type"]) === "slider"
|
||||||
//message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<InputNumber />
|
<InputNumber />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
})}
|
})
|
||||||
<Form.Item>
|
)}
|
||||||
<Button
|
|
||||||
type="dashed"
|
|
||||||
onClick={() => {
|
|
||||||
add();
|
|
||||||
}}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
|
||||||
{t("general.actions.add")}
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</LayoutFormRow>
|
||||||
}}
|
);
|
||||||
</Form.List>
|
}}
|
||||||
</LayoutFormRow>
|
</Form.List>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button, Form, Input, Space } from "antd";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
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 LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import {
|
import {
|
||||||
INLINE_TITLE_GROUP_STYLE,
|
INLINE_TITLE_GROUP_STYLE,
|
||||||
@@ -25,361 +26,364 @@ export default function ShopInfoLaborRates() {
|
|||||||
<CurrencyInput min={0} />
|
<CurrencyInput min={0} />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("bodyshop.labels.laborrates")}>
|
<Form.List name={["md_labor_rates"]}>
|
||||||
<Form.List name={["md_labor_rates"]}>
|
{(fields, { add, remove, move }) => {
|
||||||
{(fields, { add, remove, move }) => {
|
return (
|
||||||
return (
|
<LayoutFormRow
|
||||||
|
header={t("bodyshop.labels.laborrates")}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-labor-rate"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("bodyshop.actions.newlaborrate")}
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
{fields.map((field, index) => {
|
{fields.length === 0 ? (
|
||||||
return (
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.newlaborrate")} />
|
||||||
<Form.Item key={field.key}>
|
) : (
|
||||||
<LayoutFormRow
|
fields.map((field, index) => {
|
||||||
noDivider={index === 0}
|
return (
|
||||||
title={
|
<Form.Item key={field.key}>
|
||||||
<div style={INLINE_TITLE_ROW_STYLE}>
|
<LayoutFormRow
|
||||||
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
noDivider={index === 0}
|
||||||
<div
|
title={
|
||||||
style={{
|
<div style={INLINE_TITLE_ROW_STYLE}>
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
||||||
flex: "1 1 340px"
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
||||||
}}
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("jobs.fields.labor_rate_desc")}</div>
|
||||||
>
|
<Form.Item
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("jobs.fields.labor_rate_desc")}</div>
|
noStyle
|
||||||
<Form.Item
|
name={[field.name, "rate_label"]}
|
||||||
noStyle
|
rules={[
|
||||||
name={[field.name, "rate_label"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
}
|
||||||
required: true
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<Input
|
||||||
>
|
size="small"
|
||||||
<Input
|
placeholder={t("jobs.fields.labor_rate_desc")}
|
||||||
size="small"
|
style={{
|
||||||
placeholder={t("jobs.fields.labor_rate_desc")}
|
...INLINE_TITLE_INPUT_STYLE,
|
||||||
style={{
|
width: "100%"
|
||||||
...INLINE_TITLE_INPUT_STYLE,
|
}}
|
||||||
width: "100%"
|
/>
|
||||||
}}
|
</Form.Item>
|
||||||
/>
|
</div>
|
||||||
</Form.Item>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
}
|
wrapTitle
|
||||||
wrapTitle
|
extra={
|
||||||
extra={
|
<Space align="center" size="small">
|
||||||
<Space align="center" size="small">
|
<Button
|
||||||
<Button
|
type="text"
|
||||||
type="text"
|
danger
|
||||||
icon={<DeleteFilled />}
|
icon={<DeleteFilled />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
remove(field.name);
|
remove(field.name);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<FormListMoveArrows
|
<FormListMoveArrows
|
||||||
move={move}
|
move={move}
|
||||||
index={index}
|
index={index}
|
||||||
total={fields.length}
|
total={fields.length}
|
||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
label={t("jobs.fields.rate_laa")}
|
|
||||||
key={`${index}rate_laa`}
|
|
||||||
name={[field.name, "rate_laa"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_laa")}
|
||||||
<Form.Item
|
key={`${index}rate_laa`}
|
||||||
label={t("jobs.fields.rate_lab")}
|
name={[field.name, "rate_laa"]}
|
||||||
key={`${index}rate_lab`}
|
rules={[
|
||||||
name={[field.name, "rate_lab"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_lab")}
|
||||||
<Form.Item
|
key={`${index}rate_lab`}
|
||||||
label={t("jobs.fields.rate_lad")}
|
name={[field.name, "rate_lab"]}
|
||||||
key={`${index}rate_lad`}
|
rules={[
|
||||||
name={[field.name, "rate_lad"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_lad")}
|
||||||
<Form.Item
|
key={`${index}rate_lad`}
|
||||||
label={t("jobs.fields.rate_lae")}
|
name={[field.name, "rate_lad"]}
|
||||||
key={`${index}rate_lae`}
|
rules={[
|
||||||
name={[field.name, "rate_lae"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_lae")}
|
||||||
<Form.Item
|
key={`${index}rate_lae`}
|
||||||
label={t("jobs.fields.rate_laf")}
|
name={[field.name, "rate_lae"]}
|
||||||
key={`${index}rate_laf`}
|
rules={[
|
||||||
name={[field.name, "rate_laf"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_laf")}
|
||||||
<Form.Item
|
key={`${index}rate_laf`}
|
||||||
label={t("jobs.fields.rate_lag")}
|
name={[field.name, "rate_laf"]}
|
||||||
key={`${index}rate_lag`}
|
rules={[
|
||||||
name={[field.name, "rate_lag"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_lag")}
|
||||||
<Form.Item
|
key={`${index}rate_lag`}
|
||||||
label={t("jobs.fields.rate_lam")}
|
name={[field.name, "rate_lag"]}
|
||||||
key={`${index}rate_lam`}
|
rules={[
|
||||||
name={[field.name, "rate_lam"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_lam")}
|
||||||
<Form.Item
|
key={`${index}rate_lam`}
|
||||||
label={t("jobs.fields.rate_lar")}
|
name={[field.name, "rate_lam"]}
|
||||||
key={`${index}rate_lar`}
|
rules={[
|
||||||
name={[field.name, "rate_lar"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_lar")}
|
||||||
<Form.Item
|
key={`${index}rate_lar`}
|
||||||
label={t("jobs.fields.rate_las")}
|
name={[field.name, "rate_lar"]}
|
||||||
key={`${index}rate_las`}
|
rules={[
|
||||||
name={[field.name, "rate_las"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_las")}
|
||||||
<Form.Item
|
key={`${index}rate_las`}
|
||||||
label={t("jobs.fields.rate_la1")}
|
name={[field.name, "rate_las"]}
|
||||||
key={`${index}rate_la1`}
|
rules={[
|
||||||
name={[field.name, "rate_la1"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_la1")}
|
||||||
<Form.Item
|
key={`${index}rate_la1`}
|
||||||
label={t("jobs.fields.rate_la2")}
|
name={[field.name, "rate_la1"]}
|
||||||
key={`${index}rate_la2`}
|
rules={[
|
||||||
name={[field.name, "rate_la2"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_la2")}
|
||||||
<Form.Item
|
key={`${index}rate_la2`}
|
||||||
label={t("jobs.fields.rate_la3")}
|
name={[field.name, "rate_la2"]}
|
||||||
key={`${index}rate_la3`}
|
rules={[
|
||||||
name={[field.name, "rate_la3"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_la3")}
|
||||||
<Form.Item
|
key={`${index}rate_la3`}
|
||||||
label={t("jobs.fields.rate_la4")}
|
name={[field.name, "rate_la3"]}
|
||||||
key={`${index}rate_la4`}
|
rules={[
|
||||||
name={[field.name, "rate_la4"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_la4")}
|
||||||
<Form.Item
|
key={`${index}rate_la4`}
|
||||||
label={t("jobs.fields.rate_mash")}
|
name={[field.name, "rate_la4"]}
|
||||||
key={`${index}rate_mash`}
|
rules={[
|
||||||
name={[field.name, "rate_mash"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_mash")}
|
||||||
<Form.Item
|
key={`${index}rate_mash`}
|
||||||
label={t("jobs.fields.rate_mapa")}
|
name={[field.name, "rate_mash"]}
|
||||||
key={`${index}rate_mapa`}
|
rules={[
|
||||||
name={[field.name, "rate_mapa"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_mapa")}
|
||||||
<Form.Item
|
key={`${index}rate_mapa`}
|
||||||
label={t("jobs.fields.rate_ma2s")}
|
name={[field.name, "rate_mapa"]}
|
||||||
key={`${index}rate_ma2s`}
|
rules={[
|
||||||
name={[field.name, "rate_ma2s"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_ma2s")}
|
||||||
<Form.Item
|
key={`${index}rate_ma2s`}
|
||||||
label={t("jobs.fields.rate_ma3s")}
|
name={[field.name, "rate_ma2s"]}
|
||||||
key={`${index}rate_ma3s`}
|
rules={[
|
||||||
name={[field.name, "rate_ma3s"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_ma3s")}
|
||||||
{
|
key={`${index}rate_ma3s`}
|
||||||
// <Form.Item
|
name={[field.name, "rate_ma3s"]}
|
||||||
// label={t("jobs.fields.rate_mabl")}
|
rules={[
|
||||||
// key={`${index}rate_mabl`}
|
{
|
||||||
// name={[field.name, "rate_mabl"]}
|
required: true
|
||||||
// rules={[
|
//message: t("general.validation.required"),
|
||||||
// {
|
}
|
||||||
// required: true,
|
]}
|
||||||
// //message: t("general.validation.required"),
|
>
|
||||||
// },
|
<CurrencyInput min={0} />
|
||||||
// ]}
|
</Form.Item>
|
||||||
// >
|
{
|
||||||
// <CurrencyInput min={0} />
|
// <Form.Item
|
||||||
// </Form.Item>
|
// label={t("jobs.fields.rate_mabl")}
|
||||||
// <Form.Item
|
// key={`${index}rate_mabl`}
|
||||||
// label={t("jobs.fields.rate_macs")}
|
// name={[field.name, "rate_mabl"]}
|
||||||
// key={`${index}rate_macs`}
|
// rules={[
|
||||||
// name={[field.name, "rate_macs"]}
|
// {
|
||||||
// rules={[
|
// required: true,
|
||||||
// {
|
// //message: t("general.validation.required"),
|
||||||
// required: true,
|
// },
|
||||||
// //message: t("general.validation.required"),
|
// ]}
|
||||||
// },
|
// >
|
||||||
// ]}
|
// <CurrencyInput min={0} />
|
||||||
// >
|
// </Form.Item>
|
||||||
// <CurrencyInput min={0} />
|
// <Form.Item
|
||||||
// </Form.Item>
|
// label={t("jobs.fields.rate_macs")}
|
||||||
}
|
// key={`${index}rate_macs`}
|
||||||
<Form.Item
|
// name={[field.name, "rate_macs"]}
|
||||||
label={t("jobs.fields.rate_matd")}
|
// rules={[
|
||||||
key={`${index}rate_matd`}
|
// {
|
||||||
name={[field.name, "rate_matd"]}
|
// required: true,
|
||||||
rules={[
|
// //message: t("general.validation.required"),
|
||||||
{
|
// },
|
||||||
required: true
|
// ]}
|
||||||
//message: t("general.validation.required"),
|
// >
|
||||||
}
|
// <CurrencyInput min={0} />
|
||||||
]}
|
// </Form.Item>
|
||||||
>
|
}
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_matd")}
|
||||||
<Form.Item
|
key={`${index}rate_matd`}
|
||||||
label={t("jobs.fields.rate_mahw")}
|
name={[field.name, "rate_matd"]}
|
||||||
key={`${index}rate_mahw`}
|
rules={[
|
||||||
name={[field.name, "rate_mahw"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<CurrencyInput min={0} />
|
||||||
>
|
</Form.Item>
|
||||||
<CurrencyInput min={0} />
|
<Form.Item
|
||||||
</Form.Item>
|
label={t("jobs.fields.rate_mahw")}
|
||||||
</LayoutFormRow>
|
key={`${index}rate_mahw`}
|
||||||
</Form.Item>
|
name={[field.name, "rate_mahw"]}
|
||||||
);
|
rules={[
|
||||||
})}
|
{
|
||||||
<Form.Item>
|
required: true
|
||||||
<Button
|
//message: t("general.validation.required"),
|
||||||
type="dashed"
|
}
|
||||||
onClick={() => {
|
]}
|
||||||
add();
|
>
|
||||||
}}
|
<CurrencyInput min={0} />
|
||||||
style={{ width: "100%" }}
|
</Form.Item>
|
||||||
>
|
</LayoutFormRow>
|
||||||
{t("bodyshop.actions.newlaborrate")}
|
</Form.Item>
|
||||||
</Button>
|
);
|
||||||
</Form.Item>
|
})
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
</LayoutFormRow>
|
||||||
}}
|
);
|
||||||
</Form.List>
|
}}
|
||||||
</LayoutFormRow>
|
</Form.List>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button, Col, Form, Input, Row, Select, Space, Switch } from "antd";
|
|||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
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 LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import {
|
import {
|
||||||
INLINE_TITLE_GROUP_STYLE,
|
INLINE_TITLE_GROUP_STYLE,
|
||||||
@@ -10,7 +11,8 @@ import {
|
|||||||
INLINE_TITLE_INPUT_STYLE,
|
INLINE_TITLE_INPUT_STYLE,
|
||||||
INLINE_TITLE_LABEL_STYLE,
|
INLINE_TITLE_LABEL_STYLE,
|
||||||
INLINE_TITLE_ROW_STYLE,
|
INLINE_TITLE_ROW_STYLE,
|
||||||
INLINE_TITLE_SEPARATOR_STYLE
|
INLINE_TITLE_SEPARATOR_STYLE,
|
||||||
|
INLINE_TITLE_SWITCH_GROUP_STYLE
|
||||||
} from "../layout-form-row/inline-form-row-title.utils.js";
|
} from "../layout-form-row/inline-form-row-title.utils.js";
|
||||||
import i18n from "i18next";
|
import i18n from "i18next";
|
||||||
|
|
||||||
@@ -76,229 +78,221 @@ export default function ShopInfoPartsScan({ form }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<LayoutFormRow header={t("bodyshop.labels.md_parts_scan")}>
|
<Form.List name={["md_parts_scan"]}>
|
||||||
<Form.List name={["md_parts_scan"]}>
|
{(fields, { add, remove, move }) => (
|
||||||
{(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>
|
<div>
|
||||||
{fields.map((field, index) => {
|
{fields.length === 0 ? (
|
||||||
const selectedField = watchedFields?.[index]?.field || "line_desc";
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.addpartsrule")} />
|
||||||
const fieldType = getFieldType(selectedField);
|
) : (
|
||||||
|
fields.map((field, index) => {
|
||||||
|
const selectedField = watchedFields?.[index]?.field || "line_desc";
|
||||||
|
const fieldType = getFieldType(selectedField);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form.Item key={field.key}>
|
<Form.Item key={field.key}>
|
||||||
<LayoutFormRow
|
<LayoutFormRow
|
||||||
noDivider
|
noDivider
|
||||||
title={
|
title={
|
||||||
<div style={INLINE_TITLE_ROW_STYLE}>
|
<div style={INLINE_TITLE_ROW_STYLE}>
|
||||||
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
||||||
<div
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
||||||
style={{
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("bodyshop.fields.md_parts_scan.field")}</div>
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<Form.Item
|
||||||
flex: "1 1 260px"
|
noStyle
|
||||||
}}
|
name={[field.name, "field"]}
|
||||||
>
|
rules={[
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("bodyshop.fields.md_parts_scan.field")}</div>
|
{
|
||||||
|
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
|
<Form.Item
|
||||||
noStyle
|
label={t("bodyshop.fields.md_parts_scan.update_field")}
|
||||||
name={[field.name, "field"]}
|
name={[field.name, "update_field"]}
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
message: t("general.validation.required", {
|
|
||||||
label: t("bodyshop.fields.md_parts_scan.field")
|
|
||||||
})
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
options={fieldSelectOptions}
|
options={fieldSelectOptions}
|
||||||
onChange={() => {
|
allowClear
|
||||||
form.setFields([
|
onClear={() =>
|
||||||
{ name: ["md_parts_scan", index, "operation"], value: "contains" },
|
form.setFields([{ name: ["md_parts_scan", index, "update_field"], value: null }])
|
||||||
{ name: ["md_parts_scan", index, "value"], value: undefined }
|
}
|
||||||
]);
|
|
||||||
}}
|
|
||||||
style={{
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
styles={{
|
|
||||||
selector: INLINE_TITLE_INPUT_STYLE
|
|
||||||
}}
|
|
||||||
size="small"
|
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</Col>
|
||||||
{fieldType === "string" && (
|
|
||||||
<>
|
{/* Update Field */}
|
||||||
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
<Col span={4}>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
|
||||||
flex: "0 0 auto"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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_GROUP_STYLE,
|
|
||||||
flex: "0 0 auto"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<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"
|
|
||||||
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
|
<Form.Item
|
||||||
label={t("bodyshop.fields.md_parts_scan.operation")}
|
label={t("bodyshop.fields.md_parts_scan.update_value")}
|
||||||
name={[field.name, "operation"]}
|
name={[field.name, "update_value"]}
|
||||||
|
dependencies={[["md_parts_scan", index, "update_field"]]}
|
||||||
|
tooltip={t("bodyshop.tooltips.md_parts_scan.update_value_tooltip")}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true,
|
required: form.getFieldValue(["md_parts_scan", index, "update_field"]),
|
||||||
message: t("general.validation.required", {
|
message: t("general.validation.required", {
|
||||||
label: t("bodyshop.fields.md_parts_scan.operation")
|
label: t("bodyshop.fields.md_parts_scan.update_value")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Select options={operationOptions[fieldType]} />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Col>
|
</Col>
|
||||||
)}
|
</Row>
|
||||||
|
</LayoutFormRow>
|
||||||
{/* Value */}
|
</Form.Item>
|
||||||
{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>
|
|
||||||
</LayoutFormRow>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
|
|
||||||
<Form.Item>
|
|
||||||
<Button
|
|
||||||
type="dashed"
|
|
||||||
onClick={() =>
|
|
||||||
add({
|
|
||||||
field: "line_desc",
|
|
||||||
operation: "contains",
|
|
||||||
mark_critical: true,
|
|
||||||
caseInsensitive: true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
|
||||||
{t("bodyshop.actions.addpartsrule")}
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
</LayoutFormRow>
|
||||||
</Form.List>
|
)}
|
||||||
</LayoutFormRow>
|
</Form.List>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -7,6 +7,7 @@ import { ChromePicker } from "react-color";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { getFormListItemTitle } from "../form-list-move-arrows/form-list-item-title.utils";
|
import { getFormListItemTitle } from "../form-list-move-arrows/form-list-item-title.utils";
|
||||||
|
import ConfigListEmptyState from "../layout-form-row/config-list-empty-state.component.jsx";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import { DEFAULT_TRANSLUCENT_CARD_COLOR, getTintedCardSurfaceStyles } from "./shop-info.color.utils";
|
import { DEFAULT_TRANSLUCENT_CARD_COLOR, getTintedCardSurfaceStyles } from "./shop-info.color.utils";
|
||||||
|
|
||||||
@@ -405,106 +406,116 @@ export function ShopInfoROStatusComponent({ bodyshop, form }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
{Production_List_Status_Colors.treatment === "on" && (
|
{Production_List_Status_Colors.treatment === "on" && (
|
||||||
<LayoutFormRow grow header={t("bodyshop.fields.statuses.production_colors")} id="production_colors">
|
<Form.List name={["md_ro_statuses", "production_colors"]}>
|
||||||
<Form.List name={["md_ro_statuses", "production_colors"]}>
|
{(fields, { add, remove }) => {
|
||||||
{(fields, { add, remove }) => {
|
return (
|
||||||
return (
|
<LayoutFormRow
|
||||||
|
grow
|
||||||
|
header={t("bodyshop.fields.statuses.production_colors")}
|
||||||
|
id="production_colors"
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-production-status-color"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add({
|
||||||
|
color: { ...DEFAULT_TRANSLUCENT_CARD_COLOR }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("bodyshop.actions.add_production_status_color")}
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
<Space size="large" wrap align="start">
|
{fields.length === 0 ? (
|
||||||
{fields.map((field, index) => {
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.add_production_status_color")} />
|
||||||
const productionColor = productionColors[field.name] || {};
|
) : (
|
||||||
const productionColorSurfaceStyles = getTintedCardSurfaceStyles(productionColor.color);
|
<Space size="large" wrap align="start">
|
||||||
const selectedProductionColorStatuses = productionColors
|
{fields.map((field, index) => {
|
||||||
.map((item) => item?.status)
|
const productionColor = productionColors[field.name] || {};
|
||||||
.filter(Boolean);
|
const productionColorSurfaceStyles = getTintedCardSurfaceStyles(productionColor.color);
|
||||||
const productionColorStatusOptions = [
|
const selectedProductionColorStatuses = productionColors
|
||||||
...new Set([productionColor.status, ...availableProductionStatuses])
|
.map((item) => item?.status)
|
||||||
]
|
.filter(Boolean);
|
||||||
.filter(Boolean)
|
const productionColorStatusOptions = [
|
||||||
.filter(
|
...new Set([productionColor.status, ...availableProductionStatuses])
|
||||||
(status) =>
|
]
|
||||||
status === productionColor.status || !selectedProductionColorStatuses.includes(status)
|
.filter(Boolean)
|
||||||
);
|
.filter(
|
||||||
|
(status) =>
|
||||||
|
status === productionColor.status || !selectedProductionColorStatuses.includes(status)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutFormRow
|
<LayoutFormRow
|
||||||
key={field.key}
|
key={field.key}
|
||||||
noDivider
|
noDivider
|
||||||
title={
|
title={
|
||||||
<Form.Item
|
<Form.Item
|
||||||
noStyle
|
noStyle
|
||||||
key={`${index}status`}
|
key={`${index}status`}
|
||||||
name={[field.name, "status"]}
|
name={[field.name, "status"]}
|
||||||
rules={[
|
rules={[
|
||||||
{
|
{
|
||||||
required: true
|
required: true
|
||||||
//message: t("general.validation.required"),
|
//message: t("general.validation.required"),
|
||||||
}
|
}
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
className="production-status-color-title-select"
|
className="production-status-color-title-select"
|
||||||
variant="borderless"
|
variant="borderless"
|
||||||
placeholder={getFormListItemTitle(
|
placeholder={getFormListItemTitle(
|
||||||
t("jobs.fields.status"),
|
t("jobs.fields.status"),
|
||||||
index,
|
index,
|
||||||
productionColor.status
|
productionColor.status
|
||||||
)}
|
)}
|
||||||
options={productionColorStatusOptions.map((item) => ({
|
options={productionColorStatusOptions.map((item) => ({
|
||||||
value: item,
|
value: item,
|
||||||
label: item
|
label: item
|
||||||
}))}
|
}))}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
|
extra={
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
danger
|
||||||
|
icon={<DeleteFilled />}
|
||||||
|
onClick={() => {
|
||||||
|
remove(field.name);
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</Form.Item>
|
}
|
||||||
}
|
{...productionColorSurfaceStyles}
|
||||||
extra={
|
style={{ width: 260, marginBottom: 0 }}
|
||||||
<Button
|
>
|
||||||
type="text"
|
<div>
|
||||||
icon={<DeleteFilled />}
|
<Form.Item
|
||||||
onClick={() => {
|
key={`${index}color`}
|
||||||
remove(field.name);
|
name={[field.name, "color"]}
|
||||||
}}
|
rules={[
|
||||||
/>
|
{
|
||||||
}
|
required: true
|
||||||
{...productionColorSurfaceStyles}
|
//message: t("general.validation.required"),
|
||||||
style={{ width: 260, marginBottom: 0 }}
|
}
|
||||||
>
|
]}
|
||||||
<div>
|
>
|
||||||
<Form.Item
|
<ColorPicker />
|
||||||
key={`${index}color`}
|
</Form.Item>
|
||||||
name={[field.name, "color"]}
|
</div>
|
||||||
rules={[
|
</LayoutFormRow>
|
||||||
{
|
);
|
||||||
required: true
|
})}
|
||||||
//message: t("general.validation.required"),
|
</Space>
|
||||||
}
|
)}
|
||||||
]}
|
|
||||||
>
|
|
||||||
<ColorPicker />
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</LayoutFormRow>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</Space>
|
|
||||||
<Form.Item style={{ marginTop: 8 }}>
|
|
||||||
<Button
|
|
||||||
type="dashed"
|
|
||||||
onClick={() => {
|
|
||||||
add({
|
|
||||||
color: { ...DEFAULT_TRANSLUCENT_CARD_COLOR }
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
|
||||||
{t("general.actions.add")}
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</LayoutFormRow>
|
||||||
}}
|
);
|
||||||
</Form.List>
|
}}
|
||||||
</LayoutFormRow>
|
</Form.List>
|
||||||
)}
|
)}
|
||||||
</SelectorDiv>
|
</SelectorDiv>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
import { HasFeatureAccess } from "../feature-wrapper/feature-wrapper.component";
|
||||||
import ColorpickerFormItemComponent from "../form-items-formatted/colorpicker-form-item.component";
|
import ColorpickerFormItemComponent from "../form-items-formatted/colorpicker-form-item.component";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
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 LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import { ColorPicker } from "./shop-info.rostatus.component";
|
import { ColorPicker } from "./shop-info.rostatus.component";
|
||||||
import {
|
import {
|
||||||
@@ -227,195 +228,74 @@ export function ShopInfoSchedulingComponent({ form, bodyshop }) {
|
|||||||
))}
|
))}
|
||||||
</Space>
|
</Space>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow header={t("bodyshop.labels.apptcolors")} id="apptcolors">
|
<Form.List name={["appt_colors"]}>
|
||||||
<Form.List name={["appt_colors"]}>
|
{(fields, { add, remove, move }) => {
|
||||||
{(fields, { add, remove, move }) => {
|
return (
|
||||||
return (
|
<LayoutFormRow
|
||||||
|
header={t("bodyshop.labels.apptcolors")}
|
||||||
|
id="apptcolors"
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-appointment-color"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add({
|
||||||
|
color: {
|
||||||
|
...DEFAULT_TRANSLUCENT_PICKER_COLOR,
|
||||||
|
rgb: { ...DEFAULT_TRANSLUCENT_PICKER_COLOR.rgb }
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("bodyshop.actions.addapptcolor")}
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
{fields.map((field, index) => {
|
{fields.length === 0 ? (
|
||||||
const appointmentColor =
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.addapptcolor")} />
|
||||||
appointmentColors[field.name] || form.getFieldValue(["appt_colors", field.name]) || {};
|
) : (
|
||||||
const appointmentColorSurfaceStyles = getTintedCardSurfaceStyles(appointmentColor.color);
|
fields.map((field, index) => {
|
||||||
|
const appointmentColor =
|
||||||
return (
|
appointmentColors[field.name] || form.getFieldValue(["appt_colors", field.name]) || {};
|
||||||
<Form.Item key={field.key}>
|
const appointmentColorSurfaceStyles = getTintedCardSurfaceStyles(appointmentColor.color);
|
||||||
<LayoutFormRow
|
|
||||||
noDivider
|
|
||||||
title={
|
|
||||||
<div style={{ minWidth: 180, maxWidth: "100%" }}>
|
|
||||||
<Form.Item
|
|
||||||
noStyle
|
|
||||||
key={`${index}aptcolorlabel`}
|
|
||||||
name={[field.name, "label"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
size="small"
|
|
||||||
placeholder={t("bodyshop.fields.appt_colors.label")}
|
|
||||||
style={SECTION_TITLE_INPUT_STYLE}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
extra={
|
|
||||||
<Space align="center" size="small">
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<DeleteFilled />}
|
|
||||||
onClick={() => {
|
|
||||||
remove(field.name);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormListMoveArrows
|
|
||||||
move={move}
|
|
||||||
index={index}
|
|
||||||
total={fields.length}
|
|
||||||
orientation="horizontal"
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
{...appointmentColorSurfaceStyles}
|
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
key={`${index}aptcolorcolor`}
|
|
||||||
name={[field.name, "color"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<ColorpickerFormItemComponent styles={APPOINTMENT_COLOR_PICKER_STYLES} />
|
|
||||||
</Form.Item>
|
|
||||||
</LayoutFormRow>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<Form.Item>
|
|
||||||
<Button
|
|
||||||
type="dashed"
|
|
||||||
onClick={() => {
|
|
||||||
add({
|
|
||||||
color: {
|
|
||||||
...DEFAULT_TRANSLUCENT_PICKER_COLOR,
|
|
||||||
rgb: { ...DEFAULT_TRANSLUCENT_PICKER_COLOR.rgb }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
|
||||||
{t("bodyshop.actions.addapptcolor")}
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
</Form.List>
|
|
||||||
</LayoutFormRow>
|
|
||||||
{HasFeatureAccess({ featureName: "smartscheduling", bodyshop }) && (
|
|
||||||
<LayoutFormRow header={t("bodyshop.labels.ssbuckets")} id="ssbuckets">
|
|
||||||
<Form.List name={["ssbuckets"]}>
|
|
||||||
{(fields, { add, remove, move }) => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{fields.map((field, index) => {
|
|
||||||
const schedulingBucket =
|
|
||||||
schedulingBuckets[field.name] || form.getFieldValue(["ssbuckets", field.name]) || {};
|
|
||||||
const schedulingBucketSurfaceStyles = getTintedCardSurfaceStyles(schedulingBucket.color);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form.Item key={field.key}>
|
<Form.Item key={field.key}>
|
||||||
<LayoutFormRow
|
<LayoutFormRow
|
||||||
noDivider
|
noDivider
|
||||||
title={
|
title={
|
||||||
<div style={SECTION_TITLE_INPUT_ROW_STYLE}>
|
<div style={{ minWidth: 180, maxWidth: "100%" }}>
|
||||||
<div style={SECTION_TITLE_INPUT_GROUP_STYLE}>
|
<Form.Item
|
||||||
<div style={SECTION_TITLE_INPUT_LABEL_STYLE}>{t("bodyshop.fields.ssbuckets.id")}</div>
|
noStyle
|
||||||
<Form.Item
|
key={`${index}aptcolorlabel`}
|
||||||
noStyle
|
name={[field.name, "label"]}
|
||||||
key={`${index}id`}
|
rules={[
|
||||||
name={[field.name, "id"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
size="small"
|
|
||||||
placeholder={t("bodyshop.fields.ssbuckets.id")}
|
|
||||||
style={{
|
|
||||||
...SECTION_TITLE_INPUT_STYLE,
|
|
||||||
width: 72
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
...SECTION_TITLE_INPUT_GROUP_STYLE,
|
|
||||||
flex: 1,
|
|
||||||
minWidth: 0
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div style={SECTION_TITLE_INPUT_LABEL_STYLE}>
|
<Input
|
||||||
{t("bodyshop.fields.ssbuckets.label")}
|
size="small"
|
||||||
</div>
|
placeholder={t("bodyshop.fields.appt_colors.label")}
|
||||||
<Form.Item
|
style={SECTION_TITLE_INPUT_STYLE}
|
||||||
noStyle
|
/>
|
||||||
key={`${index}label`}
|
</Form.Item>
|
||||||
name={[field.name, "label"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input
|
|
||||||
size="small"
|
|
||||||
placeholder={t("bodyshop.fields.ssbuckets.label")}
|
|
||||||
style={{
|
|
||||||
...SECTION_TITLE_INPUT_STYLE,
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
extra={
|
extra={
|
||||||
<Space align="center" size="small">
|
<Space align="center" size="small">
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
|
danger
|
||||||
icon={<DeleteFilled />}
|
icon={<DeleteFilled />}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
remove(field.name);
|
remove(field.name);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Tooltip title={t("bodyshop.tooltips.reset-color")}>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<ReloadOutlined />}
|
|
||||||
onClick={() => {
|
|
||||||
form.setFieldValue(["ssbuckets", field.name, "color"]);
|
|
||||||
|
|
||||||
form.setFields([
|
|
||||||
{
|
|
||||||
name: ["ssbuckets", field.name, "color"],
|
|
||||||
touched: true
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Tooltip>
|
|
||||||
<FormListMoveArrows
|
<FormListMoveArrows
|
||||||
move={move}
|
move={move}
|
||||||
index={index}
|
index={index}
|
||||||
@@ -424,74 +304,213 @@ export function ShopInfoSchedulingComponent({ form, bodyshop }) {
|
|||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
{...schedulingBucketSurfaceStyles}
|
{...appointmentColorSurfaceStyles}
|
||||||
>
|
>
|
||||||
<div className="shop-info-scheduling__bucket-card-body">
|
<Form.Item
|
||||||
<div className="shop-info-scheduling__bucket-card-fields">
|
key={`${index}aptcolorcolor`}
|
||||||
<Form.Item
|
name={[field.name, "color"]}
|
||||||
label={t("bodyshop.fields.ssbuckets.gte")}
|
rules={[
|
||||||
key={`${index}gte`}
|
{
|
||||||
name={[field.name, "gte"]}
|
required: true
|
||||||
rules={[
|
//message: t("general.validation.required"),
|
||||||
{
|
}
|
||||||
required: true
|
]}
|
||||||
//message: t("general.validation.required"),
|
>
|
||||||
}
|
<ColorpickerFormItemComponent styles={APPOINTMENT_COLOR_PICKER_STYLES} />
|
||||||
]}
|
</Form.Item>
|
||||||
>
|
|
||||||
<InputNumber />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t("bodyshop.fields.ssbuckets.lt")}
|
|
||||||
key={`${index}lt`}
|
|
||||||
name={[field.name, "lt"]}
|
|
||||||
>
|
|
||||||
<InputNumber />
|
|
||||||
</Form.Item>
|
|
||||||
|
|
||||||
<Form.Item
|
|
||||||
label={t("bodyshop.fields.ssbuckets.target")}
|
|
||||||
key={`${index}target`}
|
|
||||||
name={[field.name, "target"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<InputNumber />
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<div className="shop-info-scheduling__bucket-card-color">
|
|
||||||
<Form.Item key={`${index}color`} name={[field.name, "color"]}>
|
|
||||||
<ColorPicker styles={SCHEDULING_BUCKET_COLOR_PICKER_STYLES} />
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
})}
|
})
|
||||||
<Form.Item>
|
)}
|
||||||
<Button
|
</div>
|
||||||
type="dashed"
|
</LayoutFormRow>
|
||||||
onClick={() => {
|
);
|
||||||
add({
|
}}
|
||||||
color: { ...DEFAULT_TRANSLUCENT_CARD_COLOR }
|
</Form.List>
|
||||||
});
|
{HasFeatureAccess({ featureName: "smartscheduling", bodyshop }) && (
|
||||||
}}
|
<Form.List name={["ssbuckets"]}>
|
||||||
style={{ width: "100%" }}
|
{(fields, { add, remove, move }) => {
|
||||||
>
|
return (
|
||||||
{t("bodyshop.actions.addbucket")}
|
<LayoutFormRow
|
||||||
</Button>
|
header={t("bodyshop.labels.ssbuckets")}
|
||||||
</Form.Item>
|
id="ssbuckets"
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-job-size-definition"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add({
|
||||||
|
color: { ...DEFAULT_TRANSLUCENT_CARD_COLOR }
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("bodyshop.actions.addbucket")}
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{fields.length === 0 ? (
|
||||||
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.addbucket")} />
|
||||||
|
) : (
|
||||||
|
fields.map((field, index) => {
|
||||||
|
const schedulingBucket =
|
||||||
|
schedulingBuckets[field.name] || form.getFieldValue(["ssbuckets", field.name]) || {};
|
||||||
|
const schedulingBucketSurfaceStyles = getTintedCardSurfaceStyles(schedulingBucket.color);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Form.Item key={field.key}>
|
||||||
|
<LayoutFormRow
|
||||||
|
noDivider
|
||||||
|
title={
|
||||||
|
<div style={SECTION_TITLE_INPUT_ROW_STYLE}>
|
||||||
|
<div style={SECTION_TITLE_INPUT_GROUP_STYLE}>
|
||||||
|
<div style={SECTION_TITLE_INPUT_LABEL_STYLE}>{t("bodyshop.fields.ssbuckets.id")}</div>
|
||||||
|
<Form.Item
|
||||||
|
noStyle
|
||||||
|
key={`${index}id`}
|
||||||
|
name={[field.name, "id"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
size="small"
|
||||||
|
placeholder={t("bodyshop.fields.ssbuckets.id")}
|
||||||
|
style={{
|
||||||
|
...SECTION_TITLE_INPUT_STYLE,
|
||||||
|
width: 72
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
...SECTION_TITLE_INPUT_GROUP_STYLE,
|
||||||
|
flex: 1,
|
||||||
|
minWidth: 0
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={SECTION_TITLE_INPUT_LABEL_STYLE}>
|
||||||
|
{t("bodyshop.fields.ssbuckets.label")}
|
||||||
|
</div>
|
||||||
|
<Form.Item
|
||||||
|
noStyle
|
||||||
|
key={`${index}label`}
|
||||||
|
name={[field.name, "label"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
size="small"
|
||||||
|
placeholder={t("bodyshop.fields.ssbuckets.label")}
|
||||||
|
style={{
|
||||||
|
...SECTION_TITLE_INPUT_STYLE,
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
extra={
|
||||||
|
<Space align="center" size="small">
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
danger
|
||||||
|
icon={<DeleteFilled />}
|
||||||
|
onClick={() => {
|
||||||
|
remove(field.name);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Tooltip title={t("bodyshop.tooltips.reset-color")}>
|
||||||
|
<Button
|
||||||
|
type="text"
|
||||||
|
icon={<ReloadOutlined />}
|
||||||
|
onClick={() => {
|
||||||
|
form.setFieldValue(["ssbuckets", field.name, "color"]);
|
||||||
|
|
||||||
|
form.setFields([
|
||||||
|
{
|
||||||
|
name: ["ssbuckets", field.name, "color"],
|
||||||
|
touched: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<FormListMoveArrows
|
||||||
|
move={move}
|
||||||
|
index={index}
|
||||||
|
total={fields.length}
|
||||||
|
orientation="horizontal"
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
{...schedulingBucketSurfaceStyles}
|
||||||
|
>
|
||||||
|
<div className="shop-info-scheduling__bucket-card-body">
|
||||||
|
<div className="shop-info-scheduling__bucket-card-fields">
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.ssbuckets.gte")}
|
||||||
|
key={`${index}gte`}
|
||||||
|
name={[field.name, "gte"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.ssbuckets.lt")}
|
||||||
|
key={`${index}lt`}
|
||||||
|
name={[field.name, "lt"]}
|
||||||
|
>
|
||||||
|
<InputNumber />
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.ssbuckets.target")}
|
||||||
|
key={`${index}target`}
|
||||||
|
name={[field.name, "target"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
<div className="shop-info-scheduling__bucket-card-color">
|
||||||
|
<Form.Item key={`${index}color`} name={[field.name, "color"]}>
|
||||||
|
<ColorPicker styles={SCHEDULING_BUCKET_COLOR_PICKER_STYLES} />
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</LayoutFormRow>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
</LayoutFormRow>
|
||||||
}}
|
);
|
||||||
</Form.List>
|
}}
|
||||||
</LayoutFormRow>
|
</Form.List>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button, Form, Input, Select, Space } from "antd";
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { TemplateList } from "../../utils/TemplateConstants";
|
import { TemplateList } from "../../utils/TemplateConstants";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
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 LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import {
|
import {
|
||||||
INLINE_TITLE_GROUP_STYLE,
|
INLINE_TITLE_GROUP_STYLE,
|
||||||
@@ -23,133 +24,131 @@ export default function ShopInfoSpeedPrint() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LayoutFormRow header={t("bodyshop.labels.speedprint_configurations")}>
|
<Form.List name={["speedprint"]}>
|
||||||
<Form.List name={["speedprint"]}>
|
{(fields, { add, remove, move }) => {
|
||||||
{(fields, { add, remove, move }) => {
|
return (
|
||||||
return (
|
<LayoutFormRow
|
||||||
|
header={t("bodyshop.labels.speedprint_configurations")}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-speedprint"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("bodyshop.actions.addspeedprint")}
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
{fields.map((field, index) => {
|
{fields.length === 0 ? (
|
||||||
return (
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.addspeedprint")} />
|
||||||
<Form.Item key={field.key} style={{ padding: 0, margin: 2 }}>
|
) : (
|
||||||
<LayoutFormRow
|
fields.map((field, index) => {
|
||||||
noDivider
|
return (
|
||||||
title={
|
<Form.Item key={field.key} style={{ padding: 0, margin: 2 }}>
|
||||||
<div style={INLINE_TITLE_ROW_STYLE}>
|
<LayoutFormRow
|
||||||
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
noDivider
|
||||||
<div
|
title={
|
||||||
style={{
|
<div style={INLINE_TITLE_ROW_STYLE}>
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
||||||
flex: "0 1 180px"
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
||||||
}}
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("bodyshop.fields.speedprint.id")}</div>
|
||||||
>
|
<Form.Item
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("bodyshop.fields.speedprint.id")}</div>
|
noStyle
|
||||||
<Form.Item
|
name={[field.name, "id"]}
|
||||||
noStyle
|
rules={[
|
||||||
name={[field.name, "id"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
//message: t("general.validation.required"),
|
||||||
required: true
|
}
|
||||||
//message: t("general.validation.required"),
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<Input
|
||||||
>
|
size="small"
|
||||||
<Input
|
placeholder={t("bodyshop.fields.speedprint.id")}
|
||||||
size="small"
|
style={{
|
||||||
placeholder={t("bodyshop.fields.speedprint.id")}
|
...INLINE_TITLE_INPUT_STYLE,
|
||||||
style={{
|
width: "100%"
|
||||||
...INLINE_TITLE_INPUT_STYLE,
|
}}
|
||||||
width: "100%"
|
/>
|
||||||
}}
|
</Form.Item>
|
||||||
/>
|
</div>
|
||||||
</Form.Item>
|
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
||||||
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
||||||
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("bodyshop.fields.speedprint.label")}</div>
|
||||||
|
<Form.Item
|
||||||
|
noStyle
|
||||||
|
name={[field.name, "label"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input
|
||||||
|
size="small"
|
||||||
|
placeholder={t("bodyshop.fields.speedprint.label")}
|
||||||
|
style={{
|
||||||
|
...INLINE_TITLE_INPUT_STYLE,
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
}
|
||||||
<div
|
wrapTitle
|
||||||
style={{
|
extra={
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<Space align="center" size="small">
|
||||||
flex: "1 1 280px"
|
<Button
|
||||||
}}
|
type="text"
|
||||||
>
|
danger
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("bodyshop.fields.speedprint.label")}</div>
|
icon={<DeleteFilled />}
|
||||||
<Form.Item
|
onClick={() => {
|
||||||
noStyle
|
remove(field.name);
|
||||||
name={[field.name, "label"]}
|
}}
|
||||||
rules={[
|
/>
|
||||||
{
|
<FormListMoveArrows
|
||||||
required: true
|
move={move}
|
||||||
//message: t("general.validation.required"),
|
index={index}
|
||||||
}
|
total={fields.length}
|
||||||
]}
|
orientation="horizontal"
|
||||||
>
|
/>
|
||||||
<Input
|
</Space>
|
||||||
size="small"
|
}
|
||||||
placeholder={t("bodyshop.fields.speedprint.label")}
|
|
||||||
style={{
|
|
||||||
...INLINE_TITLE_INPUT_STYLE,
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
wrapTitle
|
|
||||||
extra={
|
|
||||||
<Space align="center" size="small">
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<DeleteFilled />}
|
|
||||||
onClick={() => {
|
|
||||||
remove(field.name);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormListMoveArrows
|
|
||||||
move={move}
|
|
||||||
index={index}
|
|
||||||
total={fields.length}
|
|
||||||
orientation="horizontal"
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
name={[field.name, "templates"]}
|
|
||||||
label={t("bodyshop.fields.speedprint.templates")}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true,
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
type: "array"
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
<Select
|
<Form.Item
|
||||||
mode="multiple"
|
name={[field.name, "templates"]}
|
||||||
options={Object.keys(TemplateListGenerated).map((key) => ({
|
label={t("bodyshop.fields.speedprint.templates")}
|
||||||
value: TemplateListGenerated[key].key,
|
rules={[
|
||||||
label: TemplateListGenerated[key].title
|
{
|
||||||
}))}
|
required: true,
|
||||||
/>
|
//message: t("general.validation.required"),
|
||||||
</Form.Item>
|
type: "array"
|
||||||
</LayoutFormRow>
|
}
|
||||||
</Form.Item>
|
]}
|
||||||
);
|
>
|
||||||
})}
|
<Select
|
||||||
<Form.Item>
|
mode="multiple"
|
||||||
<Button
|
options={Object.keys(TemplateListGenerated).map((key) => ({
|
||||||
type="dashed"
|
value: TemplateListGenerated[key].key,
|
||||||
onClick={() => {
|
label: TemplateListGenerated[key].title
|
||||||
add();
|
}))}
|
||||||
}}
|
/>
|
||||||
style={{ width: "100%" }}
|
</Form.Item>
|
||||||
>
|
</LayoutFormRow>
|
||||||
{t("bodyshop.actions.addspeedprint")}
|
</Form.Item>
|
||||||
</Button>
|
);
|
||||||
</Form.Item>
|
})
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
</LayoutFormRow>
|
||||||
}}
|
);
|
||||||
</Form.List>
|
}}
|
||||||
</LayoutFormRow>
|
</Form.List>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import { Button, Checkbox, Col, Form, Input, InputNumber, Row, Select, Space, Sw
|
|||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
||||||
import { getFormListItemTitle } from "../form-list-move-arrows/form-list-item-title.utils";
|
import { getFormListItemTitle } from "../form-list-move-arrows/form-list-item-title.utils";
|
||||||
|
import ConfigListEmptyState from "../layout-form-row/config-list-empty-state.component.jsx";
|
||||||
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
|
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
@@ -78,208 +79,216 @@ export function ShopInfoTaskPresets({ bodyshop }) {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
|
|
||||||
<LayoutFormRow header={t("bodyshop.labels.md_tasks_presets")}>
|
<Form.List
|
||||||
<Form.List
|
name={["md_tasks_presets", "presets"]}
|
||||||
name={["md_tasks_presets", "presets"]}
|
rules={[
|
||||||
rules={[
|
{
|
||||||
{
|
validator: async (_, presets) => {
|
||||||
validator: async (_, presets) => {
|
const allocationErrors = getTaskPresetAllocationErrors(presets, t);
|
||||||
const allocationErrors = getTaskPresetAllocationErrors(presets, t);
|
|
||||||
|
|
||||||
if (allocationErrors.length > 0) {
|
if (allocationErrors.length > 0) {
|
||||||
throw new Error(allocationErrors.join(" "));
|
throw new Error(allocationErrors.join(" "));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]}
|
}
|
||||||
>
|
]}
|
||||||
{(fields, { add, remove, move }, { errors }) => {
|
>
|
||||||
return (
|
{(fields, { add, remove, move }, { errors }) => {
|
||||||
|
return (
|
||||||
|
<LayoutFormRow
|
||||||
|
header={t("bodyshop.labels.md_tasks_presets")}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-task-preset"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("bodyshop.actions.add_task_preset")}
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
{fields.map((field, index) => {
|
{fields.length === 0 ? (
|
||||||
const taskPreset = taskPresets[field.name] || {};
|
<ConfigListEmptyState actionLabel={t("bodyshop.actions.add_task_preset")} />
|
||||||
|
) : (
|
||||||
|
fields.map((field, index) => {
|
||||||
|
const taskPreset = taskPresets[field.name] || {};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form.Item key={field.key}>
|
<Form.Item key={field.key}>
|
||||||
<LayoutFormRow
|
<LayoutFormRow
|
||||||
noDivider
|
noDivider
|
||||||
title={getFormListItemTitle(
|
title={getFormListItemTitle(
|
||||||
t("bodyshop.fields.md_tasks_presets.name"),
|
t("bodyshop.fields.md_tasks_presets.name"),
|
||||||
index,
|
index,
|
||||||
taskPreset.name,
|
taskPreset.name,
|
||||||
taskPreset.memo
|
taskPreset.memo
|
||||||
)}
|
)}
|
||||||
extra={
|
extra={
|
||||||
<Space align="center" size="small">
|
<Space align="center" size="small">
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
type="text"
|
||||||
icon={<DeleteFilled />}
|
danger
|
||||||
onClick={() => {
|
icon={<DeleteFilled />}
|
||||||
remove(field.name);
|
onClick={() => {
|
||||||
}}
|
remove(field.name);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormListMoveArrows
|
||||||
|
move={move}
|
||||||
|
index={index}
|
||||||
|
total={fields.length}
|
||||||
|
orientation="horizontal"
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.md_tasks_presets.name")}
|
||||||
|
key={`${index}name`}
|
||||||
|
name={[field.name, "name"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
span={12}
|
||||||
|
label={t("bodyshop.fields.md_tasks_presets.hourstype")}
|
||||||
|
key={`${index}hourstype`}
|
||||||
|
name={[field.name, "hourstype"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Checkbox.Group>
|
||||||
|
<Row>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAA" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAA")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAB" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAB")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAD" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAD")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAE" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAE")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAF" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAF")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAG" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAG")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAM" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAM")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAR" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAR")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAS" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAS")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LAU" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LAU")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LA1" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LA1")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LA2" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LA2")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LA3" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LA3")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Checkbox value="LA4" style={{ lineHeight: "32px" }}>
|
||||||
|
{t("joblines.fields.lbr_types.LA4")}
|
||||||
|
</Checkbox>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Checkbox.Group>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.md_tasks_presets.percent")}
|
||||||
|
key={`${index}percent`}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
//message: t("general.validation.required"),
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
name={[field.name, "percent"]}
|
||||||
|
>
|
||||||
|
<InputNumber min={0} max={100} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.md_tasks_presets.memo")}
|
||||||
|
key={`${index}memo`}
|
||||||
|
name={[field.name, "memo"]}
|
||||||
|
>
|
||||||
|
<Input />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item
|
||||||
|
label={t("bodyshop.fields.md_tasks_presets.nextstatus")}
|
||||||
|
key={`${index}nextstatus`}
|
||||||
|
name={[field.name, "nextstatus"]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
options={bodyshop.md_ro_statuses.production_statuses.map((o) => ({
|
||||||
|
value: o,
|
||||||
|
label: o
|
||||||
|
}))}
|
||||||
/>
|
/>
|
||||||
<FormListMoveArrows
|
</Form.Item>
|
||||||
move={move}
|
</LayoutFormRow>
|
||||||
index={index}
|
</Form.Item>
|
||||||
total={fields.length}
|
);
|
||||||
orientation="horizontal"
|
})
|
||||||
/>
|
)}
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
label={t("bodyshop.fields.md_tasks_presets.name")}
|
|
||||||
key={`${index}name`}
|
|
||||||
name={[field.name, "name"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
span={12}
|
|
||||||
label={t("bodyshop.fields.md_tasks_presets.hourstype")}
|
|
||||||
key={`${index}hourstype`}
|
|
||||||
name={[field.name, "hourstype"]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Checkbox.Group>
|
|
||||||
<Row>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAA" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAA")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAB" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAB")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAD" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAD")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAE" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAE")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAF" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAF")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAG" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAG")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAM" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAM")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAR" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAR")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAS" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAS")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LAU" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LAU")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LA1" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LA1")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LA2" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LA2")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LA3" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LA3")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
<Col span={4}>
|
|
||||||
<Checkbox value="LA4" style={{ lineHeight: "32px" }}>
|
|
||||||
{t("joblines.fields.lbr_types.LA4")}
|
|
||||||
</Checkbox>
|
|
||||||
</Col>
|
|
||||||
</Row>
|
|
||||||
</Checkbox.Group>
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("bodyshop.fields.md_tasks_presets.percent")}
|
|
||||||
key={`${index}percent`}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
//message: t("general.validation.required"),
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
name={[field.name, "percent"]}
|
|
||||||
>
|
|
||||||
<InputNumber min={0} max={100} />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("bodyshop.fields.md_tasks_presets.memo")}
|
|
||||||
key={`${index}memo`}
|
|
||||||
name={[field.name, "memo"]}
|
|
||||||
>
|
|
||||||
<Input />
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label={t("bodyshop.fields.md_tasks_presets.nextstatus")}
|
|
||||||
key={`${index}nextstatus`}
|
|
||||||
name={[field.name, "nextstatus"]}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
options={bodyshop.md_ro_statuses.production_statuses.map((o) => ({
|
|
||||||
value: o,
|
|
||||||
label: o
|
|
||||||
}))}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</LayoutFormRow>
|
|
||||||
</Form.Item>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
<Form.ErrorList errors={errors} />
|
<Form.ErrorList errors={errors} />
|
||||||
<Form.Item>
|
|
||||||
<Button
|
|
||||||
type="dashed"
|
|
||||||
onClick={() => {
|
|
||||||
add();
|
|
||||||
}}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
|
||||||
{t("bodyshop.actions.add_task_preset")}
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</LayoutFormRow>
|
||||||
}}
|
);
|
||||||
</Form.List>
|
}}
|
||||||
</LayoutFormRow>
|
</Form.List>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
|||||||
import AlertComponent from "../alert/alert.component";
|
import AlertComponent from "../alert/alert.component";
|
||||||
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
import CurrencyInput from "../form-items-formatted/currency-form-item.component";
|
||||||
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
|
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 LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import {
|
import {
|
||||||
INLINE_TITLE_GROUP_STYLE,
|
INLINE_TITLE_GROUP_STYLE,
|
||||||
@@ -20,7 +21,8 @@ import {
|
|||||||
INLINE_TITLE_INPUT_STYLE,
|
INLINE_TITLE_INPUT_STYLE,
|
||||||
INLINE_TITLE_LABEL_STYLE,
|
INLINE_TITLE_LABEL_STYLE,
|
||||||
INLINE_TITLE_ROW_STYLE,
|
INLINE_TITLE_ROW_STYLE,
|
||||||
INLINE_TITLE_SEPARATOR_STYLE
|
INLINE_TITLE_SEPARATOR_STYLE,
|
||||||
|
INLINE_TITLE_SWITCH_GROUP_STYLE
|
||||||
} from "../layout-form-row/inline-form-row-title.utils.js";
|
} from "../layout-form-row/inline-form-row-title.utils.js";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
@@ -209,8 +211,8 @@ export function ShopEmployeeTeamsFormComponent({ bodyshop }) {
|
|||||||
<Card
|
<Card
|
||||||
title={isTeamHydrating ? undefined : teamCardTitle}
|
title={isTeamHydrating ? undefined : teamCardTitle}
|
||||||
extra={
|
extra={
|
||||||
<Button type="primary" onClick={() => form.submit()} disabled={isTeamHydrating}>
|
<Button type="primary" onClick={() => form.submit()} disabled={isTeamHydrating} style={{ minWidth: 190 }}>
|
||||||
{t("general.actions.save")}
|
{t("employee_teams.actions.save_team")}
|
||||||
</Button>
|
</Button>
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
@@ -239,8 +241,7 @@ export function ShopEmployeeTeamsFormComponent({ bodyshop }) {
|
|||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
...INLINE_TITLE_SWITCH_GROUP_STYLE,
|
||||||
flex: "0 0 auto",
|
|
||||||
marginLeft: "auto"
|
marginLeft: "auto"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -277,188 +278,181 @@ export function ShopEmployeeTeamsFormComponent({ bodyshop }) {
|
|||||||
<InputNumber min={0} precision={1} suffix="%" />
|
<InputNumber min={0} precision={1} suffix="%" />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</LayoutFormRow>
|
</LayoutFormRow>
|
||||||
<LayoutFormRow title={t("employee_teams.labels.members")}>
|
<Form.List name={["employee_team_members"]}>
|
||||||
<Form.List name={["employee_team_members"]}>
|
{(fields, { add, remove, move }) => {
|
||||||
{(fields, { add, remove, move }) => {
|
return (
|
||||||
return (
|
<LayoutFormRow
|
||||||
|
title={t("employee_teams.labels.members")}
|
||||||
|
actions={[
|
||||||
|
<Button
|
||||||
|
key="add-team-member"
|
||||||
|
type="primary"
|
||||||
|
block
|
||||||
|
onClick={() => {
|
||||||
|
add({
|
||||||
|
percentage: 0,
|
||||||
|
payout_method: "hourly",
|
||||||
|
labor_rates: {},
|
||||||
|
commission_rates: {}
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("employee_teams.actions.newmember")}
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
<div>
|
<div>
|
||||||
{fields.map((field, index) => {
|
{fields.length === 0 ? (
|
||||||
return (
|
<ConfigListEmptyState actionLabel={t("employee_teams.actions.newmember")} />
|
||||||
<Form.Item key={field.key} style={{ padding: 0, margin: 2 }}>
|
) : (
|
||||||
<Form.Item name={[field.name, "id"]} hidden>
|
fields.map((field, index) => {
|
||||||
<Input type="hidden" />
|
return (
|
||||||
</Form.Item>
|
<Form.Item key={field.key} style={{ padding: 0, margin: 2 }}>
|
||||||
<LayoutFormRow
|
<Form.Item name={[field.name, "id"]} hidden>
|
||||||
grow
|
<Input type="hidden" />
|
||||||
title={
|
</Form.Item>
|
||||||
<div style={INLINE_TITLE_ROW_STYLE}>
|
<LayoutFormRow
|
||||||
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
grow
|
||||||
<div
|
title={
|
||||||
style={{
|
<div style={INLINE_TITLE_ROW_STYLE}>
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<HolderOutlined style={INLINE_TITLE_HANDLE_STYLE} />
|
||||||
flex: "1 1 320px"
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
||||||
}}
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employee_teams.fields.employeeid")}</div>
|
||||||
>
|
<Form.Item
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employee_teams.fields.employeeid")}</div>
|
noStyle
|
||||||
<Form.Item
|
name={[field.name, "employeeid"]}
|
||||||
noStyle
|
rules={[
|
||||||
name={[field.name, "employeeid"]}
|
{
|
||||||
rules={[
|
required: true
|
||||||
{
|
}
|
||||||
required: true
|
]}
|
||||||
}
|
>
|
||||||
]}
|
<EmployeeSearchSelectComponent options={bodyshop.employees} />
|
||||||
>
|
</Form.Item>
|
||||||
<EmployeeSearchSelectComponent options={bodyshop.employees} />
|
</div>
|
||||||
</Form.Item>
|
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
||||||
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
||||||
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employee_teams.fields.allocation")}</div>
|
||||||
|
<Form.Item
|
||||||
|
noStyle
|
||||||
|
name={[field.name, "percentage"]}
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<InputNumber
|
||||||
|
min={0}
|
||||||
|
max={100}
|
||||||
|
precision={2}
|
||||||
|
size="small"
|
||||||
|
aria-label={t("employee_teams.fields.allocation")}
|
||||||
|
suffix="%"
|
||||||
|
style={{
|
||||||
|
...INLINE_TITLE_INPUT_STYLE,
|
||||||
|
width: "100%"
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
|
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
||||||
|
<div style={INLINE_TITLE_GROUP_STYLE}>
|
||||||
|
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employee_teams.fields.payout_method")}</div>
|
||||||
|
<Form.Item
|
||||||
|
noStyle
|
||||||
|
key={`${index}-payout-method`}
|
||||||
|
name={[field.name, "payout_method"]}
|
||||||
|
initialValue="hourly"
|
||||||
|
rules={[
|
||||||
|
{
|
||||||
|
required: true
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Select
|
||||||
|
aria-label={t("employee_teams.fields.payout_method")}
|
||||||
|
size="small"
|
||||||
|
options={payoutMethodOptions}
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
styles={{
|
||||||
|
selector: INLINE_TITLE_INPUT_STYLE
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
}
|
||||||
<div
|
wrapTitle
|
||||||
style={{
|
extra={
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
<Space align="center" size="small">
|
||||||
flex: "0 1 170px"
|
<Button
|
||||||
}}
|
type="text"
|
||||||
|
danger
|
||||||
|
icon={<DeleteFilled />}
|
||||||
|
onClick={() => {
|
||||||
|
remove(field.name);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<FormListMoveArrows
|
||||||
|
move={move}
|
||||||
|
index={index}
|
||||||
|
total={fields.length}
|
||||||
|
orientation="horizontal"
|
||||||
|
/>
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<Form.Item
|
||||||
|
noStyle
|
||||||
|
dependencies={[["employee_team_members", field.name, "payout_method"]]}
|
||||||
>
|
>
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employee_teams.fields.allocation")}</div>
|
{() => {
|
||||||
<Form.Item
|
const payoutMethod =
|
||||||
noStyle
|
form.getFieldValue(["employee_team_members", field.name, "payout_method"]) ||
|
||||||
name={[field.name, "percentage"]}
|
"hourly";
|
||||||
rules={[
|
const fieldName = payoutMethod === "commission" ? "commission_rates" : "labor_rates";
|
||||||
{
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<InputNumber
|
|
||||||
min={0}
|
|
||||||
max={100}
|
|
||||||
precision={2}
|
|
||||||
size="small"
|
|
||||||
aria-label={t("employee_teams.fields.allocation")}
|
|
||||||
suffix="%"
|
|
||||||
style={{
|
|
||||||
...INLINE_TITLE_INPUT_STYLE,
|
|
||||||
width: "100%"
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
<div aria-hidden style={INLINE_TITLE_SEPARATOR_STYLE} />
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
...INLINE_TITLE_GROUP_STYLE,
|
|
||||||
flex: "0 1 260px"
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div style={INLINE_TITLE_LABEL_STYLE}>{t("employee_teams.fields.payout_method")}</div>
|
|
||||||
<Form.Item
|
|
||||||
noStyle
|
|
||||||
key={`${index}-payout-method`}
|
|
||||||
name={[field.name, "payout_method"]}
|
|
||||||
initialValue="hourly"
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<Select
|
|
||||||
aria-label={t("employee_teams.fields.payout_method")}
|
|
||||||
size="small"
|
|
||||||
options={payoutMethodOptions}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
styles={{
|
|
||||||
selector: INLINE_TITLE_INPUT_STYLE
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
wrapTitle
|
|
||||||
extra={
|
|
||||||
<Space align="center" size="small">
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<DeleteFilled />}
|
|
||||||
onClick={() => {
|
|
||||||
remove(field.name);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<FormListMoveArrows
|
|
||||||
move={move}
|
|
||||||
index={index}
|
|
||||||
total={fields.length}
|
|
||||||
orientation="horizontal"
|
|
||||||
/>
|
|
||||||
</Space>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<div>
|
|
||||||
<Form.Item
|
|
||||||
noStyle
|
|
||||||
dependencies={[["employee_team_members", field.name, "payout_method"]]}
|
|
||||||
>
|
|
||||||
{() => {
|
|
||||||
const payoutMethod =
|
|
||||||
form.getFieldValue(["employee_team_members", field.name, "payout_method"]) ||
|
|
||||||
"hourly";
|
|
||||||
const fieldName = payoutMethod === "commission" ? "commission_rates" : "labor_rates";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Row gutter={[16, 0]}>
|
<Row gutter={[16, 0]}>
|
||||||
{LABOR_TYPES.map((laborType) => (
|
{LABOR_TYPES.map((laborType) => (
|
||||||
<Col
|
<Col
|
||||||
{...TEAM_MEMBER_RATE_FIELD_COLS}
|
{...TEAM_MEMBER_RATE_FIELD_COLS}
|
||||||
key={`${index}-${fieldName}-${laborType}`}
|
key={`${index}-${fieldName}-${laborType}`}
|
||||||
>
|
|
||||||
<Form.Item
|
|
||||||
label={t(`joblines.fields.lbr_types.${laborType}`)}
|
|
||||||
name={[field.name, fieldName, laborType]}
|
|
||||||
rules={[
|
|
||||||
{
|
|
||||||
required: true
|
|
||||||
}
|
|
||||||
]}
|
|
||||||
>
|
>
|
||||||
{payoutMethod === "commission" ? (
|
<Form.Item
|
||||||
<InputNumber min={0} max={100} precision={2} suffix="%" />
|
label={t(`joblines.fields.lbr_types.${laborType}`)}
|
||||||
) : (
|
name={[field.name, fieldName, laborType]}
|
||||||
<CurrencyInput prefix="$" />
|
rules={[
|
||||||
)}
|
{
|
||||||
</Form.Item>
|
required: true
|
||||||
</Col>
|
}
|
||||||
))}
|
]}
|
||||||
</Row>
|
>
|
||||||
);
|
{payoutMethod === "commission" ? (
|
||||||
}}
|
<InputNumber min={0} max={100} precision={2} suffix="%" />
|
||||||
</Form.Item>
|
) : (
|
||||||
</div>
|
<CurrencyInput prefix="$" />
|
||||||
</LayoutFormRow>
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
</Col>
|
||||||
})}
|
))}
|
||||||
<Form.Item>
|
</Row>
|
||||||
<Button
|
);
|
||||||
type="dashed"
|
}}
|
||||||
onClick={() => {
|
</Form.Item>
|
||||||
add({
|
</div>
|
||||||
percentage: 0,
|
</LayoutFormRow>
|
||||||
payout_method: "hourly",
|
</Form.Item>
|
||||||
labor_rates: {},
|
);
|
||||||
commission_rates: {}
|
})
|
||||||
});
|
)}
|
||||||
}}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
>
|
|
||||||
{t("employee_teams.actions.newmember")}
|
|
||||||
</Button>
|
|
||||||
</Form.Item>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
</LayoutFormRow>
|
||||||
}}
|
);
|
||||||
</Form.List>
|
}}
|
||||||
</LayoutFormRow>
|
</Form.List>
|
||||||
</Form>
|
</Form>
|
||||||
)}
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -42,9 +42,11 @@ vi.mock("react-i18next", () => ({
|
|||||||
"employee_teams.options.commission": "Commission",
|
"employee_teams.options.commission": "Commission",
|
||||||
"employee_teams.options.commission_percentage": "Commission",
|
"employee_teams.options.commission_percentage": "Commission",
|
||||||
"employee_teams.actions.newmember": "New Team Member",
|
"employee_teams.actions.newmember": "New Team Member",
|
||||||
|
"employee_teams.actions.save_team": "Save Employee Team",
|
||||||
"employee_teams.errors.minimum_one_member": "Add at least one team member.",
|
"employee_teams.errors.minimum_one_member": "Add at least one team member.",
|
||||||
"employee_teams.errors.duplicate_member": "Team members must be unique.",
|
"employee_teams.errors.duplicate_member": "Team members must be unique.",
|
||||||
"employee_teams.errors.allocation_total_exact": "Allocation must total exactly 100%.",
|
"employee_teams.errors.allocation_total_exact": "Allocation must total exactly 100%.",
|
||||||
|
"general.labels.click_to_begin": `Click ${values.action ?? ""} to begin`,
|
||||||
"general.actions.save": "Save",
|
"general.actions.save": "Save",
|
||||||
"employees.successes.save": "Saved"
|
"employees.successes.save": "Saved"
|
||||||
};
|
};
|
||||||
@@ -101,11 +103,12 @@ vi.mock("../form-items-formatted/currency-form-item.component", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
vi.mock("../layout-form-row/layout-form-row.component", () => ({
|
vi.mock("../layout-form-row/layout-form-row.component", () => ({
|
||||||
default: ({ title, extra, children }) => (
|
default: ({ title, extra, actions, children }) => (
|
||||||
<div>
|
<div>
|
||||||
{title}
|
{title}
|
||||||
{extra}
|
{extra}
|
||||||
{children}
|
{children}
|
||||||
|
{actions}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}));
|
}));
|
||||||
@@ -211,7 +214,7 @@ describe("ShopEmployeeTeamsFormComponent", () => {
|
|||||||
rate: 27.5
|
rate: 27.5
|
||||||
});
|
});
|
||||||
|
|
||||||
fireEvent.click(screen.getByRole("button", { name: "Save" }));
|
fireEvent.click(screen.getByRole("button", { name: "Save Employee Team" }));
|
||||||
|
|
||||||
await waitFor(() => {
|
await waitFor(() => {
|
||||||
expect(insertEmployeeTeamMock).toHaveBeenCalledWith({
|
expect(insertEmployeeTeamMock).toHaveBeenCalledWith({
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { Button } from "antd";
|
|||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
import { useLocation, useNavigate } from "react-router-dom";
|
import { useLocation, useNavigate } from "react-router-dom";
|
||||||
|
import ConfigListEmptyState from "../layout-form-row/config-list-empty-state.component.jsx";
|
||||||
|
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import ResponsiveTable from "../responsive-table/responsive-table.component";
|
import ResponsiveTable from "../responsive-table/responsive-table.component";
|
||||||
|
|
||||||
export default function ShopEmployeeTeamsListComponent({ loading, employee_teams }) {
|
export default function ShopEmployeeTeamsListComponent({ loading, employee_teams }) {
|
||||||
@@ -9,13 +11,28 @@ export default function ShopEmployeeTeamsListComponent({ loading, employee_teams
|
|||||||
const history = useNavigate();
|
const history = useNavigate();
|
||||||
const search = queryString.parse(useLocation().search);
|
const search = queryString.parse(useLocation().search);
|
||||||
|
|
||||||
|
const navigateToTeam = (employeeTeamId) => {
|
||||||
|
history({
|
||||||
|
search: queryString.stringify({
|
||||||
|
...search,
|
||||||
|
employeeTeamId
|
||||||
|
})
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const clearTeamSelection = () => {
|
||||||
|
const { employeeTeamId, ...nextSearch } = search;
|
||||||
|
void employeeTeamId;
|
||||||
|
history({
|
||||||
|
search: queryString.stringify(nextSearch)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleOnRowClick = (record) => {
|
const handleOnRowClick = (record) => {
|
||||||
if (record) {
|
if (record) {
|
||||||
search.employeeTeamId = record.id;
|
navigateToTeam(record.id);
|
||||||
history({ search: queryString.stringify(search) });
|
|
||||||
} else {
|
} else {
|
||||||
delete search.employeeTeamId;
|
clearTeamSelection();
|
||||||
history({ search: queryString.stringify(search) });
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const columns = [
|
const columns = [
|
||||||
@@ -27,43 +44,38 @@ export default function ShopEmployeeTeamsListComponent({ loading, employee_teams
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<LayoutFormRow
|
||||||
<ResponsiveTable
|
title={t("bodyshop.labels.employee_teams")}
|
||||||
title={() => {
|
actions={[
|
||||||
return (
|
<Button key="new-team" type="primary" block onClick={() => navigateToTeam("new")}>
|
||||||
<Button
|
{t("employee_teams.actions.new")}
|
||||||
type="primary"
|
</Button>
|
||||||
onClick={() => {
|
]}
|
||||||
search.employeeTeamId = "new";
|
>
|
||||||
history({ search: queryString.stringify(search) });
|
{employee_teams.length === 0 ? (
|
||||||
}}
|
<ConfigListEmptyState actionLabel={t("employee_teams.actions.new")} />
|
||||||
>
|
) : (
|
||||||
{t("employee_teams.actions.new")}
|
<ResponsiveTable
|
||||||
</Button>
|
loading={loading}
|
||||||
);
|
pagination={{ placement: "top" }}
|
||||||
}}
|
columns={columns}
|
||||||
loading={loading}
|
mobileColumnKeys={["name"]}
|
||||||
pagination={{ placement: "top" }}
|
rowKey="id"
|
||||||
columns={columns}
|
dataSource={employee_teams}
|
||||||
mobileColumnKeys={["name"]}
|
rowSelection={{
|
||||||
rowKey="id"
|
onSelect: (props) => navigateToTeam(props.id),
|
||||||
dataSource={employee_teams}
|
type: "radio",
|
||||||
rowSelection={{
|
selectedRowKeys: [search.employeeTeamId]
|
||||||
onSelect: (props) => {
|
}}
|
||||||
search.employeeTeamId = props.id;
|
onRow={(record) => {
|
||||||
history({ search: queryString.stringify(search) });
|
return {
|
||||||
},
|
onClick: () => {
|
||||||
type: "radio",
|
handleOnRowClick(record);
|
||||||
selectedRowKeys: [search.employeeTeamId]
|
}
|
||||||
}}
|
};
|
||||||
onRow={(record) => {
|
}}
|
||||||
return {
|
/>
|
||||||
onClick: () => {
|
)}
|
||||||
handleOnRowClick(record);
|
</LayoutFormRow>
|
||||||
}
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { createStructuredSelector } from "reselect";
|
|||||||
import { QUERY_SHOP_ASSOCIATIONS } from "../../graphql/user.queries";
|
import { QUERY_SHOP_ASSOCIATIONS } from "../../graphql/user.queries";
|
||||||
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 LayoutFormRow from "../layout-form-row/layout-form-row.component";
|
||||||
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
import RbacWrapper from "../rbac-wrapper/rbac-wrapper.component";
|
||||||
import ResponsiveTable from "../responsive-table/responsive-table.component";
|
import ResponsiveTable from "../responsive-table/responsive-table.component";
|
||||||
import ShopUsersAuthEdit from "../shop-users-auth-edit/shop-users-auth-edit.component";
|
import ShopUsersAuthEdit from "../shop-users-auth-edit/shop-users-auth-edit.component";
|
||||||
@@ -66,7 +67,7 @@ export function ShopInfoUsersComponent({ bodyshop }) {
|
|||||||
return <AlertComponent type="error" title={JSON.stringify(error)} />;
|
return <AlertComponent type="error" title={JSON.stringify(error)} />;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div>
|
<LayoutFormRow title={t("bodyshop.labels.licensing")}>
|
||||||
<ResponsiveTable
|
<ResponsiveTable
|
||||||
loading={loading}
|
loading={loading}
|
||||||
pagination={{ placement: "top" }}
|
pagination={{ placement: "top" }}
|
||||||
@@ -75,6 +76,6 @@ export function ShopInfoUsersComponent({ bodyshop }) {
|
|||||||
rowKey="id"
|
rowKey="id"
|
||||||
dataSource={data && data.associations}
|
dataSource={data && data.associations}
|
||||||
/>
|
/>
|
||||||
</div>
|
</LayoutFormRow>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -292,7 +292,23 @@
|
|||||||
},
|
},
|
||||||
"bodyshop": {
|
"bodyshop": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"add_adjuster": "Add Adjuster",
|
||||||
|
"add_control_number": "Add Control Number",
|
||||||
|
"add_cost_center": "Add Cost Center",
|
||||||
|
"add_courtesy_car_rate_preset": "Add Courtesy Car Contract Rate Preset",
|
||||||
|
"add_delivery_checklist_item": "Add Delivery Checklist Item",
|
||||||
|
"add_dms_allocation": "Add DMS Allocation",
|
||||||
|
"add_estimator": "Add Estimator",
|
||||||
|
"add_insurance_company": "Add Insurance Company",
|
||||||
|
"add_intake_checklist_item": "Add Intake Checklist Item",
|
||||||
|
"add_jobline_preset": "Add Jobline Preset",
|
||||||
|
"add_messaging_preset": "Add Messaging Preset",
|
||||||
|
"add_note_preset": "Add Note Preset",
|
||||||
|
"add_parts_order_comment": "Add Parts Order Comment",
|
||||||
|
"add_production_status_color": "Add Production Status Color",
|
||||||
|
"add_profit_center": "Add Profit Center",
|
||||||
"add_task_preset": "Add Task Preset",
|
"add_task_preset": "Add Task Preset",
|
||||||
|
"add_to_email_preset": "Add To Email Preset",
|
||||||
"addapptcolor": "Add Appointment Color",
|
"addapptcolor": "Add Appointment Color",
|
||||||
"addbucket": "Add Definition",
|
"addbucket": "Add Definition",
|
||||||
"addpartslocation": "Add Parts Location",
|
"addpartslocation": "Add Parts Location",
|
||||||
@@ -301,6 +317,7 @@
|
|||||||
"addtemplate": "Add Template",
|
"addtemplate": "Add Template",
|
||||||
"newlaborrate": "New Labor Rate",
|
"newlaborrate": "New Labor Rate",
|
||||||
"newsalestaxcode": "New Sales Tax Code",
|
"newsalestaxcode": "New Sales Tax Code",
|
||||||
|
"save_shop_information": "Save Shop Information",
|
||||||
"newstatus": "Add Status",
|
"newstatus": "Add Status",
|
||||||
"testrender": "Test Render"
|
"testrender": "Test Render"
|
||||||
},
|
},
|
||||||
@@ -1206,7 +1223,8 @@
|
|||||||
"employee_teams": {
|
"employee_teams": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"new": "New Team",
|
"new": "New Team",
|
||||||
"newmember": "New Team Member"
|
"newmember": "New Team Member",
|
||||||
|
"save_team": "Save Employee Team"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"allocation_total_exact": "Team allocation must total exactly 100%.",
|
"allocation_total_exact": "Team allocation must total exactly 100%.",
|
||||||
@@ -1236,9 +1254,11 @@
|
|||||||
},
|
},
|
||||||
"employees": {
|
"employees": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"addrate": "Add Rate",
|
||||||
"addvacation": "Add Vacation",
|
"addvacation": "Add Vacation",
|
||||||
"new": "New Employee",
|
"new": "New Employee",
|
||||||
"newrate": "New Rate",
|
"newrate": "New Rate",
|
||||||
|
"save_employee": "Save Employee",
|
||||||
"select": "Select Employee"
|
"select": "Select Employee"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1403,6 +1423,7 @@
|
|||||||
"beta": "BETA",
|
"beta": "BETA",
|
||||||
"cancel": "Are you sure you want to cancel? Your changes will not be saved.",
|
"cancel": "Are you sure you want to cancel? Your changes will not be saved.",
|
||||||
"changelog": "Change Log",
|
"changelog": "Change Log",
|
||||||
|
"click_to_begin": "Click {{action}} to begin",
|
||||||
"clear": "Clear",
|
"clear": "Clear",
|
||||||
"confirmpassword": "Confirm Password",
|
"confirmpassword": "Confirm Password",
|
||||||
"created_at": "Created At",
|
"created_at": "Created At",
|
||||||
|
|||||||
@@ -292,7 +292,23 @@
|
|||||||
},
|
},
|
||||||
"bodyshop": {
|
"bodyshop": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"add_adjuster": "",
|
||||||
|
"add_control_number": "",
|
||||||
|
"add_cost_center": "",
|
||||||
|
"add_courtesy_car_rate_preset": "",
|
||||||
|
"add_delivery_checklist_item": "",
|
||||||
|
"add_dms_allocation": "",
|
||||||
|
"add_estimator": "",
|
||||||
|
"add_insurance_company": "",
|
||||||
|
"add_intake_checklist_item": "",
|
||||||
|
"add_jobline_preset": "",
|
||||||
|
"add_messaging_preset": "",
|
||||||
|
"add_note_preset": "",
|
||||||
|
"add_parts_order_comment": "",
|
||||||
|
"add_production_status_color": "",
|
||||||
|
"add_profit_center": "",
|
||||||
"add_task_preset": "",
|
"add_task_preset": "",
|
||||||
|
"add_to_email_preset": "",
|
||||||
"addapptcolor": "",
|
"addapptcolor": "",
|
||||||
"addbucket": "",
|
"addbucket": "",
|
||||||
"addpartslocation": "",
|
"addpartslocation": "",
|
||||||
@@ -301,6 +317,7 @@
|
|||||||
"addtemplate": "",
|
"addtemplate": "",
|
||||||
"newlaborrate": "",
|
"newlaborrate": "",
|
||||||
"newsalestaxcode": "",
|
"newsalestaxcode": "",
|
||||||
|
"save_shop_information": "",
|
||||||
"newstatus": "",
|
"newstatus": "",
|
||||||
"testrender": ""
|
"testrender": ""
|
||||||
},
|
},
|
||||||
@@ -1206,7 +1223,8 @@
|
|||||||
"employee_teams": {
|
"employee_teams": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"new": "",
|
"new": "",
|
||||||
"newmember": ""
|
"newmember": "",
|
||||||
|
"save_team": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"allocation_total_exact": "",
|
"allocation_total_exact": "",
|
||||||
@@ -1236,9 +1254,11 @@
|
|||||||
},
|
},
|
||||||
"employees": {
|
"employees": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"addrate": "",
|
||||||
"addvacation": "",
|
"addvacation": "",
|
||||||
"new": "Nuevo empleado",
|
"new": "Nuevo empleado",
|
||||||
"newrate": "",
|
"newrate": "",
|
||||||
|
"save_employee": "",
|
||||||
"select": ""
|
"select": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1403,6 +1423,7 @@
|
|||||||
"beta": "",
|
"beta": "",
|
||||||
"cancel": "",
|
"cancel": "",
|
||||||
"changelog": "",
|
"changelog": "",
|
||||||
|
"click_to_begin": "",
|
||||||
"clear": "",
|
"clear": "",
|
||||||
"confirmpassword": "",
|
"confirmpassword": "",
|
||||||
"created_at": "",
|
"created_at": "",
|
||||||
|
|||||||
@@ -292,7 +292,23 @@
|
|||||||
},
|
},
|
||||||
"bodyshop": {
|
"bodyshop": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"add_adjuster": "",
|
||||||
|
"add_control_number": "",
|
||||||
|
"add_cost_center": "",
|
||||||
|
"add_courtesy_car_rate_preset": "",
|
||||||
|
"add_delivery_checklist_item": "",
|
||||||
|
"add_dms_allocation": "",
|
||||||
|
"add_estimator": "",
|
||||||
|
"add_insurance_company": "",
|
||||||
|
"add_intake_checklist_item": "",
|
||||||
|
"add_jobline_preset": "",
|
||||||
|
"add_messaging_preset": "",
|
||||||
|
"add_note_preset": "",
|
||||||
|
"add_parts_order_comment": "",
|
||||||
|
"add_production_status_color": "",
|
||||||
|
"add_profit_center": "",
|
||||||
"add_task_preset": "",
|
"add_task_preset": "",
|
||||||
|
"add_to_email_preset": "",
|
||||||
"addapptcolor": "",
|
"addapptcolor": "",
|
||||||
"addbucket": "",
|
"addbucket": "",
|
||||||
"addpartslocation": "",
|
"addpartslocation": "",
|
||||||
@@ -301,6 +317,7 @@
|
|||||||
"addtemplate": "",
|
"addtemplate": "",
|
||||||
"newlaborrate": "",
|
"newlaborrate": "",
|
||||||
"newsalestaxcode": "",
|
"newsalestaxcode": "",
|
||||||
|
"save_shop_information": "",
|
||||||
"newstatus": "",
|
"newstatus": "",
|
||||||
"testrender": ""
|
"testrender": ""
|
||||||
},
|
},
|
||||||
@@ -1206,7 +1223,8 @@
|
|||||||
"employee_teams": {
|
"employee_teams": {
|
||||||
"actions": {
|
"actions": {
|
||||||
"new": "",
|
"new": "",
|
||||||
"newmember": ""
|
"newmember": "",
|
||||||
|
"save_team": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"allocation_total_exact": "",
|
"allocation_total_exact": "",
|
||||||
@@ -1236,9 +1254,11 @@
|
|||||||
},
|
},
|
||||||
"employees": {
|
"employees": {
|
||||||
"actions": {
|
"actions": {
|
||||||
|
"addrate": "",
|
||||||
"addvacation": "",
|
"addvacation": "",
|
||||||
"new": "Nouvel employé",
|
"new": "Nouvel employé",
|
||||||
"newrate": "",
|
"newrate": "",
|
||||||
|
"save_employee": "",
|
||||||
"select": ""
|
"select": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
@@ -1403,6 +1423,7 @@
|
|||||||
"beta": "",
|
"beta": "",
|
||||||
"cancel": "",
|
"cancel": "",
|
||||||
"changelog": "",
|
"changelog": "",
|
||||||
|
"click_to_begin": "",
|
||||||
"clear": "",
|
"clear": "",
|
||||||
"confirmpassword": "",
|
"confirmpassword": "",
|
||||||
"created_at": "",
|
"created_at": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user