ES Cleanup

This commit is contained in:
Patrick Fic
2025-09-04 09:44:21 -07:00
parent b90fe00078
commit cf9c237235
7 changed files with 108 additions and 74 deletions

View File

@@ -86,7 +86,7 @@ async function ScrubEstimate({ job }) {
});
}
const fileName = `RPSTest-${job.id}-${Date.now()}`;
const fileName = `RPS-Scrub-${job.id}-${job.clm_no}-${Date.now()}`;
// Write job object to logs subfolder
try {
@@ -110,22 +110,23 @@ async function ScrubEstimate({ job }) {
const resultPDFUrl = result?.data?.report_link
log.log("Estimate Scrubber Result:", result.data, resultPDFUrl);
// log.log("Estimate Scrubber Result:", result.data, resultPDFUrl);
const b = BrowserWindow.getAllWindows()[0];
b.webContents.send(ipcTypes.app.toRenderer.scrubResults, {
jobid: job.id,
items: result.data?.identified_item
items: result.data?.identified_item,
pdfUrl: resultPDFUrl
});
const pdfWindow = new BrowserWindow({
// const pdfWindow = new BrowserWindow({
webPreferences: {
plugins: true, // Enable PDF viewing
},
});
// webPreferences: {
// plugins: true, // Enable PDF viewing
// },
// });
pdfWindow.loadURL(resultPDFUrl);
pdfWindow.focus();
// pdfWindow.loadURL(resultPDFUrl);
// pdfWindow.focus();
return resultPDFUrl
}
exports.ScrubEstimate = ScrubEstimate

View File

@@ -3,7 +3,7 @@
"productName": "ImEX RPS",
"author": "ImEX Systems Inc. <support@thinkimex.com>",
"description": "ImEX RPS",
"version": "1.4.2-alpha.10",
"version": "1.4.2-alpha.11",
"main": "electron/main.js",
"homepage": "./",
"dependencies": {

View File

@@ -37,6 +37,22 @@ export function EstimateScrubberButton({ bodyshop, jobid, job }) {
const result = await ipcRenderer.invoke(ipcTypes.app.toMain.scrubEstimate, {
job: jobData.data.jobs_by_pk
});
message.success("Estimate scrubbed successfully! ");
// Scroll to the estimate scrubber results section
const scrollToResults = () => {
const element = document.getElementById("es-results-card");
if (element) {
element.scrollIntoView({
behavior: "smooth",
block: "start",
inline: "nearest"
});
}
};
// Small delay to ensure DOM is updated before scrolling
setTimeout(scrollToResults, 100);
} catch (error) {
message.error("Error scrubbing estimate: " + error.message);
console.error("Error scrubbing estimate:", error);

View File

@@ -1,11 +1,12 @@
import { InfoCircleOutlined, LinkOutlined, SearchOutlined } from "@ant-design/icons";
import { Badge, Collapse, Input, Space, Table, Tag, Typography } from "antd";
import { Badge, Button, Collapse, Input, Result, Space, Table, Tag, Typography } from "antd";
import _ from "lodash";
import { useState } from "react";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { selectEsResults } from "../../../redux/application/application.selectors";
import { selectBodyshop } from "../../../redux/user/user.selectors";
import EstimateScrubberButton from "../estimate-scrubber-button/estimate-scrubber-button.molecule";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
@@ -24,8 +25,8 @@ export function EstimateScrubberResults({ bodyshop, jobid, job, esResults }) {
const [searchText, setSearchText] = useState("");
// Filter items based on search text
const filteredItems = esResults?.items
? esResults.items.filter(item => {
const filteredItems = esResults?.items
? esResults.items.filter((item) => {
if (!searchText.trim()) return true;
const searchLower = searchText.toLowerCase();
return (
@@ -86,13 +87,21 @@ export function EstimateScrubberResults({ bodyshop, jobid, job, esResults }) {
if (!esResults?.items?.length || job?.id !== esResults?.jobid) {
return (
<div style={{ padding: "24px", textAlign: "center" }}>
<InfoCircleOutlined style={{ fontSize: "48px", color: "#d9d9d9", marginBottom: "16px" }} />
<Title level={4} type="secondary">
Estimate not yet scrubbed.
</Title>
<Text type="secondary">Run the estimate scrubber to see results here.</Text>
</div>
<Result
status={"info"}
title="Estimate not yet scrubbed."
subTitle="Run the estimate scrubber to see results here."
extra={<EstimateScrubberButton key="es" jobid={job ? job.id : null} job={job ? job : null} />}
/>
// <div style={{ padding: "24px", textAlign: "center" }}>
// <InfoCircleOutlined style={{ fontSize: "48px", color: "#d9d9d9", marginBottom: "16px" }} />
// <Title level={4} type="secondary">
// Estimate not yet scrubbed.
// </Title>
// <Text type="secondary">Run the estimate scrubber to see results here.</Text>
// <EstimateScrubberButton key="es" jobid={job ? job.id : null} job={job ? job : null} />
// </div>
);
}
@@ -101,7 +110,7 @@ export function EstimateScrubberResults({ bodyshop, jobid, job, esResults }) {
return (
<div style={{ padding: "16px" }}>
<Input
placeholder="Search items and descriptions..."
placeholder="Search..."
prefix={<SearchOutlined />}
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
@@ -124,21 +133,43 @@ export function EstimateScrubberResults({ bodyshop, jobid, job, esResults }) {
<Space direction="vertical" size="large" style={{ width: "100%" }}>
{/* Search Input */}
<div>
<Input
placeholder="Search items and descriptions..."
prefix={<SearchOutlined />}
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
allowClear
style={{ maxWidth: 400 }}
/>
{searchText && (
<div style={{ marginTop: "8px" }}>
<Text type="secondary">
Showing {filteredItems.length} of {esResults.items.length} items
</Text>
</div>
)}
<Space>
<Input
placeholder="Search"
prefix={<SearchOutlined />}
value={searchText}
onChange={(e) => setSearchText(e.target.value)}
allowClear
style={{ maxWidth: 400 }}
/>
{searchText && (
<div style={{ marginTop: "8px" }}>
<Text type="secondary">
Showing {filteredItems.length} of {esResults.items.length} items
</Text>
</div>
)}
<Space wrap size={"small"}>
{Object.entries(groupedItems).map(([category, items]) => {
const config = categoryConfig[category] || { color: "default" };
return (
<Tag key={category} color={config.color}>
{category}: {items.length}
</Tag>
);
})}
</Space>
</Space>
<Button
style={{ float: "right" }}
type="primary"
href={esResults?.pdfUrl}
target="_blank"
disabled={!esResults?.pdfUrl}
>
View PDF
</Button>
</div>
{/* Grouped Results */}
@@ -179,18 +210,6 @@ export function EstimateScrubberResults({ bodyshop, jobid, job, esResults }) {
</Collapse>
{/* Summary */}
<Title level={5}>Summary</Title>
<Space wrap>
{Object.entries(groupedItems).map(([category, items]) => {
const config = categoryConfig[category] || { color: "default" };
return (
<Tag key={category} color={config.color}>
{category}: {items.length}
</Tag>
);
})}
</Space>
</Space>
</div>
);

View File

@@ -13,8 +13,17 @@ import TimeAgoFormatter from "../../atoms/time-ago-formatter/time-ago-formatter.
import VehicleGroupAlertAtom from "../../atoms/vehicle-group-alert/vehicle-group-alert.atom";
import CloseDateDisplayMolecule from "../close-date-display/close-date-display.molecule";
import JobGroupMolecule from "../job-group/job-group.molecule";
import EstimateScrubberButton from "../estimate-scrubber-button/estimate-scrubber-button.molecule.jsx";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../../redux/user/user.selectors.js";
import { connect } from "react-redux";
export default function JobsDetailDescriptionMolecule({ loading, job, jobDetailRef }) {
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
});
export default connect(mapStateToProps, null)(JobsDetailDescriptionMolecule);
export function JobsDetailDescriptionMolecule({ bodyshop, loading, job, jobDetailRef }) {
// Store original theme state
const originalThemeRef = useRef(null);
@@ -88,6 +97,7 @@ export default function JobsDetailDescriptionMolecule({ loading, job, jobDetailR
/>
</Tooltip>
),
bodyshop.phone && <EstimateScrubberButton key="es" jobid={job ? job.id : null} job={job ? job : null} />,
<DeleteJobAtom key="delete" jobId={job.id} />,
<Button key="print" onClick={handlePrint}>
<PrinterFilled />

View File

@@ -14,17 +14,19 @@ import JobsDetailDescriptionMolecule from "../../molecules/jobs-detail-descripti
import JobsLinesTableMolecule from "../../molecules/jobs-lines-table/jobs-lines-table.molecule";
import JobsTargetsStatsMolecule from "../../molecules/jobs-targets-stats/jobs-targets-stats.molecule";
import "./jobs-detail.organism.styles.scss";
import { selectBodyshop } from "../../../redux/user/user.selectors";
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
selectedJobId: selectSelectedJobId
selectedJobId: selectSelectedJobId,
bodyshop: selectBodyshop
});
const mapDispatchToProps = (dispatch) => ({
//setUserLanguage: language => dispatch(setUserLanguage(language))
setSelectedJobTargetPc: (job) => dispatch(setSelectedJobTargetPc(job))
});
export function JobsDetailOrganism({ selectedJobId, setSelectedJobTargetPc }) {
export function JobsDetailOrganism({ bodyshop, selectedJobId, setSelectedJobTargetPc }) {
const { loading, error, data } = useQuery(QUERY_JOB_BY_PK, {
variables: { jobId: selectedJobId },
skip: !selectedJobId
@@ -81,30 +83,14 @@ export function JobsDetailOrganism({ selectedJobId, setSelectedJobTargetPc }) {
//2025-05-27 Removing CC AI
*/}
<Card
title="Estimate Lines"
extra={[
<EstimateScrubberButton
key="es"
jobid={data ? data.jobs_by_pk?.id : null}
job={data ? data.jobs_by_pk : null}
/>
]}
>
<Card title="Estimate Lines">
<JobsLinesTableMolecule loading={loading} job={data ? data.jobs_by_pk : {}} />
</Card>
<Card
title="Estimate Scrubber Results"
extra={[
<EstimateScrubberButton
key="es"
jobid={data ? data.jobs_by_pk?.id : null}
job={data ? data.jobs_by_pk : null}
/>
]}
>
<EstimateScrubberResultsMolecule loading={loading} job={data ? data.jobs_by_pk : {}} />
</Card>
{bodyshop.phone && (
<Card id="es-results-card" title="Estimate Scrubber Results" extra={[]}>
<EstimateScrubberResultsMolecule loading={loading} job={data ? data.jobs_by_pk : {}} />
</Card>
)}
<Card title="Parts Breakdown">
<div
style={{

View File

@@ -10,6 +10,8 @@ export const QUERY_BODYSHOP = gql`
ppd_diff_alert
features
channel
zip_post
phone
}
targets {
id