Added formatting for jobs lists and jobs detail components
This commit is contained in:
@@ -170,7 +170,7 @@ async function DecodeVehFile(extensionlessFilePath) {
|
||||
async function DecodeTtlFile(extensionlessFilePath) {
|
||||
let dbf = await DBFFile.open(`${extensionlessFilePath}.TTL`);
|
||||
let records = await dbf.readRecords(1);
|
||||
return _.pick(records[0], ["CLM_TOTAL"]);
|
||||
return { clm_total: records[0]["G_TTL_AMT"] };
|
||||
}
|
||||
|
||||
async function DecodeLinFile(extensionlessFilePath) {
|
||||
|
||||
1
hasura/debug.log
Normal file
1
hasura/debug.log
Normal file
@@ -0,0 +1 @@
|
||||
[1014/195617.530:ERROR:directory_reader_win.cc(43)] FindFirstFile: The system cannot find the path specified. (0x3)
|
||||
@@ -0,0 +1,37 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: false
|
||||
columns:
|
||||
- clm_total
|
||||
- clm_no
|
||||
- ins_co_nm
|
||||
- ownr_fn
|
||||
- ownr_ln
|
||||
- ro_number
|
||||
- v_makedesc
|
||||
- v_model
|
||||
- v_model_yr
|
||||
- v_type
|
||||
- v_vin
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
computed_fields: []
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -0,0 +1,37 @@
|
||||
- args:
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: drop_select_permission
|
||||
- args:
|
||||
permission:
|
||||
allow_aggregations: true
|
||||
columns:
|
||||
- clm_total
|
||||
- clm_no
|
||||
- ins_co_nm
|
||||
- ownr_fn
|
||||
- ownr_ln
|
||||
- ro_number
|
||||
- v_makedesc
|
||||
- v_model
|
||||
- v_model_yr
|
||||
- v_type
|
||||
- v_vin
|
||||
- created_at
|
||||
- updated_at
|
||||
- bodyshopid
|
||||
- id
|
||||
computed_fields: []
|
||||
filter:
|
||||
bodyshop:
|
||||
associations:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
role: user
|
||||
table:
|
||||
name: jobs
|
||||
schema: public
|
||||
type: create_select_permission
|
||||
@@ -195,6 +195,7 @@ tables:
|
||||
user:
|
||||
authid:
|
||||
_eq: X-Hasura-User-Id
|
||||
allow_aggregations: true
|
||||
update_permissions:
|
||||
- role: user
|
||||
permission:
|
||||
|
||||
51
package-lock.json
generated
51
package-lock.json
generated
@@ -6787,6 +6787,11 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"dinero.js": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/dinero.js/-/dinero.js-1.8.1.tgz",
|
||||
"integrity": "sha512-AQ09MDKonkGUrhBZZFx4tPTVcVJuHJ0VEA73LvcBoBB2eQSi1DbapeXj4wnUUpx1hVnPdyev1xPNnNMGy/Au0g=="
|
||||
},
|
||||
"dir-glob": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz",
|
||||
@@ -13426,6 +13431,17 @@
|
||||
"prepend-http": "^1.0.0",
|
||||
"query-string": "^4.1.0",
|
||||
"sort-keys": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"requires": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"prepend-http": {
|
||||
@@ -13442,6 +13458,11 @@
|
||||
"ajv-errors": "^1.0.0",
|
||||
"ajv-keywords": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -16315,12 +16336,13 @@
|
||||
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
|
||||
},
|
||||
"query-string": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
|
||||
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
|
||||
"version": "6.13.5",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-6.13.5.tgz",
|
||||
"integrity": "sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q==",
|
||||
"requires": {
|
||||
"object-assign": "^4.1.0",
|
||||
"strict-uri-encode": "^1.0.0"
|
||||
"decode-uri-component": "^0.2.0",
|
||||
"split-on-first": "^1.0.0",
|
||||
"strict-uri-encode": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"querystring": {
|
||||
@@ -17130,6 +17152,14 @@
|
||||
"resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.7.tgz",
|
||||
"integrity": "sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA=="
|
||||
},
|
||||
"react-infinite-scroller": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/react-infinite-scroller/-/react-infinite-scroller-1.2.4.tgz",
|
||||
"integrity": "sha512-/oOa0QhZjXPqaD6sictN2edFMsd3kkMiE19Vcz5JDgHpzEJVqYcmq+V3mkwO88087kvKGe1URNksHEOt839Ubw==",
|
||||
"requires": {
|
||||
"prop-types": "^15.5.8"
|
||||
}
|
||||
},
|
||||
"react-is": {
|
||||
"version": "16.13.1",
|
||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||
@@ -18914,6 +18944,11 @@
|
||||
"integrity": "sha1-mHbb0qFp0xFUAtSObqYynIgWpQ0=",
|
||||
"dev": true
|
||||
},
|
||||
"split-on-first": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz",
|
||||
"integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw=="
|
||||
},
|
||||
"split-string": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
|
||||
@@ -19059,9 +19094,9 @@
|
||||
"integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ=="
|
||||
},
|
||||
"strict-uri-encode": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
|
||||
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
|
||||
"integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
|
||||
},
|
||||
"string-convert": {
|
||||
"version": "0.2.1",
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
"apollo-link-logger": "^2.0.0",
|
||||
"chokidar": "^3.4.3",
|
||||
"dbffile": "^1.4.3",
|
||||
"dinero.js": "^1.8.1",
|
||||
"dotenv": "^8.2.0",
|
||||
"electron-is-dev": "^1.2.0",
|
||||
"electron-settings": "^4.0.2",
|
||||
@@ -18,10 +19,13 @@
|
||||
"firebase": "^7.23.0",
|
||||
"graphql": "^15.3.0",
|
||||
"lodash": "^4.17.20",
|
||||
"moment": "^2.29.1",
|
||||
"node-notifier": "^8.0.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"query-string": "^6.13.5",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-infinite-scroller": "^1.2.4",
|
||||
"react-redux": "^7.2.1",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "3.4.3",
|
||||
|
||||
@@ -10,6 +10,7 @@ import client from "../graphql/GraphQLClient";
|
||||
import "../ipc/ipc-renderer-handler";
|
||||
import { checkUserSession } from "../redux/user/user.actions";
|
||||
import { selectCurrentUser } from "../redux/user/user.selectors";
|
||||
import "./App.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
body {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.imex-flex-row {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
|
||||
&__grow {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&__margin {
|
||||
margin: 0.2rem 0.2rem;
|
||||
}
|
||||
|
||||
&__margin-large {
|
||||
margin: 0.5rem 0.5rem;
|
||||
}
|
||||
|
||||
&__flex-space-around {
|
||||
justify-content: space-around;
|
||||
}
|
||||
}
|
||||
|
||||
.ellipses {
|
||||
display: inline-block; /* for em, a, span, etc (inline by default) */
|
||||
text-overflow: ellipsis;
|
||||
width: calc(95%);
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
||||
border-radius: 0.2rem;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 0.25rem;
|
||||
max-height: 0.25rem;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
border-radius: 0.2rem;
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3);
|
||||
background-color: #188fff;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
import React from "react";
|
||||
import Dinero from "dinero.js";
|
||||
export default function CurrencyFormatterAtom({ children, ...restProps }) {
|
||||
const m = Dinero({ amount: Math.round((children || 0) * 100) });
|
||||
return <div>{m.toFormat()}</div>;
|
||||
}
|
||||
23
src/components/atoms/error-result/error-result.atom.jsx
Normal file
23
src/components/atoms/error-result/error-result.atom.jsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Button, Result } from "antd";
|
||||
import React from "react";
|
||||
|
||||
export default function ErrorResultAtom({
|
||||
title,
|
||||
errorMessage,
|
||||
tryAgainCallback,
|
||||
}) {
|
||||
return (
|
||||
<Result
|
||||
status="500"
|
||||
title={title}
|
||||
subTitle={errorMessage}
|
||||
extra={
|
||||
tryAgainCallback ? (
|
||||
<Button type="primary" onClick={() => tryAgainCallback()}>
|
||||
Try Again
|
||||
</Button>
|
||||
) : null
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import { Tooltip } from "antd";
|
||||
import moment from "moment";
|
||||
import React from "react";
|
||||
|
||||
export default function TimeAgoFormatter(props) {
|
||||
const m = moment(props.children);
|
||||
return props.children ? (
|
||||
<Tooltip placement="top" title={m.format("MM/DD/YYY hh:mm A")}>
|
||||
{m.fromNow()}
|
||||
</Tooltip>
|
||||
) : null;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { Descriptions, Skeleton } from "antd";
|
||||
import React from "react";
|
||||
import CurrencyFormatterAtom from "../../atoms/currency-formatter/currency-formatter.atom";
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
|
||||
export default function JobsDetailDescriptionMolecule({ loading, job }) {
|
||||
if (loading) return <Skeleton active />;
|
||||
|
||||
if (!job) return <ErrorResultAtom title="Error displaying job data." />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Descriptions
|
||||
title={`${job.clm_no}${job.ins_co_nm ? ` | ${job.ins_co_nm}` : ""}`}
|
||||
bordered
|
||||
layout="vertical"
|
||||
column={{ xxl: 5, xl: 4, lg: 3, md: 3, sm: 2, xs: 1 }}
|
||||
>
|
||||
<Descriptions.Item label="Claim No.">{job.clm_no}</Descriptions.Item>
|
||||
<Descriptions.Item label="Ins Co. Nm.">
|
||||
{job.ins_co_nm}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Owner">{`${job.ownr_fn} ${job.ownr_ln}`}</Descriptions.Item>
|
||||
<Descriptions.Item label="Vehicle">{`${job.v_model_yr} ${job.v_makedesc} ${job.v_model}`}</Descriptions.Item>
|
||||
<Descriptions.Item label="Claim Total.">
|
||||
<CurrencyFormatterAtom>{job.clm_total}</CurrencyFormatterAtom>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import { Table } from "antd";
|
||||
import React from "react";
|
||||
import CurrencyFormatterAtom from "../../atoms/currency-formatter/currency-formatter.atom";
|
||||
|
||||
export default function JobLinesTableMolecule({ loading, jobLines }) {
|
||||
const columns = [
|
||||
{
|
||||
title: "#",
|
||||
dataIndex: "unq_seq",
|
||||
key: "unq_seq",
|
||||
},
|
||||
{
|
||||
title: "S#",
|
||||
dataIndex: "line_ind",
|
||||
key: "line_ind",
|
||||
},
|
||||
{
|
||||
title: "Line Description",
|
||||
dataIndex: "line_desc",
|
||||
key: "line_desc",
|
||||
},
|
||||
{
|
||||
title: "Part Type",
|
||||
dataIndex: "part_type",
|
||||
key: "part_type",
|
||||
},
|
||||
{
|
||||
title: "Part Number",
|
||||
dataIndex: "oem_partno",
|
||||
key: "oem_partno",
|
||||
},
|
||||
{
|
||||
title: "Database Price",
|
||||
dataIndex: "db_price",
|
||||
key: "db_price",
|
||||
|
||||
render: (text, record) => (
|
||||
<CurrencyFormatterAtom>{record.db_price}</CurrencyFormatterAtom>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Actual Price",
|
||||
dataIndex: "act_price",
|
||||
key: "act_price",
|
||||
|
||||
render: (text, record) => (
|
||||
<CurrencyFormatterAtom>{record.act_price}</CurrencyFormatterAtom>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: "Qty.",
|
||||
dataIndex: "part_qty",
|
||||
key: "part_qty",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
loading={loading}
|
||||
size="small"
|
||||
pagination={false}
|
||||
dataSource={jobLines}
|
||||
scroll={{
|
||||
x: true,
|
||||
//y: "40rem"
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Result } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { QUERY_JOB_BY_PK } from "../../../graphql/jobs.queries";
|
||||
import { selectSelectedJobId } from "../../../redux/application/application.selectors";
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
import JobsDetailDescriptionMolecule from "../../molecules/jobs-detail-description/jobs-detail-description.molecule";
|
||||
import JobsLinesTableMolecule from "../../molecules/jobs-lines-table/jobs-lines-table.molecule";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
selectedJobId: selectSelectedJobId,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function JobsDetailOrganism({ selectedJobId }) {
|
||||
const { loading, error, data } = useQuery(QUERY_JOB_BY_PK, {
|
||||
variables: { jobId: selectedJobId },
|
||||
skip: !selectedJobId,
|
||||
});
|
||||
|
||||
if (!selectedJobId) return <Result title="No job selected." />;
|
||||
if (error)
|
||||
return (
|
||||
<ErrorResultAtom
|
||||
title="Error fetching Job details.."
|
||||
errorMessage={JSON.stringify(error)}
|
||||
/>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<JobsDetailDescriptionMolecule
|
||||
loading={loading}
|
||||
job={data ? data.jobs_by_pk : null}
|
||||
/>
|
||||
<JobsLinesTableMolecule
|
||||
loading={loading}
|
||||
jobLines={data ? data.jobs_by_pk.joblines : []}
|
||||
/>
|
||||
{selectedJobId}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailOrganism);
|
||||
135
src/components/organisms/jobs-table/jobs-table.organism.jsx
Normal file
135
src/components/organisms/jobs-table/jobs-table.organism.jsx
Normal file
@@ -0,0 +1,135 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { List, Space, Spin, Typography } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import InfiniteScroll from "react-infinite-scroller";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { QUERY_ALL_JOBS_PAGINATED } from "../../../graphql/jobs.queries";
|
||||
import { setSelectedJobId } from "../../../redux/application/application.actions";
|
||||
import { selectSelectedJobId } from "../../../redux/application/application.selectors";
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
import TimeAgoFormatter from "../../atoms/time-ago-formatter/time-ago-formatter.atom";
|
||||
import "./jobs-table.organism.styles.scss";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
selectedJobId: selectSelectedJobId,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setSelectedJobId: (jobId) => dispatch(setSelectedJobId(jobId)),
|
||||
});
|
||||
|
||||
const limit = 20;
|
||||
export function JobsTableOrganism({ selectedJobId, setSelectedJobId }) {
|
||||
const [state, setState] = useState({ hasMore: true });
|
||||
|
||||
const { loading, error, data, fetchMore } = useQuery(
|
||||
QUERY_ALL_JOBS_PAGINATED,
|
||||
{
|
||||
variables: {
|
||||
offset: 0,
|
||||
limit: limit,
|
||||
order: [{ updated_at: "desc" }],
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const handleInfiniteOnLoad = (page) => {
|
||||
fetchMore({
|
||||
variables: {
|
||||
offset: limit * page,
|
||||
},
|
||||
updateQuery: (prev, { fetchMoreResult }) => {
|
||||
if (!fetchMoreResult) {
|
||||
console.log("No more results. Fetch More was empty.");
|
||||
setState({ ...state, hasMore: false });
|
||||
return prev;
|
||||
}
|
||||
|
||||
const newCache = Object.assign({}, prev, {
|
||||
jobs: [...prev.jobs, ...fetchMoreResult.jobs],
|
||||
});
|
||||
|
||||
if (
|
||||
newCache.jobs.length >= data &&
|
||||
data.jobs_aggregate.aggregate.count
|
||||
) {
|
||||
console.log("No more results.");
|
||||
setState({ ...state, hasMore: false });
|
||||
}
|
||||
|
||||
return newCache;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const handleSelect = (jobId) => {
|
||||
setSelectedJobId(jobId);
|
||||
};
|
||||
|
||||
if (error)
|
||||
return (
|
||||
<ErrorResultAtom
|
||||
title="Error fetching Jobs data."
|
||||
errorMessage={JSON.stringify(error)}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="jobs-list-infinite-container">
|
||||
<InfiniteScroll
|
||||
pageStart={0}
|
||||
loadMore={handleInfiniteOnLoad}
|
||||
hasMore={!loading && state.hasMore}
|
||||
useWindow={false}
|
||||
>
|
||||
<List
|
||||
dataSource={data ? data.jobs : []}
|
||||
renderItem={(item) => (
|
||||
<List.Item
|
||||
className="jobs-list-item"
|
||||
key={item.id}
|
||||
onClick={() => handleSelect(item.id)}
|
||||
>
|
||||
<div
|
||||
className={`jobs-list-item-content ${
|
||||
item.id === selectedJobId
|
||||
? "jobs-list-item-content-selected"
|
||||
: ""
|
||||
}`}
|
||||
>
|
||||
<div style={{ display: "flex" }}>
|
||||
<Typography.Title level={4} style={{ flex: 1 }}>
|
||||
{`${item.clm_no}${
|
||||
item.ins_co_nm ? ` | ${item.ins_co_nm}` : ""
|
||||
}`}
|
||||
</Typography.Title>
|
||||
<span className="job-list-last-updated-time">
|
||||
<TimeAgoFormatter>{item.updated_at}</TimeAgoFormatter>
|
||||
</span>
|
||||
</div>
|
||||
<Space>
|
||||
<span>{`${item.ownr_fn} ${item.ownr_ln}`}</span>
|
||||
<span>
|
||||
{`${item.v_model_yr} ${item.v_makedesc} ${item.v_model} ${item.v_vin}`}
|
||||
</span>
|
||||
</Space>
|
||||
</div>
|
||||
</List.Item>
|
||||
)}
|
||||
>
|
||||
{loading && state.hasMore && (
|
||||
<div>
|
||||
<Spin />
|
||||
</div>
|
||||
)}
|
||||
</List>
|
||||
</InfiniteScroll>
|
||||
</div>
|
||||
{`${data ? data.jobs.length : 0} jobs loaded. ${
|
||||
data ? data.jobs_aggregate.aggregate.count : 0
|
||||
} total jobs.`}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsTableOrganism);
|
||||
@@ -0,0 +1,26 @@
|
||||
.jobs-list-infinite-container {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
height: 95vh;
|
||||
}
|
||||
|
||||
.jobs-list-item {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.jobs-list-item-content {
|
||||
&-selected {
|
||||
border-left: 3px solid #1890ff;
|
||||
}
|
||||
|
||||
display: inline;
|
||||
margin: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
cursor: pointer;
|
||||
&:hover {
|
||||
background-color: #e6f7ff;
|
||||
}
|
||||
}
|
||||
@@ -1,33 +1,25 @@
|
||||
import { Button } from "antd";
|
||||
import { Col, Row } from "antd";
|
||||
import React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
const { ipcRenderer } = window;
|
||||
//const settings = window.require("electron-settings");
|
||||
import JobsTableOrganism from "../../organisms/jobs-table/jobs-table.organism";
|
||||
import JobsDetailOrganism from "../../organisms/jobs-detail/jobs-detail.organism";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export function JobsPage() {
|
||||
// useEffect(() => {
|
||||
// ipcRenderer.on("test-success", (event, obj) => {
|
||||
// console.log("Test Success", obj);
|
||||
// });
|
||||
|
||||
// // Cleanup the listener events so that memory leaks are avoided.
|
||||
// return function cleanup() {
|
||||
// ipcRenderer.removeAllListeners(
|
||||
// "test-success",
|
||||
// ipcTypes.default.filewatcher.startSuccess
|
||||
// );
|
||||
// };
|
||||
// }, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div>Welcome to your new react app. </div>
|
||||
<Button onClick={() => ipcRenderer.send("test")}>Send Test IPC</Button>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={10}>
|
||||
<JobsTableOrganism />
|
||||
</Col>
|
||||
|
||||
<Col span={14}>
|
||||
<JobsDetailOrganism />
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -24,3 +24,61 @@ export const INSERT_NEW_JOB = gql`
|
||||
// v_type
|
||||
// ]
|
||||
// }
|
||||
|
||||
export const QUERY_ALL_JOBS_PAGINATED = gql`
|
||||
query QUERY_ALL_JOBS_PAGINATED(
|
||||
$offset: Int
|
||||
$limit: Int
|
||||
$order: [jobs_order_by!]
|
||||
) {
|
||||
jobs(offset: $offset, limit: $limit, order_by: $order) {
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
v_vin
|
||||
v_model_yr
|
||||
v_model
|
||||
v_makedesc
|
||||
id
|
||||
ins_co_nm
|
||||
clm_no
|
||||
clm_total
|
||||
ro_number
|
||||
updated_at
|
||||
}
|
||||
jobs_aggregate {
|
||||
aggregate {
|
||||
count(distinct: true)
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const QUERY_JOB_BY_PK = gql`
|
||||
query QUERY_ALL_JOBS_PAGINATED($jobId: uuid!) {
|
||||
jobs_by_pk(id: $jobId) {
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
v_vin
|
||||
v_model_yr
|
||||
v_model
|
||||
v_makedesc
|
||||
id
|
||||
ins_co_nm
|
||||
clm_no
|
||||
clm_total
|
||||
ro_number
|
||||
updated_at
|
||||
joblines(order_by: { unq_seq: asc }) {
|
||||
id
|
||||
act_price
|
||||
db_price
|
||||
line_desc
|
||||
line_ind
|
||||
oem_partno
|
||||
part_qty
|
||||
part_type
|
||||
unq_seq
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -19,7 +19,13 @@ export const setWatcherStatus = (status) => ({
|
||||
type: ApplicationActionTypes.SET_WATCHER_STATUS,
|
||||
payload: status,
|
||||
});
|
||||
|
||||
export const setWatcherError = (error) => ({
|
||||
type: ApplicationActionTypes.SET_WATCHER_ERROR,
|
||||
payload: error,
|
||||
});
|
||||
|
||||
export const setSelectedJobId = (jobId) => ({
|
||||
type: ApplicationActionTypes.SET_SELECTED_JOB_ID,
|
||||
payload: jobId,
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ const INITIAL_STATE = {
|
||||
watcherStatus: "Not Started",
|
||||
watchedPaths: [],
|
||||
watcherError: null,
|
||||
selectedJobId: null,
|
||||
};
|
||||
|
||||
const applicationReducer = (state = INITIAL_STATE, action) => {
|
||||
@@ -32,6 +33,8 @@ const applicationReducer = (state = INITIAL_STATE, action) => {
|
||||
...state,
|
||||
watcherError: action.payload,
|
||||
};
|
||||
case ApplicationActionTypes.SET_SELECTED_JOB_ID:
|
||||
return { ...state, selectedJobId: action.payload };
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
|
||||
@@ -16,3 +16,7 @@ export const selectWatcherError = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.watcherError
|
||||
);
|
||||
export const selectSelectedJobId = createSelector(
|
||||
[selectApplication],
|
||||
(application) => application.selectedJobId
|
||||
);
|
||||
|
||||
@@ -4,5 +4,6 @@ const ApplicationActionTypes = {
|
||||
REMOVE_WATCHED_PATH: "REMOVE_WATCHED_PATH",
|
||||
SET_WATCHER_STATUS: "SET_WATCHER_STATUS",
|
||||
SET_WATCHER_ERROR: "SET_WATCHER_ERROR",
|
||||
SET_SELECTED_JOB_ID: "SET_SELECTED_JOB_ID",
|
||||
};
|
||||
export default ApplicationActionTypes;
|
||||
|
||||
@@ -7,7 +7,7 @@ import userReducer from "./user/user.reducer";
|
||||
const persistConfig = {
|
||||
key: "root",
|
||||
storage,
|
||||
blacklist: ["application"],
|
||||
blacklist: ["application", "user"],
|
||||
};
|
||||
|
||||
const rootReducer = combineReducers({
|
||||
|
||||
Reference in New Issue
Block a user