diff --git a/electron/audit/audit-ipc.js b/electron/audit/audit-ipc.js index e209a74..4b411e8 100644 --- a/electron/audit/audit-ipc.js +++ b/electron/audit/audit-ipc.js @@ -31,7 +31,7 @@ ipcMain.on(ipcTypes.default.audit.toMain.browseForFile, async (event, { sheetNam clm_no: line[0], close_date: line[1], v_model_yr: line[3], - v_make_desc: line[4], + v_makedesc: line[4], v_model: line[5], under20kmiles: line[6], pan_total: line[7], diff --git a/hasura/metadata/databases/default/tables/public_bodyshops.yaml b/hasura/metadata/databases/default/tables/public_bodyshops.yaml index 4296d9d..55048ce 100644 --- a/hasura/metadata/databases/default/tables/public_bodyshops.yaml +++ b/hasura/metadata/databases/default/tables/public_bodyshops.yaml @@ -29,6 +29,7 @@ select_permissions: columns: - accepted_ins_co - created_at + - features - groups - id - ppd_diff_alert diff --git a/hasura/migrations/default/1713972915783_alter_table_public_bodyshops_add_column_features/down.sql b/hasura/migrations/default/1713972915783_alter_table_public_bodyshops_add_column_features/down.sql new file mode 100644 index 0000000..fc0ae53 --- /dev/null +++ b/hasura/migrations/default/1713972915783_alter_table_public_bodyshops_add_column_features/down.sql @@ -0,0 +1,4 @@ +-- Could not auto-generate a down migration. +-- Please write an appropriate down migration for the SQL below: +-- alter table "public"."bodyshops" add column "features" jsonb +-- null default jsonb_build_object(); diff --git a/hasura/migrations/default/1713972915783_alter_table_public_bodyshops_add_column_features/up.sql b/hasura/migrations/default/1713972915783_alter_table_public_bodyshops_add_column_features/up.sql new file mode 100644 index 0000000..6127432 --- /dev/null +++ b/hasura/migrations/default/1713972915783_alter_table_public_bodyshops_add_column_features/up.sql @@ -0,0 +1,2 @@ +alter table "public"."bodyshops" add column "features" jsonb + null default jsonb_build_object(); diff --git a/src/components/organisms/audit-results/audit-results.organism.jsx b/src/components/organisms/audit-results/audit-results.organism.jsx index 9dad2d9..c612d0c 100644 --- a/src/components/organisms/audit-results/audit-results.organism.jsx +++ b/src/components/organisms/audit-results/audit-results.organism.jsx @@ -7,6 +7,7 @@ import { selectAuditData } from "../../../redux/reporting/reporting.selectors"; import { DateFormat } from "../../../util/constants"; import dayjs from "../../../util/day"; import Dinero from "dinero.js"; +import { alphaSort, dateSort } from "../../../util/sorters"; const mapStateToProps = createStructuredSelector({ selectAuditData: selectAuditData @@ -18,25 +19,41 @@ const mapDispatchToProps = (dispatch) => ({ export function AuditResultsOrganism({ selectAuditData }) { const missingColumns = [ - { key: "clm_no", width: "20%", title: "Claim No.", dataIndex: "clm_no" }, + { + key: "clm_no", + width: "20%", + title: "Claim No.", + sorter: (a, b) => alphaSort(a.clm_no, b.clm_no), + dataIndex: "clm_no" + }, { key: "close_date", width: "20%", title: "[RPS] R4P", dataIndex: "close_date", + defaultSortOrder: "ascend", + sorter: (a, b) => dateSort(a.close_date, b.close_date), render: (text, record) => dayjs(record.close_date).format(DateFormat) }, { 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_makedesc", width: "20%", title: "Make", dataIndex: "v_makedesc" }, { key: "v_model", width: "20%", title: "Model", dataIndex: "v_model" } ]; const mismatchColumns = [ - { key: "clm_no", width: "12%", title: "Claim No.", dataIndex: ["rps", "clm_no"] }, + { + key: "clm_no", + width: "12%", + title: "Claim No.", + sorter: (a, b) => alphaSort(a.rps.clm_no, b.rps.clm_no), + dataIndex: ["rps", "clm_no"] + }, { key: "close_date", title: "[RPS] R4P", dataIndex: "close_date", + defaultSortOrder: "ascend", + sorter: (a, b) => dateSort(a.rps.close_date, b.rps.close_date), render: (text, record) => dayjs(record.rps.close_date).format(DateFormat) }, { @@ -44,10 +61,12 @@ export function AuditResultsOrganism({ selectAuditData }) { width: "12%", title: "[Audit] R4P", dataIndex: "close_date_audit", + sorter: (a, b) => dateSort(a.audit.close_date, b.audit.close_date), + render: (text, record) => dayjs(record.audit.close_date).format(DateFormat) }, { 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_makedesc", width: "12%", title: "Make", dataIndex: ["audit", "v_makedesc"] }, { key: "v_model", width: "12%", title: "Model", dataIndex: ["audit", "v_model"] }, { key: "expected_rps", diff --git a/src/components/pages/audit/audit.page.jsx b/src/components/pages/audit/audit.page.jsx index da796f8..5b3ddb4 100644 --- a/src/components/pages/audit/audit.page.jsx +++ b/src/components/pages/audit/audit.page.jsx @@ -1,13 +1,14 @@ 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"; import { createStructuredSelector } from "reselect"; +import ipcTypes from "../../../ipc.types"; import { queryReportingData } from "../../../redux/reporting/reporting.actions"; +import { selectAuditError } from "../../../redux/reporting/reporting.selectors"; import dayjs from "../../../util/day"; import AuditResultsOrganism from "../../organisms/audit-results/audit-results.organism"; +import FeatureWrapper from "../../templates/feature-wrapper"; import "./audit.page.styles.scss"; -import { selectAuditError } from "../../../redux/reporting/reporting.selectors"; const { ipcRenderer } = window; @@ -28,70 +29,81 @@ export function AuditPage({ auditError, queryReportingData }) { }); ipcRenderer.send(ipcTypes.audit.toMain.browseForFile, { sheetName }); }; - + if (auditError) console.log("Error when opening audit file.", auditError); return ( -
- - - -
- 1) { - // return Promise.reject("Time period exceeds 1 month. Please select a shorter date range."); - // } else { - return Promise.resolve(); - // } - } - } - ]} - > - - - - - - -
-
- - {auditError && ( + +
+ - + +
+ 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/reporting/reporting.page.jsx b/src/components/pages/reporting/reporting.page.jsx index 5c6aa85..f9bd347 100644 --- a/src/components/pages/reporting/reporting.page.jsx +++ b/src/components/pages/reporting/reporting.page.jsx @@ -4,10 +4,7 @@ import { connect } from "react-redux"; import { Link } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { setSelectedJobId } from "../../../redux/application/application.actions"; -import { - selectDates, - selectReportingError, -} from "../../../redux/reporting/reporting.selectors"; +import { selectDates, selectReportingError } from "../../../redux/reporting/reporting.selectors"; import ReportingTitleAtom from "../../atoms/reporting-title/reporting-title.atom"; import ReportingDatesMolecule from "../../molecules/reporting-dates/reporting-dates.molecule"; import ReportingJobsListMolecule from "../../molecules/reporting-jobs-list/reporting-jobs-list.molecule"; @@ -17,10 +14,10 @@ import "./reporting.page.styles.scss"; const mapStateToProps = createStructuredSelector({ dates: selectDates, - error: selectReportingError, + error: selectReportingError }); const mapDispatchToProps = (dispatch) => ({ - setSelectedJobId: (id) => dispatch(setSelectedJobId(id)), + setSelectedJobId: (id) => dispatch(setSelectedJobId(id)) }); export function ReportingPage({ dates, error, setSelectedJobId }) { diff --git a/src/components/templates/feature-wrapper.jsx b/src/components/templates/feature-wrapper.jsx new file mode 100644 index 0000000..3b2055f --- /dev/null +++ b/src/components/templates/feature-wrapper.jsx @@ -0,0 +1,40 @@ +import dayjs from "../../util/day"; +import React from "react"; +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +import { Alert } from "antd"; + +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop +}); + +function FeatureWrapper({ bodyshop, featureName, noauth, children, ...restProps }) { + if (HasFeatureAccess({ featureName, bodyshop })) return children; + + return ( + noauth || ( + + ) + ); +} + +export function HasFeatureAccess({ featureName, bodyshop }) { + return bodyshop?.features?.allAccess || dayjs(bodyshop?.features[featureName]).isAfter(dayjs()); +} + +export default connect(mapStateToProps, null)(FeatureWrapper); + +/* +dashboard +production-board +scoreboard +csi +tech-console +mobile-imaging +*/ diff --git a/src/graphql/bodyshop.queries.js b/src/graphql/bodyshop.queries.js index d19b207..ab1adff 100644 --- a/src/graphql/bodyshop.queries.js +++ b/src/graphql/bodyshop.queries.js @@ -8,6 +8,7 @@ export const QUERY_BODYSHOP = gql` accepted_ins_co groups ppd_diff_alert + features } targets { id @@ -33,6 +34,7 @@ export const UPDATE_SHOP = gql` accepted_ins_co groups ppd_diff_alert + features } } } diff --git a/src/util/sorters.js b/src/util/sorters.js index 1139ee7..4789dc4 100644 --- a/src/util/sorters.js +++ b/src/util/sorters.js @@ -1,12 +1,11 @@ export function alphaSort(a, b) { - let A; - let B; - - A = a ? a.toLowerCase() : ""; - B = b ? b.toLowerCase() : ""; - if (A < B) - //sort string ascending - return -1; - if (A > B) return 1; - return 0; //default return value (no sorting) + return (a ? a.toLowerCase() : "").localeCompare(b ? b.toLowerCase() : ""); +} + +export function dateSort(a, b) { + return new Date(a) - new Date(b); +} + +export function statusSort(a, b, statusList) { + return statusList.findIndex((x) => x === a) - statusList.findIndex((x) => x === b); }