Merged in feature/IO-2886-Product-List-Profiles (pull request #1647)

Feature/IO-2886 Product List Profiles
This commit is contained in:
Dave Richer
2024-08-21 20:51:47 +00:00
5 changed files with 140 additions and 64 deletions

View File

@@ -23,7 +23,6 @@ export function ProductionListConfigManager({
setColumns,
setState,
onSave,
defaultView,
hasUnsavedChanges,
setHasUnsavedChanges
}) {
@@ -34,6 +33,7 @@ export function ProductionListConfigManager({
const [open, setOpen] = useState(false);
const [isAddingNewProfile, setIsAddingNewProfile] = useState(false);
const [form] = Form.useForm();
const [activeView, setActiveView] = useState(() => {
const assoc = bodyshop.associations.find((a) => a.useremail === currentUser.email);
return assoc && assoc.default_prod_list_view;
@@ -257,7 +257,29 @@ export function ProductionListConfigManager({
} else {
await updateActiveProdView(null);
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(() => {
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 the default view doesn't exist, revert to the main profile
@@ -344,7 +366,7 @@ export function ProductionListConfigManager({
}
} else {
// If the default view exists, set it as active
setActiveView(defaultView);
setActiveView(activeView);
}
};
@@ -356,13 +378,31 @@ export function ProductionListConfigManager({
validateAndSetDefaultView();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [defaultView, bodyshop.production_config]);
}, [activeView, bodyshop.production_config]);
const popMenu = (
<div>
<Form layout="vertical" form={form} onFinish={handleSaveConfig}>
{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 />
</Form.Item>
)}
@@ -376,7 +416,25 @@ export function ProductionListConfigManager({
>
{t("general.actions.save")}
</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>
</Form>
</div>
@@ -384,55 +442,64 @@ export function ProductionListConfigManager({
return (
<Space>
<Popover open={open} content={popMenu}>
<Button loading={loading} onClick={() => setOpen(true)} disabled={!isAddingNewProfile && !hasUnsavedChanges}>
{t("production.actions.saveconfig")}
</Button>
</Popover>
<Select
style={{
minWidth: "150px"
}}
onSelect={handleSelect}
placeholder={t("production.labels.selectview")}
optionLabelProp="label"
popupMatchSelectWidth={false}
value={activeView} // Ensure this only changes when appropriate
>
{bodyshop.production_config
.slice()
.sort((a, b) =>
a.name === t("production.constants.main_profile")
? -1
: b.name === t("production.constants.main_profile")
? 1
: 0
) //
.map((config) => (
<Select.Option key={config.name} label={config.name}>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<span style={{ flex: 1, maxWidth: "80%", marginRight: "1rem", textOverflow: "ellipsis" }}>
{config.name}
</span>
{config.name !== t("production.constants.main_profile") && (
<Popconfirm
placement="right"
title={t("general.labels.areyousure")}
onConfirm={() => handleTrash(config.name)}
<Button loading={loading} onClick={() => setOpen(true)} disabled={isAddingNewProfile || !hasUnsavedChanges}>
{t("production.actions.saveconfig")}
</Button>
<Popover open={open} content={popMenu} placement="bottom">
<Select
style={{
minWidth: "150px"
}}
onSelect={handleSelect}
placeholder={t("production.labels.selectview")}
optionLabelProp="label"
popupMatchSelectWidth={false}
value={activeView}
disabled={open || isAddingNewProfile} // Disable the Select box when the popover is open or adding a new profile
>
{bodyshop.production_config
.slice()
.sort((a, b) =>
a.name === t("production.constants.main_profile")
? -1
: b.name === t("production.constants.main_profile")
? 1
: 0
) //
.map((config) => (
<Select.Option key={config.name} label={config.name}>
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
<span
style={{
flex: 1,
maxWidth: "80%",
marginRight: "1rem",
textOverflow: "ellipsis"
}}
>
<DeleteOutlined onClick={(e) => e.stopPropagation()} />
</Popconfirm>
)}
</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>
{config.name}
</span>
{config.name !== t("production.constants.main_profile") && (
<Popconfirm
placement="right"
title={t("general.labels.areyousure")}
onConfirm={() => handleTrash(config.name)}
onCancel={(e) => e.stopPropagation()}
>
<DeleteOutlined onClick={(e) => e.stopPropagation()} />
</Popconfirm>
)}
</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>
);
}

View File

@@ -269,17 +269,17 @@ export function ProductionListTable({ loading, data, refetch, bodyshop, technici
data={data}
onColumnAdd={addColumn}
/>
<ProductionListConfigManager
columns={columns}
tableState={state}
setColumns={setColumns}
state={state}
setState={setState}
refetch={refetch}
data={data}
bodyshop={bodyshop}
technician={technician}
currentUser={currentUser}
defaultView={defaultView}
setHasUnsavedChanges={setHasUnsavedChanges}
hasUnsavedChanges={hasUnsavedChanges}
onSave={() => {

View File

@@ -1165,7 +1165,8 @@
"tryagain": "Try Again",
"view": "View",
"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": {
"fcm": "You must allow notification permissions to have real time messaging. Click to try again.",
@@ -1180,7 +1181,7 @@
"vehicle": "Vehicle"
},
"labels": {
"unsavedchanges": "Unsaved change.",
"unsavedchanges": "Unsaved changes.",
"actions": "Actions",
"areyousure": "Are you sure?",
"barcode": "Barcode",
@@ -2788,7 +2789,9 @@
"errors": {
"boardupdate": "Error encountered updating Job. {{message}}",
"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": {
"kiosk_mode": "Kiosk Mode",

View File

@@ -1165,7 +1165,8 @@
"tryagain": "",
"view": "",
"viewreleasenotes": "",
"remove_alert": ""
"remove_alert": "",
"saveas": ""
},
"errors": {
"fcm": "",
@@ -2788,7 +2789,9 @@
"errors": {
"boardupdate": "",
"removing": "",
"settings": ""
"settings": "",
"name_exists": "",
"name_required": ""
},
"labels": {
"kiosk_mode": "",

View File

@@ -1165,7 +1165,8 @@
"tryagain": "",
"view": "",
"viewreleasenotes": "",
"remove_alert": ""
"remove_alert": "",
"saveas": ""
},
"errors": {
"fcm": "",
@@ -2788,7 +2789,9 @@
"errors": {
"boardupdate": "",
"removing": "",
"settings": ""
"settings": "",
"name_exists": "",
"name_required": ""
},
"labels": {
"kiosk_mode": "",