Merged in feature/IO-2886-Product-List-Profiles (pull request #1647)
Feature/IO-2886 Product List Profiles
This commit is contained in:
@@ -23,7 +23,6 @@ export function ProductionListConfigManager({
|
|||||||
setColumns,
|
setColumns,
|
||||||
setState,
|
setState,
|
||||||
onSave,
|
onSave,
|
||||||
defaultView,
|
|
||||||
hasUnsavedChanges,
|
hasUnsavedChanges,
|
||||||
setHasUnsavedChanges
|
setHasUnsavedChanges
|
||||||
}) {
|
}) {
|
||||||
@@ -34,6 +33,7 @@ export function ProductionListConfigManager({
|
|||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [isAddingNewProfile, setIsAddingNewProfile] = useState(false);
|
const [isAddingNewProfile, setIsAddingNewProfile] = useState(false);
|
||||||
const [form] = Form.useForm();
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
const [activeView, setActiveView] = useState(() => {
|
const [activeView, setActiveView] = useState(() => {
|
||||||
const assoc = bodyshop.associations.find((a) => a.useremail === currentUser.email);
|
const assoc = bodyshop.associations.find((a) => a.useremail === currentUser.email);
|
||||||
return assoc && assoc.default_prod_list_view;
|
return assoc && assoc.default_prod_list_view;
|
||||||
@@ -257,7 +257,29 @@ export function ProductionListConfigManager({
|
|||||||
} else {
|
} else {
|
||||||
await updateActiveProdView(null);
|
await updateActiveProdView(null);
|
||||||
setColumns([]);
|
setColumns([]);
|
||||||
setState(defaultState); // Reset to default state if no configs are left
|
setState(defaultState);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Revert back to the active view and load its columns and state
|
||||||
|
const activeConfig = bodyshop.production_config.find((pc) => pc.name === activeView);
|
||||||
|
if (activeConfig) {
|
||||||
|
await updateActiveProdView(activeView);
|
||||||
|
setColumns(
|
||||||
|
activeConfig.columns.columnKeys.map((k) => {
|
||||||
|
return {
|
||||||
|
...ProductionListColumns({
|
||||||
|
technician,
|
||||||
|
state: ensureDefaultState(state),
|
||||||
|
refetch,
|
||||||
|
data: data,
|
||||||
|
activeStatuses: bodyshop.md_ro_statuses.active_statuses,
|
||||||
|
treatments: { Enhanced_Payroll }
|
||||||
|
}).find((e) => e.key === k.key),
|
||||||
|
width: k.width
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
setState(ensureDefaultState(activeConfig.columns.tableState));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -311,7 +333,7 @@ export function ProductionListConfigManager({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const validateAndSetDefaultView = () => {
|
const validateAndSetDefaultView = () => {
|
||||||
const configExists = bodyshop.production_config.some((pc) => pc.name === defaultView);
|
const configExists = bodyshop.production_config.some((pc) => pc.name === activeView);
|
||||||
|
|
||||||
if (!configExists) {
|
if (!configExists) {
|
||||||
// If the default view doesn't exist, revert to the main profile
|
// If the default view doesn't exist, revert to the main profile
|
||||||
@@ -344,7 +366,7 @@ export function ProductionListConfigManager({
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// If the default view exists, set it as active
|
// If the default view exists, set it as active
|
||||||
setActiveView(defaultView);
|
setActiveView(activeView);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -356,13 +378,31 @@ export function ProductionListConfigManager({
|
|||||||
validateAndSetDefaultView();
|
validateAndSetDefaultView();
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [defaultView, bodyshop.production_config]);
|
}, [activeView, bodyshop.production_config]);
|
||||||
|
|
||||||
const popMenu = (
|
const popMenu = (
|
||||||
<div>
|
<div>
|
||||||
<Form layout="vertical" form={form} onFinish={handleSaveConfig}>
|
<Form layout="vertical" form={form} onFinish={handleSaveConfig}>
|
||||||
{isAddingNewProfile && (
|
{isAddingNewProfile && (
|
||||||
<Form.Item label={t("production.labels.viewname")} name="name" rules={[{ required: true }]}>
|
<Form.Item
|
||||||
|
label={t("production.labels.viewname")}
|
||||||
|
name="name"
|
||||||
|
rules={[
|
||||||
|
{ required: true, message: t("production.errors.name_required") },
|
||||||
|
{
|
||||||
|
validator: (_, value) => {
|
||||||
|
if (!value) {
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
const nameExists = bodyshop.production_config.some((pc) => pc.name === value);
|
||||||
|
if (nameExists) {
|
||||||
|
return Promise.reject(new Error(t("production.errors.name_exists")));
|
||||||
|
}
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
>
|
||||||
<Input />
|
<Input />
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
)}
|
)}
|
||||||
@@ -376,7 +416,25 @@ export function ProductionListConfigManager({
|
|||||||
>
|
>
|
||||||
{t("general.actions.save")}
|
{t("general.actions.save")}
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={() => setOpen(false)}>{t("general.actions.close")}</Button>
|
{!isAddingNewProfile && (
|
||||||
|
<Button
|
||||||
|
type="default"
|
||||||
|
onClick={() => {
|
||||||
|
setIsAddingNewProfile(true);
|
||||||
|
setOpen(true);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("general.actions.saveas")}
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setIsAddingNewProfile(false);
|
||||||
|
setOpen(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t("general.actions.cancel")}
|
||||||
|
</Button>
|
||||||
</Space>
|
</Space>
|
||||||
</Form>
|
</Form>
|
||||||
</div>
|
</div>
|
||||||
@@ -384,55 +442,64 @@ export function ProductionListConfigManager({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Space>
|
<Space>
|
||||||
<Popover open={open} content={popMenu}>
|
<Button loading={loading} onClick={() => setOpen(true)} disabled={isAddingNewProfile || !hasUnsavedChanges}>
|
||||||
<Button loading={loading} onClick={() => setOpen(true)} disabled={!isAddingNewProfile && !hasUnsavedChanges}>
|
{t("production.actions.saveconfig")}
|
||||||
{t("production.actions.saveconfig")}
|
</Button>
|
||||||
</Button>
|
<Popover open={open} content={popMenu} placement="bottom">
|
||||||
</Popover>
|
<Select
|
||||||
<Select
|
style={{
|
||||||
style={{
|
minWidth: "150px"
|
||||||
minWidth: "150px"
|
}}
|
||||||
}}
|
onSelect={handleSelect}
|
||||||
onSelect={handleSelect}
|
placeholder={t("production.labels.selectview")}
|
||||||
placeholder={t("production.labels.selectview")}
|
optionLabelProp="label"
|
||||||
optionLabelProp="label"
|
popupMatchSelectWidth={false}
|
||||||
popupMatchSelectWidth={false}
|
value={activeView}
|
||||||
value={activeView} // Ensure this only changes when appropriate
|
disabled={open || isAddingNewProfile} // Disable the Select box when the popover is open or adding a new profile
|
||||||
>
|
>
|
||||||
{bodyshop.production_config
|
{bodyshop.production_config
|
||||||
.slice()
|
.slice()
|
||||||
.sort((a, b) =>
|
.sort((a, b) =>
|
||||||
a.name === t("production.constants.main_profile")
|
a.name === t("production.constants.main_profile")
|
||||||
? -1
|
? -1
|
||||||
: b.name === t("production.constants.main_profile")
|
: b.name === t("production.constants.main_profile")
|
||||||
? 1
|
? 1
|
||||||
: 0
|
: 0
|
||||||
) //
|
) //
|
||||||
.map((config) => (
|
.map((config) => (
|
||||||
<Select.Option key={config.name} label={config.name}>
|
<Select.Option key={config.name} label={config.name}>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
|
||||||
<span style={{ flex: 1, maxWidth: "80%", marginRight: "1rem", textOverflow: "ellipsis" }}>
|
<span
|
||||||
{config.name}
|
style={{
|
||||||
</span>
|
flex: 1,
|
||||||
{config.name !== t("production.constants.main_profile") && (
|
maxWidth: "80%",
|
||||||
<Popconfirm
|
marginRight: "1rem",
|
||||||
placement="right"
|
textOverflow: "ellipsis"
|
||||||
title={t("general.labels.areyousure")}
|
}}
|
||||||
onConfirm={() => handleTrash(config.name)}
|
|
||||||
>
|
>
|
||||||
<DeleteOutlined onClick={(e) => e.stopPropagation()} />
|
{config.name}
|
||||||
</Popconfirm>
|
</span>
|
||||||
)}
|
{config.name !== t("production.constants.main_profile") && (
|
||||||
</div>
|
<Popconfirm
|
||||||
</Select.Option>
|
placement="right"
|
||||||
))}
|
title={t("general.labels.areyousure")}
|
||||||
<Select.Option key="add_new" label={t("production.labels.addnewprofile")}>
|
onConfirm={() => handleTrash(config.name)}
|
||||||
<div style={{ display: "flex", alignItems: "center" }}>
|
onCancel={(e) => e.stopPropagation()}
|
||||||
<PlusOutlined style={{ marginRight: "0.5rem" }} />
|
>
|
||||||
{t("production.labels.addnewprofile")}
|
<DeleteOutlined onClick={(e) => e.stopPropagation()} />
|
||||||
</div>
|
</Popconfirm>
|
||||||
</Select.Option>
|
)}
|
||||||
</Select>
|
</div>
|
||||||
|
</Select.Option>
|
||||||
|
))}
|
||||||
|
<Select.Option key="add_new" label={t("production.labels.addnewprofile")}>
|
||||||
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
|
<PlusOutlined style={{ marginRight: "0.5rem" }} />
|
||||||
|
{t("production.labels.addnewprofile")}
|
||||||
|
</div>
|
||||||
|
</Select.Option>
|
||||||
|
</Select>
|
||||||
|
</Popover>
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -269,17 +269,17 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
|
|||||||
data={data}
|
data={data}
|
||||||
onColumnAdd={addColumn}
|
onColumnAdd={addColumn}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<ProductionListConfigManager
|
<ProductionListConfigManager
|
||||||
columns={columns}
|
columns={columns}
|
||||||
tableState={state}
|
|
||||||
setColumns={setColumns}
|
setColumns={setColumns}
|
||||||
|
state={state}
|
||||||
setState={setState}
|
setState={setState}
|
||||||
refetch={refetch}
|
refetch={refetch}
|
||||||
data={data}
|
data={data}
|
||||||
bodyshop={bodyshop}
|
bodyshop={bodyshop}
|
||||||
technician={technician}
|
technician={technician}
|
||||||
currentUser={currentUser}
|
currentUser={currentUser}
|
||||||
defaultView={defaultView}
|
|
||||||
setHasUnsavedChanges={setHasUnsavedChanges}
|
setHasUnsavedChanges={setHasUnsavedChanges}
|
||||||
hasUnsavedChanges={hasUnsavedChanges}
|
hasUnsavedChanges={hasUnsavedChanges}
|
||||||
onSave={() => {
|
onSave={() => {
|
||||||
|
|||||||
@@ -1165,7 +1165,8 @@
|
|||||||
"tryagain": "Try Again",
|
"tryagain": "Try Again",
|
||||||
"view": "View",
|
"view": "View",
|
||||||
"viewreleasenotes": "See What's Changed",
|
"viewreleasenotes": "See What's Changed",
|
||||||
"remove_alert": "Are you sure you want to dismiss the alert?"
|
"remove_alert": "Are you sure you want to dismiss the alert?",
|
||||||
|
"saveas": "Save As"
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"fcm": "You must allow notification permissions to have real time messaging. Click to try again.",
|
"fcm": "You must allow notification permissions to have real time messaging. Click to try again.",
|
||||||
@@ -1180,7 +1181,7 @@
|
|||||||
"vehicle": "Vehicle"
|
"vehicle": "Vehicle"
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"unsavedchanges": "Unsaved change.",
|
"unsavedchanges": "Unsaved changes.",
|
||||||
"actions": "Actions",
|
"actions": "Actions",
|
||||||
"areyousure": "Are you sure?",
|
"areyousure": "Are you sure?",
|
||||||
"barcode": "Barcode",
|
"barcode": "Barcode",
|
||||||
@@ -2788,7 +2789,9 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"boardupdate": "Error encountered updating Job. {{message}}",
|
"boardupdate": "Error encountered updating Job. {{message}}",
|
||||||
"removing": "Error removing from production board. {{error}}",
|
"removing": "Error removing from production board. {{error}}",
|
||||||
"settings": "Error saving board settings: {{error}}"
|
"settings": "Error saving board settings: {{error}}",
|
||||||
|
"name_exists": "A Profile with this name already exists. Please choose a different name.",
|
||||||
|
"name_required": "Profile name is required."
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"kiosk_mode": "Kiosk Mode",
|
"kiosk_mode": "Kiosk Mode",
|
||||||
|
|||||||
@@ -1165,7 +1165,8 @@
|
|||||||
"tryagain": "",
|
"tryagain": "",
|
||||||
"view": "",
|
"view": "",
|
||||||
"viewreleasenotes": "",
|
"viewreleasenotes": "",
|
||||||
"remove_alert": ""
|
"remove_alert": "",
|
||||||
|
"saveas": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"fcm": "",
|
"fcm": "",
|
||||||
@@ -2788,7 +2789,9 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"boardupdate": "",
|
"boardupdate": "",
|
||||||
"removing": "",
|
"removing": "",
|
||||||
"settings": ""
|
"settings": "",
|
||||||
|
"name_exists": "",
|
||||||
|
"name_required": ""
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"kiosk_mode": "",
|
"kiosk_mode": "",
|
||||||
|
|||||||
@@ -1165,7 +1165,8 @@
|
|||||||
"tryagain": "",
|
"tryagain": "",
|
||||||
"view": "",
|
"view": "",
|
||||||
"viewreleasenotes": "",
|
"viewreleasenotes": "",
|
||||||
"remove_alert": ""
|
"remove_alert": "",
|
||||||
|
"saveas": ""
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"fcm": "",
|
"fcm": "",
|
||||||
@@ -2788,7 +2789,9 @@
|
|||||||
"errors": {
|
"errors": {
|
||||||
"boardupdate": "",
|
"boardupdate": "",
|
||||||
"removing": "",
|
"removing": "",
|
||||||
"settings": ""
|
"settings": "",
|
||||||
|
"name_exists": "",
|
||||||
|
"name_required": ""
|
||||||
},
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"kiosk_mode": "",
|
"kiosk_mode": "",
|
||||||
|
|||||||
Reference in New Issue
Block a user