Replaced electron-settings with store. Implemented job upsert logic.

This commit is contained in:
Patrick Fic
2020-10-15 15:18:38 -07:00
parent 67cae24b6c
commit e467f74362
18 changed files with 385 additions and 131 deletions

View File

@@ -7,10 +7,12 @@ import { createStructuredSelector } from "reselect";
import RoutesPage from "../components/pages/routes/routes.page";
import SignInPage from "../components/pages/sign-in/sign-in.page";
import client from "../graphql/GraphQLClient";
import ipcTypes from "../ipc.types";
import "../ipc/ipc-renderer-handler";
import { checkUserSession } from "../redux/user/user.actions";
import { selectCurrentUser } from "../redux/user/user.selectors";
import "./App.styles.scss";
const { ipcRenderer } = window;
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
@@ -24,6 +26,13 @@ export function App({ currentUser, checkUserSession }) {
checkUserSession();
}, [checkUserSession]);
useEffect(() => {
//
return () => {
ipcRenderer.send(ipcTypes.default.fileWatcher.toMain.stop);
};
}, []);
if (currentUser.authorized === null) {
return <Spin />;
}

View File

@@ -1,6 +1,17 @@
import { List } from "antd";
import React from "react";
import { DeleteFilled } from "@ant-design/icons";
import ipcTypes from "../../../ipc.types";
const { ipcRenderer } = window;
export default function FilePathMolecule(item, index) {
return <List.Item key={index}>{item}</List.Item>;
const handleClick = () => {
ipcRenderer.send(ipcTypes.default.fileWatcher.toMain.removePath, item);
};
return (
<List.Item key={index} actions={[<DeleteFilled onClick={handleClick} />]}>
{item}
</List.Item>
);
}

View File

@@ -1,5 +1,6 @@
import { SyncOutlined } from "@ant-design/icons";
import { useQuery } from "@apollo/client";
import { List, Space, Spin, Typography } from "antd";
import { Button, List, Space, Spin, Typography } from "antd";
import React, { useState } from "react";
import InfiniteScroll from "react-infinite-scroller";
import { connect } from "react-redux";
@@ -10,7 +11,6 @@ import { selectSelectedJobId } from "../../../redux/application/application.sele
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
import TimeAgoFormatter from "../../atoms/time-ago-formatter/time-ago-formatter.atom";
import "./jobs-list.organism.styles.scss";
const mapStateToProps = createStructuredSelector({
selectedJobId: selectSelectedJobId,
});
@@ -22,7 +22,7 @@ const limit = 20;
export function JobsTableOrganism({ selectedJobId, setSelectedJobId }) {
const [state, setState] = useState({ hasMore: true });
const { loading, error, data, fetchMore } = useQuery(
const { loading, error, data, refetch, fetchMore } = useQuery(
QUERY_ALL_JOBS_PAGINATED,
{
variables: {
@@ -76,6 +76,9 @@ export function JobsTableOrganism({ selectedJobId, setSelectedJobId }) {
return (
<div className="jobs-list-container">
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<div className="jobs-list-infinite-container">
<InfiniteScroll
pageStart={0}

View File

@@ -5,7 +5,6 @@ import { createStructuredSelector } from "reselect";
import ipcTypes from "../ipc.types";
const { ipcRenderer } = window.require("electron");
//const settings = window.require("electron-settings");
const mapStateToProps = createStructuredSelector({});
const mapDispatchToProps = (dispatch) => ({});

View File

@@ -82,3 +82,54 @@ export const QUERY_JOB_BY_PK = gql`
}
}
`;
export const QUERY_JOB_BY_CLM_NO = gql`
query QUERY_JOB_BY_CLM_NO($clm_no: String!) {
jobs(where: { clm_no: { _eq: $clm_no } }) {
id
joblines {
id
act_price
db_price
line_desc
line_ind
oem_partno
part_qty
part_type
unq_seq
}
}
}
`;
export const UPDATE_JOB = gql`
mutation UPDATE_JOB($jobId: uuid!, $job: jobs_set_input!) {
update_jobs(where: { id: { _eq: $jobId } }, _set: $job) {
returning {
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
}
}
}
}
`;

View File

@@ -10,6 +10,7 @@ exports.default = {
start: "filewatcher__start",
stop: "filewatcher__stop",
addPath: "filewatcher__addPath",
removePath: "filewatcher__removePath",
},
toRenderer: {
filepathsList: "filewatcher__filepathslist",

View File

@@ -1,16 +1,131 @@
import gql from "graphql-tag";
import _ from "lodash";
import client from "../graphql/GraphQLClient";
import { INSERT_NEW_JOB } from "../graphql/jobs.queries";
import {
INSERT_NEW_JOB,
QUERY_JOB_BY_CLM_NO,
UPDATE_JOB,
} from "../graphql/jobs.queries";
import { store } from "../redux/store";
export async function UpsertEstimate(job) {
const shopId = store.getState().user.bodyshop.id;
console.log("UpsertEstimate -> shopId", shopId);
const result = await client.mutate({
mutation: INSERT_NEW_JOB,
variables: {
job: { ...job, bodyshopid: shopId },
},
//Using the claim number, find out if the job exists. If it doesnt, then we need to create it.
const existingJobs = await client.query({
query: QUERY_JOB_BY_CLM_NO,
variables: { clm_no: job.clm_no },
});
console.log("UpsertEstimate -> result", result);
if (existingJobs.data.jobs.length === 1) {
let suppDelta = await GetSupplementDelta(
existingJobs.data.jobs[0].id,
existingJobs.data.jobs[0].joblines,
job.joblines.data
);
await client.mutate({
mutation: gql`
${suppDelta}
`,
});
delete job.joblines;
const updatedJob = await client.mutate({
mutation: UPDATE_JOB,
variables: { jobId: existingJobs.data.jobs[0].id, job: job },
});
console.log("UpsertEstimate -> updatedJob", updatedJob);
} else {
console.log("Insert a new job recort.", job);
const result = await client.mutate({
mutation: INSERT_NEW_JOB,
variables: {
job: { ...job, bodyshopid: shopId },
},
refetchQueries: ["QUERY_ALL_JOBS_PAGINATED"],
});
console.log("UpsertEstimate -> result", result);
}
}
export const GetSupplementDelta = async (jobId, existingLinesO, newLines) => {
const existingLines = _.cloneDeep(existingLinesO);
console.log("GetSupplementDelta -> newLines", newLines);
console.log("GetSupplementDelta -> existingLines", existingLines);
const linesToInsert = [];
const linesToUpdate = [];
newLines.forEach((newLine) => {
const matchingIndex = existingLines.findIndex(
(eL) => eL.unq_seq === newLine.unq_seq
);
if (matchingIndex >= 0) {
//Found a relevant matching line. Add it to lines to update.
linesToUpdate.push({
id: existingLines[matchingIndex].id,
newData: newLine,
});
//Splice out item we found for performance.
existingLines.splice(matchingIndex, 1);
} else {
//Didn't find a match. Must be a new line.
linesToInsert.push(newLine);
}
});
//Wahtever is left in the existing lines, are lines that should be removed.
const insertQueries = linesToInsert.reduce((acc, value, idx) => {
return acc + generateInsertQuery(value, idx, jobId);
}, "");
const updateQueries = linesToUpdate.reduce((acc, value, idx) => {
return acc + generateUpdateQuery(value, idx);
}, "");
const removeQueries = existingLines.reduce((acc, value, idx) => {
return acc + generateRemoveQuery(value, idx);
}, "");
return new Promise((resolve, reject) => {
resolve(gql`
mutation SUPPLEMENT_EST_LINES{
${insertQueries + updateQueries + removeQueries}
}
`);
});
};
const generateInsertQuery = (lineToInsert, index, jobId) => {
lineToInsert.jobid = jobId;
return `
insert_joblines${index}: insert_joblines(objects: ${JSON.stringify(
lineToInsert
).replace(/"(\w+)"\s*:/g, "$1:")}) {
returning {
id
}
}`;
};
const generateUpdateQuery = (lineToUpdate, index) => {
return `
update_joblines${index}: update_joblines(where: { id: { _eq: "${
lineToUpdate.id
}" } }, _set: ${JSON.stringify(lineToUpdate.newData).replace(
/"(\w+)"\s*:/g,
"$1:"
)}) {
returning {
id
}
}`;
};
const generateRemoveQuery = (lineToRemove, index) => {
return `
delete_joblines_r${index}: delete_joblines_by_pk(id: "${lineToRemove.id}") {
id
}`;
};

View File

@@ -4,7 +4,6 @@ import {
setWatcherStatus,
} from "../redux/application/application.actions";
import { store } from "../redux/store";
import { message } from "antd";
import { UpsertEstimate } from "./ipc-estimate-utils";
const { ipcRenderer } = window;
@@ -16,7 +15,7 @@ ipcRenderer.on("test-toRenderer", (event, obj) => {
ipcRenderer.on(
ipcTypes.default.fileWatcher.toRenderer.filepathsList,
(event, ...obj) => {
(event, obj) => {
store.dispatch(setWatchedPaths(obj));
}
);
@@ -24,37 +23,32 @@ ipcRenderer.on(
//Filewatcher Status Section
ipcRenderer.on(
ipcTypes.default.fileWatcher.toRenderer.startSuccess,
(event, ...obj) => {
console.log("Watcher ready.");
message.success("Watcher started!");
store.dispatch(setWatcherStatus("READY!"));
(event, obj) => {
store.dispatch(setWatcherStatus("Started"));
}
);
ipcRenderer.on(
ipcTypes.default.fileWatcher.toRenderer.stopSuccess,
(event, ...obj) => {
store.dispatch(setWatcherStatus("STOPPED"));
}
);
ipcRenderer.on(
ipcTypes.default.fileWatcher.toRenderer.error,
(event, ...obj) => {
store.dispatch(setWatcherStatus(obj));
(event, obj) => {
store.dispatch(setWatcherStatus("Stopped"));
}
);
ipcRenderer.on(ipcTypes.default.fileWatcher.toRenderer.error, (event, obj) => {
store.dispatch(setWatcherStatus(obj));
});
//Estimate Section
ipcRenderer.on(
ipcTypes.default.estimate.toRenderer.estimateDecodeStart,
(event, ...obj) => {
(event, obj) => {
console.log("Decoding started!");
}
);
ipcRenderer.on(
ipcTypes.default.estimate.toRenderer.estimateDecodeSuccess,
async (event, ...obj) => {
console.log("Decoding success!", obj[0]);
await UpsertEstimate(obj[0]);
async (event, obj) => {
console.log("obj", obj);
await UpsertEstimate(obj);
}
);

View File

@@ -81,6 +81,7 @@ export function* onSignOutStart() {
}
export function* signOutStart() {
try {
ipcRenderer.send(ipcTypes.default.fileWatcher.toMain.stop);
yield auth.signOut();
yield put(signOutSuccess());
localStorage.removeItem("token");