diff --git a/electron/audit/audit-ipc.js b/electron/audit/audit-ipc.js index 5319720..e209a74 100644 --- a/electron/audit/audit-ipc.js +++ b/electron/audit/audit-ipc.js @@ -6,47 +6,54 @@ const _ = require("lodash"); const { store } = require("../electron-store"); const path = require("path"); var xlsx = require("node-xlsx"); +const log = require("electron-log"); -ipcMain.on(ipcTypes.default.audit.toMain.browseForFile, async (event, arg) => { +ipcMain.on(ipcTypes.default.audit.toMain.browseForFile, async (event, { sheetName }) => { const result = await dialog.showOpenDialog(mainWindow, { filters: [{ extensions: ["xls", "xlsx"], name: "Excel Files" }], properties: ["openFile"] }); if (!result.canceled) { - store.set("auditFilePath", result.filePaths); - var obj = xlsx.parse(result.filePaths[0], { cellDates: true }); // parses a file + try { + store.set("auditFilePath", result.filePaths); + var obj = xlsx.parse(result.filePaths[0], { cellDates: true }); // parses a file - const detailSheet = obj.find((sheet) => sheet.name === "Shop RPS Claim Detail"); - const claimsArray = []; - let foundHeaderRow, foundTotalRow; - detailSheet.data.forEach((line) => { - //Check the first element. If it's claim number, we have our header row. the next one is important. - if (!foundHeaderRow && line[0] === "Claim Number") { - foundHeaderRow = true; - } else if (foundHeaderRow && !foundTotalRow && line[0] && line[0] !== "Grand Total") { - //Add it to the array - const row = { - clm_no: line[0], - close_date: line[1], - v_model_yr: line[3], - v_make_desc: line[4], - v_model: line[5], - under20kmiles: line[6], - pan_total: line[7], - paa_total: line[8], - pal_total: line[9], - pam_total: line[10], - eligible_db_price_total: Math.round((line[11] + Number.EPSILON) * 100) / 100, - eligible_act_price_total: Math.round((line[12] + Number.EPSILON) * 100) / 100, - expected_rps_dollars: Math.round((line[15] + Number.EPSILON) * 100) / 100, - actual_rps_dollars: Math.round((line[16] + Number.EPSILON) * 100) / 100 - }; - claimsArray.push(row); - } else { - // foundTotalRow = true; - } - }); + const detailSheet = obj.find((sheet) => sheet.name === sheetName); + const claimsArray = []; + let foundHeaderRow, foundTotalRow; + detailSheet.data.forEach((line) => { + //Check the first element. If it's claim number, we have our header row. the next one is important. + if (!foundHeaderRow && line[0] === "Claim Number") { + foundHeaderRow = true; + } else if (foundHeaderRow && !foundTotalRow && line[0] && line[0] !== "Grand Total") { + //Add it to the array + const row = { + clm_no: line[0], + close_date: line[1], + v_model_yr: line[3], + v_make_desc: line[4], + v_model: line[5], + under20kmiles: line[6], + pan_total: line[7], + paa_total: line[8], + pal_total: line[9], + pam_total: line[10], + eligible_db_price_total: Math.round((line[11] + Number.EPSILON) * 100) / 100, + eligible_act_price_total: Math.round((line[12] + Number.EPSILON) * 100) / 100, + expected_rps_dollars: Math.round((line[15] + Number.EPSILON) * 100) / 100, + actual_rps_dollars: Math.round((line[16] + Number.EPSILON) * 100) / 100 + }; + claimsArray.push(row); + } else { + // foundTotalRow = true; + } + }); - event.sender.send(ipcTypes.default.audit.toRenderer.auditClaimsArray, claimsArray); + event.sender.send(ipcTypes.default.audit.toRenderer.auditClaimsArray, claimsArray); + } catch (error) { + console.log("ot some sort of err", error); + log.error("Error when trying to read audit xlsx file", error); + event.sender.send(ipcTypes.default.audit.toRenderer.auditError, error.message); + } } }); diff --git a/src/components/organisms/audit-results/audit-results.organism.jsx b/src/components/organisms/audit-results/audit-results.organism.jsx index df17852..9dad2d9 100644 --- a/src/components/organisms/audit-results/audit-results.organism.jsx +++ b/src/components/organisms/audit-results/audit-results.organism.jsx @@ -1,4 +1,4 @@ -import { Card, Col, Row, Table } from "antd"; +import { Card, Col, Divider, Space, Table, Tooltip } from "antd"; import React from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; @@ -6,6 +6,7 @@ import { setSelectedJobTargetPc } from "../../../redux/application/application.a import { selectAuditData } from "../../../redux/reporting/reporting.selectors"; import { DateFormat } from "../../../util/constants"; import dayjs from "../../../util/day"; +import Dinero from "dinero.js"; const mapStateToProps = createStructuredSelector({ selectAuditData: selectAuditData @@ -16,22 +17,22 @@ const mapDispatchToProps = (dispatch) => ({ }); export function AuditResultsOrganism({ selectAuditData }) { - console.log("🚀 ~ AuditResultsOrganism ~ selectAuditData:", selectAuditData); const missingColumns = [ - { key: "clm_no", title: "Claim No.", dataIndex: "clm_no" }, + { key: "clm_no", width: "20%", title: "Claim No.", dataIndex: "clm_no" }, { key: "close_date", + width: "20%", title: "[RPS] R4P", dataIndex: "close_date", render: (text, record) => dayjs(record.close_date).format(DateFormat) }, - { key: "v_model_yr", title: "Model Year", dataIndex: "v_model_yr" }, - { key: "v_make_desc", title: "Make", dataIndex: "v_make_desc" }, - { key: "v_model", title: "Model", dataIndex: "v_model" } + { key: "v_model_yr", width: "20%", title: "Model Year", dataIndex: "v_model_yr" }, + { key: "v_make_desc", width: "20%", title: "Make", dataIndex: "v_make_desc" }, + { key: "v_model", width: "20%", title: "Model", dataIndex: "v_model" } ]; const mismatchColumns = [ - { key: "clm_no", title: "Claim No.", dataIndex: ["rps", "clm_no"] }, + { key: "clm_no", width: "12%", title: "Claim No.", dataIndex: ["rps", "clm_no"] }, { key: "close_date", title: "[RPS] R4P", @@ -40,53 +41,66 @@ export function AuditResultsOrganism({ selectAuditData }) { }, { key: "close_date_audit", + width: "12%", title: "[Audit] R4P", dataIndex: "close_date_audit", render: (text, record) => dayjs(record.audit.close_date).format(DateFormat) }, - { key: "v_model_yr", title: "Model Year", dataIndex: ["audit", "v_model_yr"] }, - { key: "v_make_desc", title: "Make", dataIndex: ["audit", "v_make_desc"] }, - { key: "v_model", title: "Model", dataIndex: ["audit", "v_model"] }, + { key: "v_model_yr", width: "12%", title: "Model Year", dataIndex: ["audit", "v_model_yr"] }, + { key: "v_make_desc", width: "12%", title: "Make", dataIndex: ["audit", "v_make_desc"] }, + { key: "v_model", width: "12%", title: "Model", dataIndex: ["audit", "v_model"] }, { key: "expected_rps", - title: "[RPS] Expected", + width: "12%", + title: "Expected RPS", dataIndex: ["audit", "expectedRpsDollars"], - render: (text, record) => record.rps.expectedRpsDollars.toFormat() + render: (text, record) => ( + }> + {record.rps.expectedRpsDollars.toFormat()} + + {Dinero({ amount: Math.round(record.audit.expected_rps_dollars * 100) }).toFormat()} + + + ) }, - { key: "expected_audit", title: "[AUDIT] Expected", dataIndex: ["audit", "expected_rps_dollars"] }, { key: "actual_rps", - title: "[RPS] Actual", + width: "12%", + title: " Actual RPS", dataIndex: ["audit", "jobRpsDollars"], - render: (text, record) => record.rps.jobRpsDollars.toFormat() - }, - { key: "actual_audit", title: "[Audit] Actual", dataIndex: ["audit", "actual_rps_dollars"] } + render: (text, record) => ( + }> + {record.rps.jobRpsDollars.toFormat()} + + {Dinero({ amount: Math.round(record.audit.actual_rps_dollars * 100) }).toFormat()} + + + ) + } ]; return ( -
- - - - - - - - -
- - - - -
- - - - -
- - - - + <> + + +
+ + + + +
+ + + + +
+ + + + +
+ + + ); } export default connect(mapStateToProps, mapDispatchToProps)(AuditResultsOrganism); diff --git a/src/components/pages/audit/audit.page.jsx b/src/components/pages/audit/audit.page.jsx index 6d40b85..da796f8 100644 --- a/src/components/pages/audit/audit.page.jsx +++ b/src/components/pages/audit/audit.page.jsx @@ -1,4 +1,4 @@ -import { Button, DatePicker, Form } from "antd"; +import { Alert, Button, Card, Col, DatePicker, Form, Input, Row } from "antd"; import React from "react"; import ipcTypes from "../../../ipc.types"; import { connect } from "react-redux"; @@ -7,78 +7,91 @@ import { queryReportingData } from "../../../redux/reporting/reporting.actions"; import dayjs from "../../../util/day"; import AuditResultsOrganism from "../../organisms/audit-results/audit-results.organism"; import "./audit.page.styles.scss"; +import { selectAuditError } from "../../../redux/reporting/reporting.selectors"; const { ipcRenderer } = window; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser + auditError: selectAuditError }); const mapDispatchToProps = (dispatch) => ({ queryReportingData: (dates) => dispatch(queryReportingData(dates)) }); export default connect(mapStateToProps, mapDispatchToProps)(AuditPage); -export function AuditPage({ queryReportingData }) { - const handleBrowseForFile = async ({ dateRange }) => { - console.log("🚀 ~ handleBrowseForFile ~ dateRange:", dateRange); +export function AuditPage({ auditError, queryReportingData }) { + const handleBrowseForFile = async ({ sheetName, dateRange }) => { queryReportingData({ startDate: dateRange[0] || dayjs("2024-03-01"), endDate: dateRange[1] || dayjs("2024-03-31") }); - ipcRenderer.send(ipcTypes.audit.toMain.browseForFile); + ipcRenderer.send(ipcTypes.audit.toMain.browseForFile, { sheetName }); }; return (
-
- +
+ + + 1) { - return Promise.reject("Time period exceeds 1 month. Please select a shorter date range."); - } else { - return Promise.resolve(); - } - } - } - ]} - > - - - - - + // if (dayjs(value[1]).diff(dayjs(value[0]), "month", true) > 1) { + // return Promise.reject("Time period exceeds 1 month. Please select a shorter date range."); + // } else { + return Promise.resolve(); + // } + } + } + ]} + > + + + + + + + + + + {auditError && ( + + + + )} + + ); } diff --git a/src/components/pages/audit/audit.page.styles.scss b/src/components/pages/audit/audit.page.styles.scss index a51d7c8..2545a60 100644 --- a/src/components/pages/audit/audit.page.styles.scss +++ b/src/components/pages/audit/audit.page.styles.scss @@ -2,7 +2,7 @@ height: 100%; overflow-y: auto; background-color: rgb(244, 244, 244); - & > .reporting-cards > * { + & > * { margin: 0.7rem; } } diff --git a/src/index.jsx b/src/index.jsx index 5ffb92e..d702940 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,13 +1,12 @@ //import LogRocket from "logrocket"; import React from "react"; -import { createRoot } from "react-dom/client"; +import ReactDOM from "react-dom/client"; import { Provider } from "react-redux"; import { MemoryRouter } from "react-router-dom"; import { PersistGate } from "redux-persist/integration/react"; import App from "./App/App"; import "./index.css"; import { persistor, store } from "./redux/store"; -import ReactDOM from "react-dom/client"; import * as Sentry from "@sentry/electron"; diff --git a/src/ipc.types.json b/src/ipc.types.json index 6f80fa5..81d9bc1 100644 --- a/src/ipc.types.json +++ b/src/ipc.types.json @@ -68,7 +68,7 @@ "audit": { "toMain": { "browseForFile": "audit__browseForFile" }, - "toRenderer": { "auditClaimsArray": "audit__filepath" } + "toRenderer": { "auditClaimsArray": "audit__filepath", "auditError": "audit__auditError" } }, "estimate": { "toRenderer": { diff --git a/src/ipc/ipc-renderer-handler.js b/src/ipc/ipc-renderer-handler.js index 67a4c16..89631e2 100644 --- a/src/ipc/ipc-renderer-handler.js +++ b/src/ipc/ipc-renderer-handler.js @@ -7,7 +7,7 @@ import { setWatchedPaths, setWatcherStatus } from "../redux/application/application.actions"; -import { calculateAudit } from "../redux/reporting/reporting.actions"; +import { calculateAudit, setAuditError } from "../redux/reporting/reporting.actions"; import { setScanEstimateList } from "../redux/scan/scan.actions"; import { store } from "../redux/store"; import { signOutStart } from "../redux/user/user.actions"; @@ -81,3 +81,6 @@ ipcRenderer.on(ipcTypes.app.toRenderer.appVersion, async (event, appversion) => ipcRenderer.on(ipcTypes.audit.toRenderer.auditClaimsArray, async (event, claimsArray) => { store.dispatch(calculateAudit(claimsArray)); }); +ipcRenderer.on(ipcTypes.audit.toRenderer.auditError, async (event, error) => { + store.dispatch(setAuditError(error)); +}); diff --git a/src/redux/reporting/reporting.actions.js b/src/redux/reporting/reporting.actions.js index d2976d7..b89f82e 100644 --- a/src/redux/reporting/reporting.actions.js +++ b/src/redux/reporting/reporting.actions.js @@ -34,3 +34,5 @@ export const setAuditResults = (auditResults) => ({ type: ReportingActionTypes.SET_AUDIT_RESULTS, payload: auditResults }); + +export const setAuditError = (error) => ({ type: ReportingActionTypes.SET_AUDIT_ERROR, payload: error }); diff --git a/src/redux/reporting/reporting.reducer.js b/src/redux/reporting/reporting.reducer.js index a949796..2db406d 100644 --- a/src/redux/reporting/reporting.reducer.js +++ b/src/redux/reporting/reporting.reducer.js @@ -5,7 +5,8 @@ const INITIAL_STATE = { scoreCard: null, error: null, loading: false, - audit: {} + audit: {}, + auditError: null }; const applicationReducer = (state = INITIAL_STATE, action) => { @@ -30,7 +31,9 @@ const applicationReducer = (state = INITIAL_STATE, action) => { case ReportingActionTypes.SET_SCORE_CARD: return { ...state, loading: false, scoreCard: action.payload }; case ReportingActionTypes.SET_AUDIT_RESULTS: - return { ...state, loading: false, audit: action.payload }; + return { ...state, loading: false, auditError: null, audit: action.payload }; + case ReportingActionTypes.SET_AUDIT_ERROR: + return { ...state, auditError: action.payload }; case ReportingActionTypes.TOGGLE_GROUP_VERIFIED: return { ...state, diff --git a/src/redux/reporting/reporting.selectors.js b/src/redux/reporting/reporting.selectors.js index 505509b..d2bb7dc 100644 --- a/src/redux/reporting/reporting.selectors.js +++ b/src/redux/reporting/reporting.selectors.js @@ -2,30 +2,13 @@ import { createSelector } from "reselect"; const selectReporting = (state) => state.reporting; -export const selectReportLoading = createSelector( - [selectReporting], - (reporting) => reporting.loading -); -export const selectDates = createSelector( - [selectReporting], - (reporting) => reporting.dates -); -export const selectScorecard = createSelector( - [selectReporting], - (reporting) => reporting.scoreCard -); -export const selectReportingError = createSelector( - [selectReporting], - (reporting) => reporting.error -); -export const selectReportData = createSelector( - [selectReporting], - (reporting) => reporting.data -); -export const selectAuditData = createSelector( - [selectReporting], - (reporting) => reporting.audit -); +export const selectReportLoading = createSelector([selectReporting], (reporting) => reporting.loading); +export const selectDates = createSelector([selectReporting], (reporting) => reporting.dates); +export const selectScorecard = createSelector([selectReporting], (reporting) => reporting.scoreCard); +export const selectReportingError = createSelector([selectReporting], (reporting) => reporting.error); +export const selectReportData = createSelector([selectReporting], (reporting) => reporting.data); +export const selectAuditData = createSelector([selectReporting], (reporting) => reporting.audit); +export const selectAuditError = createSelector([selectReporting], (reporting) => reporting.auditError); // export const selectWatchedPaths = createSelector( // [selectReporting], diff --git a/src/redux/reporting/reporting.types.js b/src/redux/reporting/reporting.types.js index 28c9beb..e7b87c4 100644 --- a/src/redux/reporting/reporting.types.js +++ b/src/redux/reporting/reporting.types.js @@ -6,6 +6,7 @@ const ReportingActionTypes = { SET_REPORTING_ERROR: "SET_REPORTING_ERROR", TOGGLE_GROUP_VERIFIED: "TOGGLE_GROUP_VERIFIED", CALCULATE_AUDIT: "CALCULATE_AUDIT", - SET_AUDIT_RESULTS: "SET_AUDIT_RESULTS" + SET_AUDIT_RESULTS: "SET_AUDIT_RESULTS", + SET_AUDIT_ERROR: "SET_AUDIT_ERROR" }; export default ReportingActionTypes;