WIP report. Added stats, sagas for calculation, formatting.
This commit is contained in:
@@ -29,7 +29,7 @@ export default function CloseDateDisplayMolecule({ jobId, close_date }) {
|
||||
return (
|
||||
<div onBlur={() => setEditMode(false)}>
|
||||
<DatePicker
|
||||
value={value.isValid() ? value : null}
|
||||
value={value && value.isValid() ? value : null}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
{loading && <Spin size="small" />}
|
||||
@@ -38,7 +38,7 @@ export default function CloseDateDisplayMolecule({ jobId, close_date }) {
|
||||
|
||||
return (
|
||||
<div style={{ cursor: "pointer" }} onClick={() => setEditMode(true)}>
|
||||
{value.isValid() ? value.format("MM/DD/yyyy") : "No date set"}
|
||||
{value && value.isValid() ? value.format("MM/DD/yyyy") : "No date set"}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ export default function JobsSearchFieldsMolecule({ callSearchQuery }) {
|
||||
const handleFinish = (values) => {
|
||||
callSearchQuery({
|
||||
variables: {
|
||||
search: values.search,
|
||||
search: values.search || "",
|
||||
startDate: (values.dateRange && values.dateRange[0]) || null,
|
||||
endDate: (values.dateRange && values.dateRange[1]) || null,
|
||||
},
|
||||
|
||||
@@ -53,10 +53,9 @@ export function JobsTargetsStatsMolecule({
|
||||
<Statistic
|
||||
title="Current RPS %"
|
||||
valueStyle={{
|
||||
color:
|
||||
selectedJobTargetPc * 100 > currentRpsPc ? "tomato" : "seagreen",
|
||||
color: selectedJobTargetPc > currentRpsPc ? "tomato" : "seagreen",
|
||||
}}
|
||||
value={currentRpsPc}
|
||||
value={(currentRpsPc * 100).toFixed(1)}
|
||||
suffix="%"
|
||||
/>
|
||||
<Statistic title="Current RPS $" value={currentRpsDollars.toFormat()} />
|
||||
|
||||
@@ -0,0 +1,140 @@
|
||||
import { Input, Table } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import CurrencyFormatterAtom from "../../atoms/currency-formatter/currency-formatter.atom";
|
||||
import IgnoreJobLine from "../../atoms/ignore-job-line/ignore-job-line.atom";
|
||||
import partTypeConverterAtom from "../../atoms/part-type-converter/part-type-converter.atom";
|
||||
import PriceDiffPcFormatterAtom from "../../atoms/price-diff-pc-formatter/price-diff-pc-formatter.atom";
|
||||
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
selectReportData,
|
||||
selectReportLoading,
|
||||
} from "../../../redux/reporting/reporting.selectors";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
reportingLoading: selectReportLoading,
|
||||
reportData: selectReportData,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ReportingJobsListMolecule);
|
||||
|
||||
export function ReportingJobsListMolecule({ reportingLoading, reportData }) {
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: "Claim No.",
|
||||
dataIndex: "clm_no",
|
||||
key: "clm_no",
|
||||
},
|
||||
{
|
||||
title: "Ins Co.",
|
||||
dataIndex: "ins_co_nm",
|
||||
key: "ins_co_nm",
|
||||
},
|
||||
{
|
||||
title: "First Name",
|
||||
dataIndex: "ownr_fn",
|
||||
key: "ownr_fn",
|
||||
},
|
||||
{
|
||||
title: "Last Name",
|
||||
dataIndex: "ownr_ln",
|
||||
key: "ownr_ln",
|
||||
},
|
||||
{
|
||||
title: "Vehicle",
|
||||
dataIndex: "vehicle",
|
||||
key: "vehicle",
|
||||
render: (text, record) =>
|
||||
`${record.v_model_yr} ${record.v_makedesc} ${record.v_model} (${
|
||||
record.v_type
|
||||
}) - ${record.group} @ ${
|
||||
record.v_age === 1 ? `${record.v_age} year` : `${record.v_age} years`
|
||||
}`,
|
||||
},
|
||||
{
|
||||
title: "Database Price Sum",
|
||||
dataIndex: "dbPriceSum",
|
||||
key: "dbPriceSum",
|
||||
render: (text, record) => record.dbPriceSum.toFormat(),
|
||||
},
|
||||
{
|
||||
title: "Actual Price Sum ",
|
||||
dataIndex: "actPriceSum",
|
||||
key: "actPriceSum",
|
||||
render: (text, record) => record.actPriceSum.toFormat(),
|
||||
},
|
||||
{
|
||||
title: "Price Diff.",
|
||||
dataIndex: "jobRpsDollars",
|
||||
key: "jobRpsDollars",
|
||||
render: (text, record) => (
|
||||
<span
|
||||
style={{
|
||||
color: record.jobRpsPc > record.jobTarget ? "seagreen" : "tomato",
|
||||
}}
|
||||
>
|
||||
{`${record.jobRpsDollars.toFormat()} / ${record.expectedRpsDollars.toFormat()}`}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Price Diff. %",
|
||||
dataIndex: "price_diff_pc",
|
||||
key: "price_diff_pc",
|
||||
render: (text, record) => (
|
||||
<span
|
||||
style={{
|
||||
color: record.jobRpsPc > record.jobTarget ? "seagreen" : "tomato",
|
||||
}}
|
||||
>
|
||||
{`${(record.jobRpsPc * 100).toFixed(1)}% / ${(
|
||||
record.jobTarget * 100
|
||||
).toFixed(1)}%`}
|
||||
</span>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const data =
|
||||
searchText !== ""
|
||||
? reportData.filter(
|
||||
(j) =>
|
||||
j.ownr_fn.toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
j.ownr_ln.toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
j.ownr_clm_no.toLowerCase().includes(searchText.toLowerCase())
|
||||
)
|
||||
: reportData;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
title={() => (
|
||||
<Input.Search
|
||||
placeholder="Search"
|
||||
onSearch={(val) => {
|
||||
setSearchText(val);
|
||||
}}
|
||||
enterButton
|
||||
allowClear
|
||||
/>
|
||||
)}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
loading={reportingLoading}
|
||||
size="small"
|
||||
pagination={false}
|
||||
dataSource={data}
|
||||
scroll={{
|
||||
x: true,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { Skeleton, Statistic } from "antd";
|
||||
import React, { useCallback } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectSelectedJobTargetPc } from "../../../redux/application/application.selectors";
|
||||
import {
|
||||
selectReportLoading,
|
||||
selectScorecard,
|
||||
} from "../../../redux/reporting/reporting.selectors";
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
reportingLoading: selectReportLoading,
|
||||
scoreCard: selectScorecard,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ReportingTotalsStatsMolecule);
|
||||
|
||||
export function ReportingTotalsStatsMolecule({ reportingLoading, scoreCard }) {
|
||||
if (reportingLoading) return <Skeleton active />;
|
||||
if (!scoreCard)
|
||||
return <ErrorResultAtom title="Error displaying score card data." />;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-around",
|
||||
marginTop: "1rem",
|
||||
marginBottom: "1rem",
|
||||
}}
|
||||
>
|
||||
<Statistic
|
||||
title="RPS Total"
|
||||
value={scoreCard.shopRpsTotalDollars.toFormat()}
|
||||
/>
|
||||
<Statistic
|
||||
title="RPS Expectation"
|
||||
value={scoreCard.shopRpsExpectedDollars.toFormat()}
|
||||
/>
|
||||
<Statistic
|
||||
title="RPS Variance $"
|
||||
valueStyle={{
|
||||
color:
|
||||
scoreCard.varianceDollars.getAmount() < 0 ? "tomato" : "seagreen",
|
||||
}}
|
||||
value={scoreCard.varianceDollars.toFormat()}
|
||||
/>
|
||||
<Statistic
|
||||
title="Current RPS %"
|
||||
valueStyle={{
|
||||
color:
|
||||
scoreCard.currentRpsPc <= scoreCard.targetRpsPc
|
||||
? "tomato"
|
||||
: "seagreen",
|
||||
}}
|
||||
value={(scoreCard.currentRpsPc * 100).toFixed(1)}
|
||||
suffix="%"
|
||||
/>
|
||||
<Statistic
|
||||
title="Target RPS %"
|
||||
value={(scoreCard.targetRpsPc * 100).toFixed(1)}
|
||||
suffix="%"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,10 +1,29 @@
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectDates } from "../../../redux/reporting/reporting.selectors";
|
||||
import ReportingDatesMolecule from "../../molecules/reporting-dates/reporting-dates.molecule";
|
||||
import ReportingJobsListMolecule from "../../molecules/reporting-jobs-list/reporting-jobs-list.molecule";
|
||||
import ReportingTotalsStatsMolecule from "../../molecules/reporting-totals-stats/reporting-totals-stats.molecule";
|
||||
|
||||
export default function ReportingPage() {
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
dates: selectDates,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ReportingPage);
|
||||
|
||||
export function ReportingPage({ dates }) {
|
||||
return (
|
||||
<div>
|
||||
<ReportingDatesMolecule />
|
||||
{dates && dates.startDate && dates.endDate && (
|
||||
<div>
|
||||
<ReportingTotalsStatsMolecule />
|
||||
<ReportingJobsListMolecule />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user