feature/IO-3255-simplified-parts-management - dumb down print center

This commit is contained in:
Dave
2025-08-13 18:10:57 -04:00
parent 960a2ccd30
commit 81d642fcd3
2 changed files with 195 additions and 2 deletions

View File

@@ -0,0 +1,183 @@
import { useSplitTreatments } from "@splitsoftware/splitio-react";
import { Button, Card, Col, Row, Space, Tooltip, Typography } from "antd";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectPrintCenter } from "../../redux/modals/modals.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import { selectTechnician } from "../../redux/tech/tech.selectors";
import { TemplateList } from "../../utils/TemplateConstants";
import { GenerateDocument } from "../../utils/RenderTemplate";
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
import { HistoryOutlined, MailOutlined, PrinterOutlined, UnorderedListOutlined } from "@ant-design/icons";
const mapStateToProps = createStructuredSelector({
printCenterModal: selectPrintCenter,
bodyshop: selectBodyshop,
technician: selectTechnician
});
const mapDispatchToProps = () => ({});
export function PrintCenterJobsPartsComponent({ printCenterModal, bodyshop, technician }) {
const { id: jobId, job } = printCenterModal.context;
const tempList = TemplateList("job", {});
const notification = useNotification();
const {
treatments: { Enhanced_Payroll }
} = useSplitTreatments({
attributes: {},
names: ["Enhanced_Payroll"],
splitKey: bodyshop.imexshopid
});
const Templates =
bodyshop.cdk_dealerid === null && bodyshop.pbs_serialnumber === null
? Object.keys(tempList)
.map((key) => tempList[key])
.filter(
(temp) =>
(!temp.regions ||
(temp.regions && temp.regions[bodyshop.region_config]) ||
(temp.regions && bodyshop.region_config.includes(Object.keys(temp.regions)) === true)) &&
(!temp.dms || temp.dms === false)
)
: Object.keys(tempList)
.map((key) => tempList[key])
.filter(
(temp) =>
!temp.regions ||
(temp.regions && temp.regions[bodyshop.region_config]) ||
(temp.regions && bodyshop.region_config.includes(Object.keys(temp.regions)) === true)
);
const JobsReportsList =
Enhanced_Payroll.treatment === "on"
? Object.keys(Templates)
.map((key) => Templates[key])
.filter((temp) => temp.enhanced_payroll === undefined || temp.enhanced_payroll === true)
: Object.keys(Templates)
.map((key) => Templates[key])
.filter((temp) => temp.enhanced_payroll === undefined || temp.enhanced_payroll === false);
const orderedKeys = ["parts_list", "parts_order_history"]; // explicit order
const cards = orderedKeys.map((k) => JobsReportsList.find((t) => t.key === k)).filter(Boolean);
const handlePrint = async (key) => {
await GenerateDocument(
{
name: key,
variables: { id: jobId }
},
{},
"p",
jobId,
notification
);
};
const handleEmail = async (key) => {
await GenerateDocument(
{
name: key,
variables: { id: jobId }
},
{
to: job && job.ownr_ea,
subject: cards.find((c) => c.key === key)?.subject
},
"e",
jobId,
notification
);
};
const iconForKey = (key) => {
switch (key) {
case "parts_list":
return <UnorderedListOutlined style={{ fontSize: 28 }} />;
case "parts_order_history":
return <HistoryOutlined style={{ fontSize: 28 }} />;
default:
return <PrinterOutlined style={{ fontSize: 28 }} />;
}
};
return (
<div>
<Row gutter={[16, 16]}>
{cards.map((item) => {
const actions = [
{
key: "print",
icon: <PrinterOutlined />,
onClick: () => handlePrint(item.key),
title: "Print",
disabled: item.disabled
},
...(!technician
? [
{
key: "email",
icon: <MailOutlined />,
onClick: () => handleEmail(item.key),
title: "Email",
disabled: item.disabled
}
]
: [])
];
const columns = `repeat(${actions.length}, 1fr)`;
return (
<Col key={item.key} xs={24} sm={12}>
<Card hoverable style={{ minHeight: 100 }}>
<div style={{ display: "flex", alignItems: "center", gap: 12 }}>
<div style={{ flex: "1 1 70%", minWidth: 0 }}>
<Space align="center">
<div aria-hidden>{iconForKey(item.key)}</div>
<Typography.Title level={5} style={{ margin: 0 }}>
{item.title}
</Typography.Title>
</Space>
</div>
<div style={{ flex: "0 0 30%" }}>
<div
style={{
display: "grid",
gridTemplateColumns: columns,
gap: 8,
alignItems: "stretch"
}}
>
{actions.map((action) => (
<Tooltip key={action.key} title={action.title} placement="top">
<Button
icon={action.icon}
size="large"
onClick={action.onClick}
disabled={action.disabled}
aria-label={action.title}
style={{
width: "100%",
aspectRatio: "1 / 1",
display: "flex",
alignItems: "center",
justifyContent: "center",
padding: 0
}}
/>
</Tooltip>
))}
</div>
</div>
</div>
</Card>
</Col>
);
})}
</Row>
</div>
);
}
export default connect(mapStateToProps, mapDispatchToProps)(PrintCenterJobsPartsComponent);

View File

@@ -1,7 +1,15 @@
import { useTranslation } from "react-i18next";
import PrintCenterJobs from "../print-center-jobs/print-center-jobs.component";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectIsPartsEntry } from "../../redux/application/application.selectors";
import PrintCenterJobsParts from "../print-center-jobs/print-center-jobs-parts.component";
export default function PrintCenterModalComponent({ context }) {
const mapStateToProps = createStructuredSelector({
isPartsEntry: selectIsPartsEntry
});
export function PrintCenterModalComponent({ context, isPartsEntry }) {
const { t } = useTranslation();
const { type } = context;
@@ -9,10 +17,12 @@ export default function PrintCenterModalComponent({ context }) {
switch (type) {
case "job":
ModalContent = PrintCenterJobs;
ModalContent = isPartsEntry ? PrintCenterJobsParts : PrintCenterJobs;
break;
default:
break;
}
return <div>{ModalContent ? <ModalContent /> : t("printcenter.errors.nocontexttype")}</div>;
}
export default connect(mapStateToProps)(PrintCenterModalComponent);