Added log rocket + analytics to ensure functionality
This commit is contained in:
32
electron/analytics.js
Normal file
32
electron/analytics.js
Normal file
@@ -0,0 +1,32 @@
|
||||
const { ipcMain } = require("electron");
|
||||
const { app } = require("electron");
|
||||
const log = require("electron-log");
|
||||
const Nucleus = require("nucleus-nodejs");
|
||||
const { default: ipcTypes } = require("../src/ipc.types");
|
||||
|
||||
Nucleus.init("5f91b569b95bac34eefdb63a", { debug: true });
|
||||
|
||||
Nucleus.setProps({
|
||||
version: app.getVersion().toString(),
|
||||
});
|
||||
|
||||
Nucleus.onError = (type, err) => {
|
||||
log.error(err);
|
||||
// type will either be uncaughtException, unhandledRejection or windowError
|
||||
};
|
||||
|
||||
ipcMain.on(ipcTypes.app.toMain.setUserName, (event, userName) => {
|
||||
Nucleus.appStarted();
|
||||
Nucleus.setUserId(userName);
|
||||
});
|
||||
|
||||
ipcMain.on(ipcTypes.app.toMain.track, (e, args) => {
|
||||
console.log("args", args);
|
||||
log.log("Received Tracking Request", args);
|
||||
const { event, ...eventDetails } = args;
|
||||
try {
|
||||
Nucleus.track(event, eventDetails);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
});
|
||||
@@ -8,6 +8,7 @@ const ipcTypes = require("../../src/ipc.types");
|
||||
const {
|
||||
NewNotification,
|
||||
} = require("../notification-wrapper/notification-wrapper");
|
||||
const Nucleus = require("nucleus-nodejs");
|
||||
|
||||
async function ImportJob(path) {
|
||||
const b = BrowserWindow.getAllWindows()[0];
|
||||
@@ -26,6 +27,7 @@ async function ImportJob(path) {
|
||||
});
|
||||
} else {
|
||||
log.info(`Ignored job. ${newJob.ERROR}`);
|
||||
Nucleus.track("IGNORE_JOB", { reason: newJob.ERROR });
|
||||
NewNotification({
|
||||
title: "Job Ignored",
|
||||
body: newJob.ERROR,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const { ipcMain } = require("electron");
|
||||
const Nucleus = require("nucleus-nodejs");
|
||||
const ipcTypes = require("../../src/ipc.types");
|
||||
const { ImportJob } = require("../decoder/decoder");
|
||||
const { GetListOfEstimates } = require("./file-scan");
|
||||
@@ -17,6 +18,7 @@ ipcMain.on(
|
||||
ipcMain.on(
|
||||
ipcTypes.default.fileScan.toMain.importJob,
|
||||
async (event, filePath) => {
|
||||
Nucleus.track("IMPORT_JOB_FROM_SCAN");
|
||||
await ImportJob(filePath);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -5,8 +5,11 @@ const log = require("electron-log");
|
||||
const fsPromises = fs.promises;
|
||||
const _ = require("lodash");
|
||||
const { DecodeEstimate } = require("../decoder/decoder");
|
||||
const Nucleus = require("nucleus-nodejs");
|
||||
|
||||
async function GetListOfEstimates() {
|
||||
Nucleus.track("SCAN_ALL_ESTIMATES");
|
||||
log.info("Scanning all local estimates..");
|
||||
const ListOfEnvFiles = await GetEnvFiles();
|
||||
const ListOfSummarizedEstimates = await ReadAllEstimates(ListOfEnvFiles);
|
||||
const FilteredListOfSummarizedEstimates = ListOfSummarizedEstimates.filter(
|
||||
|
||||
@@ -8,6 +8,7 @@ const {
|
||||
NewNotification,
|
||||
} = require("../notification-wrapper/notification-wrapper");
|
||||
const log = require("electron-log");
|
||||
const Nucleus = require("nucleus-nodejs");
|
||||
var watcher;
|
||||
|
||||
async function StartWatcher() {
|
||||
@@ -53,23 +54,24 @@ async function StartWatcher() {
|
||||
console.log("File", path, "has been added");
|
||||
HandleNewFile(path);
|
||||
})
|
||||
.on("addDir", function (path) {
|
||||
console.log("Directory", path, "has been added");
|
||||
})
|
||||
// .on("addDir", function (path) {
|
||||
// console.log("Directory", path, "has been added");
|
||||
// })
|
||||
.on("change", async function (path) {
|
||||
console.log("File", path, "has been changed");
|
||||
HandleNewFile(path);
|
||||
})
|
||||
.on("unlink", function (path) {
|
||||
console.log("File", path, "has been removed");
|
||||
})
|
||||
.on("unlinkDir", function (path) {
|
||||
console.log("Directory", path, "has been removed");
|
||||
})
|
||||
// .on("unlink", function (path) {
|
||||
// console.log("File", path, "has been removed");
|
||||
// })
|
||||
// .on("unlinkDir", function (path) {
|
||||
// console.log("Directory", path, "has been removed");
|
||||
// })
|
||||
.on("error", function (error) {
|
||||
console.log("Error happened", error);
|
||||
log.error("Error in Watcher", error);
|
||||
const b = BrowserWindow.getFocusedWindow();
|
||||
b.webContents.send(ipcTypes.fileWatcher.toRenderer.error, error);
|
||||
Nucleus.track("WATCHER_ERROR", error);
|
||||
})
|
||||
.on("ready", onWatcherReady)
|
||||
.on("raw", function (event, path, details) {
|
||||
@@ -81,14 +83,14 @@ async function StartWatcher() {
|
||||
}
|
||||
|
||||
function onWatcherReady() {
|
||||
console.log("Ready!");
|
||||
log.info("Watcher ready!");
|
||||
const b = BrowserWindow.getAllWindows()[0];
|
||||
b.webContents.send(ipcTypes.default.fileWatcher.toRenderer.startSuccess);
|
||||
NewNotification({
|
||||
title: "RPS Watcher Started",
|
||||
body: "Newly exported estimates will be automatically uploaded.",
|
||||
});
|
||||
console.log("Confirmed watched paths:", watcher.getWatched());
|
||||
log.info("Confirmed watched paths:", watcher.getWatched());
|
||||
}
|
||||
|
||||
async function StopWatcher() {
|
||||
@@ -107,5 +109,6 @@ exports.StopWatcher = StopWatcher;
|
||||
exports.watcher = watcher;
|
||||
|
||||
async function HandleNewFile(path) {
|
||||
Nucleus.track("IMPORT_JOB_FROM_WATCHER");
|
||||
await ImportJob(path);
|
||||
}
|
||||
|
||||
@@ -15,11 +15,13 @@ const { store } = require("./electron-store");
|
||||
const { autoUpdater } = require("electron-updater");
|
||||
const log = require("electron-log");
|
||||
const { default: logger } = require("redux-logger");
|
||||
const Nucleus = require("nucleus-nodejs");
|
||||
require("./ipc-main-handler");
|
||||
require("./analytics");
|
||||
|
||||
autoUpdater.logger = log;
|
||||
autoUpdater.logger.transports.file.level = "info";
|
||||
log.info("App starting...");
|
||||
log.info("App starting...", app.getVersion());
|
||||
|
||||
// Conditionally include the dev tools installer to load React Dev Tools
|
||||
let installExtension, REACT_DEVELOPER_TOOLS;
|
||||
@@ -247,6 +249,7 @@ autoUpdater.on("update-downloaded", (ev, info) => {
|
||||
console.log("Update downloaded; will install in 5 seconds");
|
||||
});
|
||||
autoUpdater.on("update-downloaded", (ev, info) => {
|
||||
Nucleus.track("UPDATE_DOWNLOADED", info);
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
dialog.showMessageBox(
|
||||
{
|
||||
|
||||
@@ -3,6 +3,7 @@ const { contextBridge, ipcRenderer } = require("electron");
|
||||
const log = require("electron-log");
|
||||
|
||||
//ipcRenderer.removeAllListeners();
|
||||
|
||||
contextBridge.exposeInMainWorld("logger", {
|
||||
info: (...msg) => {
|
||||
log.info(...msg);
|
||||
@@ -26,7 +27,7 @@ contextBridge.exposeInMainWorld("ipcRenderer", {
|
||||
// whitelist channels
|
||||
// let validChannels = ["toMain"];
|
||||
// if (validChannels.includes(channel)) {
|
||||
console.log("ipcRenderer Send", channel);
|
||||
log.info("[Main] ipcRenderer Send", channel);
|
||||
ipcRenderer.send(channel, data);
|
||||
//}
|
||||
},
|
||||
|
||||
156
package-lock.json
generated
156
package-lock.json
generated
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "imexrps",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
@@ -3318,6 +3318,11 @@
|
||||
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
|
||||
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
|
||||
},
|
||||
"arch": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/arch/-/arch-2.1.2.tgz",
|
||||
"integrity": "sha512-NTBIIbAfkJeIletyABbVtdPgeKfDafR+1mZV/AyyfC1UkVkp9iUjV+wwmqtUgphHYajbI86jejBJp5e+jkGTiQ=="
|
||||
},
|
||||
"are-we-there-yet": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
|
||||
@@ -9582,6 +9587,12 @@
|
||||
"loose-envify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"invert-kv": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.1.tgz",
|
||||
"integrity": "sha512-CYdFeFexxhv/Bcny+Q0BfOV+ltRlJcd4BBZBYFX/O0u4npJrgZtIcjokegtiSMAvlMTJ+Koq0GBCc//3bueQxw==",
|
||||
"optional": true
|
||||
},
|
||||
"ip": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
|
||||
@@ -11902,6 +11913,15 @@
|
||||
"resolved": "https://registry.npmjs.org/lazy-val/-/lazy-val-1.0.4.tgz",
|
||||
"integrity": "sha512-u93kb2fPbIrfzBuLjZE+w+fJbUUMhNDXxNmMfaqNgpfQf1CO5ZSe2LfsnBqVAk7i/2NF48OSoRj+Xe2VT+lE8Q=="
|
||||
},
|
||||
"lcid": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lcid/-/lcid-3.1.1.tgz",
|
||||
"integrity": "sha512-M6T051+5QCGLBQb8id3hdvIW8+zeFV2FyBGFS9IEK5H9Wt4MueD4bW1eWikpHgZp+5xR3l5c8pZUkQsIA0BFZg==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"invert-kv": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"left-pad": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz",
|
||||
@@ -12121,6 +12141,11 @@
|
||||
"resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.7.0.tgz",
|
||||
"integrity": "sha512-i2sY04nal5jDcagM3FMfG++T69GEEM8CYuOfeOIvmXzOIcwE9a/CJPR0MFM97pYMj/u10lzz7/zd7+qwhrBTqQ=="
|
||||
},
|
||||
"logrocket": {
|
||||
"version": "1.0.14",
|
||||
"resolved": "https://registry.npmjs.org/logrocket/-/logrocket-1.0.14.tgz",
|
||||
"integrity": "sha512-notwwiIiXOmWSKQDsW8UrFJPu81u9rd6YaIFBmx6uF0XtXXwNQ+Mvteh5WHdABWcQ2nN4I7QkQrCAocYDx7OVg=="
|
||||
},
|
||||
"long": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz",
|
||||
@@ -12193,6 +12218,15 @@
|
||||
"resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz",
|
||||
"integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA=="
|
||||
},
|
||||
"map-age-cleaner": {
|
||||
"version": "0.1.3",
|
||||
"resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
|
||||
"integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"p-defer": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"map-cache": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
|
||||
@@ -12246,6 +12280,25 @@
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
|
||||
},
|
||||
"mem": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/mem/-/mem-5.1.1.tgz",
|
||||
"integrity": "sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"map-age-cleaner": "^0.1.3",
|
||||
"mimic-fn": "^2.1.0",
|
||||
"p-is-promise": "^2.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"mimic-fn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"memory-fs": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
|
||||
@@ -12878,6 +12931,12 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node-machine-id": {
|
||||
"version": "1.1.12",
|
||||
"resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz",
|
||||
"integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==",
|
||||
"optional": true
|
||||
},
|
||||
"node-modules-regexp": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz",
|
||||
@@ -13047,6 +13106,77 @@
|
||||
"boolbase": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"nucleus-nodejs": {
|
||||
"version": "3.0.6",
|
||||
"resolved": "https://registry.npmjs.org/nucleus-nodejs/-/nucleus-nodejs-3.0.6.tgz",
|
||||
"integrity": "sha512-IpgQqBlU9QZebPAfQadSODQmoHPsSABAlkTNFtuO8tKv+072NQKeKN+1CUxY8Xe9WpyOhLjFuBGQE3TpC81Dcg==",
|
||||
"requires": {
|
||||
"arch": "^2.1.1",
|
||||
"conf": "^6.1.0",
|
||||
"node-machine-id": "^1.1.12",
|
||||
"os-locale": "^4.0.0",
|
||||
"ws": "^7.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"conf": {
|
||||
"version": "6.2.4",
|
||||
"resolved": "https://registry.npmjs.org/conf/-/conf-6.2.4.tgz",
|
||||
"integrity": "sha512-GjgyPRLo1qK1LR9RWAdUagqo+DP18f5HWCFk4va7GS+wpxQTOzfuKTwKOvGW2c01/YXNicAyyoyuSddmdkBzZQ==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ajv": "^6.10.2",
|
||||
"debounce-fn": "^3.0.1",
|
||||
"dot-prop": "^5.0.0",
|
||||
"env-paths": "^2.2.0",
|
||||
"json-schema-typed": "^7.0.1",
|
||||
"make-dir": "^3.0.0",
|
||||
"onetime": "^5.1.0",
|
||||
"pkg-up": "^3.0.1",
|
||||
"semver": "^6.2.0",
|
||||
"write-file-atomic": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"debounce-fn": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/debounce-fn/-/debounce-fn-3.0.1.tgz",
|
||||
"integrity": "sha512-aBoJh5AhpqlRoHZjHmOzZlRx+wz2xVwGL9rjs+Kj0EWUrL4/h4K7OD176thl2Tdoqui/AaA4xhHrNArGLAaI3Q==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"mimic-fn": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"mimic-fn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
|
||||
"optional": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "6.3.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
|
||||
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==",
|
||||
"optional": true
|
||||
},
|
||||
"write-file-atomic": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz",
|
||||
"integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"imurmurhash": "^0.1.4",
|
||||
"is-typedarray": "^1.0.0",
|
||||
"signal-exit": "^3.0.2",
|
||||
"typedarray-to-buffer": "^3.1.5"
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
|
||||
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA==",
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"num2fraction": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
|
||||
@@ -13387,6 +13517,17 @@
|
||||
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
|
||||
},
|
||||
"os-locale": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/os-locale/-/os-locale-4.0.0.tgz",
|
||||
"integrity": "sha512-HsSR1+2l6as4Wp2SGZxqLnuFHxVvh1Ir9pvZxyujsC13egZVe7P0YeBLN0ijQzM/twrO5To3ia3jzBXAvpMTEA==",
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"execa": "^1.0.0",
|
||||
"lcid": "^3.0.0",
|
||||
"mem": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
@@ -13407,6 +13548,12 @@
|
||||
"integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==",
|
||||
"dev": true
|
||||
},
|
||||
"p-defer": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
|
||||
"integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
|
||||
"optional": true
|
||||
},
|
||||
"p-each-series": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz",
|
||||
@@ -13420,6 +13567,12 @@
|
||||
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
|
||||
"integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
|
||||
},
|
||||
"p-is-promise": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
|
||||
"integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
|
||||
"optional": true
|
||||
},
|
||||
"p-limit": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
@@ -18691,7 +18844,6 @@
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
||||
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-typedarray": "^1.0.0"
|
||||
}
|
||||
|
||||
@@ -23,9 +23,11 @@
|
||||
"firebase": "^7.24.0",
|
||||
"graphql": "^15.3.0",
|
||||
"lodash": "^4.17.20",
|
||||
"logrocket": "^1.0.14",
|
||||
"moment": "^2.29.1",
|
||||
"node-notifier": "^8.0.0",
|
||||
"node-sass": "^4.14.1",
|
||||
"nucleus-nodejs": "^3.0.6",
|
||||
"query-string": "^6.13.6",
|
||||
"react": "^16.14.0",
|
||||
"react-dom": "^16.14.0",
|
||||
|
||||
@@ -5,18 +5,24 @@ import React, { useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { DELETE_JOB } from "../../../graphql/jobs.queries";
|
||||
import ipcTypes from "../../../ipc.types";
|
||||
import { setSelectedJobId } from "../../../redux/application/application.actions";
|
||||
const { ipcRenderer } = window;
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setSelectedJobId: (id) => dispatch(setSelectedJobId(id)),
|
||||
});
|
||||
|
||||
export function DeleteJobAtom({ setSelectedJobId, jobId }) {
|
||||
const [deleteJob] = useMutation(DELETE_JOB);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const handleDelete = async () => {
|
||||
setLoading(true);
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "DELETE_JOB",
|
||||
});
|
||||
const result = await deleteJob({
|
||||
variables: { jobId: jobId },
|
||||
});
|
||||
|
||||
@@ -2,13 +2,20 @@ import { useMutation } from "@apollo/client";
|
||||
import { message, Switch } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { UPDATE_JOB_LINE } from "../../../graphql/joblines.queries";
|
||||
const { log } = window;
|
||||
import ipcTypes from "../../../ipc.types";
|
||||
const { log, ipcRenderer } = window;
|
||||
|
||||
export default function IgnoreJobLineAtom({ ignore, lineId }) {
|
||||
export default function IgnoreJobLineAtom({ ignore, lineId, line_desc }) {
|
||||
const [updateJobLine] = useMutation(UPDATE_JOB_LINE);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const handleChange = async (checked) => {
|
||||
setLoading(true);
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "TOGGLE_IGNORE_LINE",
|
||||
line_desc: line_desc,
|
||||
ignore: checked,
|
||||
});
|
||||
|
||||
const result = await updateJobLine({
|
||||
variables: { lineId: lineId, line: { ignore: checked } },
|
||||
});
|
||||
|
||||
@@ -5,7 +5,10 @@ import React, { useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { UPDATE_JOB } from "../../../graphql/jobs.queries";
|
||||
import ipcTypes from "../../../ipc.types";
|
||||
import { selectBodyshop } from "../../../redux/user/user.selectors";
|
||||
const { ipcRenderer } = window;
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
@@ -15,11 +18,17 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobGroupMolecule);
|
||||
|
||||
export function JobGroupMolecule({ bodyshop, jobId, group }) {
|
||||
export function JobGroupMolecule({ bodyshop, jobId, group, job }) {
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [updateJob] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleMenuClick = async (value) => {
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "CHANGE_VEHICLE_GROUP",
|
||||
vehicle: `${job.v_model_yr} ${job.v_makedesc} ${job.v_model} (${job.v_type})`,
|
||||
oldGroup: group,
|
||||
newGroup: value.key,
|
||||
});
|
||||
setLoading(true);
|
||||
const result = await updateJob({
|
||||
variables: { jobId: jobId, job: { group: value.key } },
|
||||
|
||||
@@ -21,7 +21,7 @@ export default function JobsDetailDescriptionMolecule({ loading, job }) {
|
||||
<CurrencyFormatterAtom>{job.clm_total}</CurrencyFormatterAtom>
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Group">
|
||||
<JobGroupMolecule jobId={job.id} group={job.group} />
|
||||
<JobGroupMolecule jobId={job.id} group={job.group} job={job} />
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="Age">{job.v_age}</Descriptions.Item>
|
||||
<Descriptions.Item label="Close Date">
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
import { Input, Table } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import ipcTypes from "../../../ipc.types";
|
||||
import { alphaSort } from "../../../util/sorters";
|
||||
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";
|
||||
|
||||
const { ipcRenderer } = window;
|
||||
|
||||
export default function JobLinesTableMolecule({ loading, job }) {
|
||||
const [searchText, setSearchText] = useState("");
|
||||
|
||||
@@ -92,7 +95,11 @@ export default function JobLinesTableMolecule({ loading, job }) {
|
||||
],
|
||||
onFilter: (value, record) => value === record.ignore,
|
||||
render: (text, record) => (
|
||||
<IgnoreJobLine lineId={record.id} ignore={record.ignore} />
|
||||
<IgnoreJobLine
|
||||
lineId={record.id}
|
||||
ignore={record.ignore}
|
||||
line_desc={record.line_desc}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
@@ -111,6 +118,10 @@ export default function JobLinesTableMolecule({ loading, job }) {
|
||||
<Input.Search
|
||||
placeholder="Search"
|
||||
onSearch={(val) => {
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "JOB_LINES_SEARCH",
|
||||
query: val,
|
||||
});
|
||||
setSearchText(val);
|
||||
}}
|
||||
enterButton
|
||||
|
||||
@@ -1,10 +1,17 @@
|
||||
import { SearchOutlined } from "@ant-design/icons";
|
||||
import { Button, DatePicker, Form, Input } from "antd";
|
||||
import React from "react";
|
||||
import ipcTypes from "../../../ipc.types";
|
||||
const { ipcRenderer } = window;
|
||||
export default function JobsSearchFieldsMolecule({ callSearchQuery }) {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleFinish = (values) => {
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "SEARCH_JOBS",
|
||||
query: values.search,
|
||||
datesIncluded: !!values.dateRange,
|
||||
});
|
||||
callSearchQuery({
|
||||
variables: {
|
||||
search: values.search || "",
|
||||
|
||||
@@ -18,7 +18,6 @@ export function ReportingDatesMolecule({ queryReportingData }) {
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleFinish = (values) => {
|
||||
console.log("values", values);
|
||||
queryReportingData({
|
||||
startDate: values.dateRange[0],
|
||||
endDate: values.dateRange[1],
|
||||
|
||||
@@ -9,7 +9,6 @@ export default function ShopSettingsFormMolecule({ form, saveLoading }) {
|
||||
form.getFieldValue("groups") || []
|
||||
);
|
||||
const handleBlur = () => {
|
||||
console.log(form.getFieldValue("groups") || []);
|
||||
setGroupOptions(form.getFieldValue("groups") || []);
|
||||
};
|
||||
|
||||
|
||||
@@ -4,10 +4,11 @@ import React, { useEffect, useState } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { QUERY_BODYSHOP, UPDATE_SHOP } from "../../../graphql/bodyshop.queries";
|
||||
import ipcTypes from "../../../ipc.types";
|
||||
import { setBodyshop } from "../../../redux/user/user.actions";
|
||||
import ErrorResultAtom from "../../atoms/error-result/error-result.atom";
|
||||
import ShopSettingsFormMolecule from "../../molecules/shop-settings-form/shop-settings-form.molecule";
|
||||
|
||||
const { ipcRenderer } = window;
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
});
|
||||
@@ -15,10 +16,6 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
setBodyshop: (shop) => dispatch(setBodyshop(shop)),
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ShopSettingsOrganism);
|
||||
|
||||
export function ShopSettingsOrganism({ setBodyshop }) {
|
||||
const { loading, error, data } = useQuery(QUERY_BODYSHOP);
|
||||
@@ -32,6 +29,9 @@ export function ShopSettingsOrganism({ setBodyshop }) {
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setSaveLoading(true);
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "UPDATE_SHOP_DETAILS",
|
||||
});
|
||||
|
||||
const result = await updateBodyshop({
|
||||
variables: { id: data.bodyshops[0].id, shop: values },
|
||||
@@ -70,3 +70,8 @@ export function ShopSettingsOrganism({ setBodyshop }) {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ShopSettingsOrganism);
|
||||
|
||||
@@ -5,8 +5,10 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import ImEXOnlineLogo from "../../../assets/logo192.png";
|
||||
import { emailSignInStart } from "../../../redux/user/user.actions";
|
||||
import { sendPasswordReset } from "../../../redux/user/user.actions";
|
||||
import {
|
||||
selectLoginLoading,
|
||||
selectPasswordReset,
|
||||
selectSignInError,
|
||||
} from "../../../redux/user/user.selectors";
|
||||
import "./sign-in.page.styles.scss";
|
||||
@@ -14,20 +16,33 @@ import "./sign-in.page.styles.scss";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
signInError: selectSignInError,
|
||||
loginLoading: selectLoginLoading,
|
||||
passwordReset: selectPasswordReset,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
emailSignInStart: (email, password) =>
|
||||
dispatch(emailSignInStart({ email, password })),
|
||||
sendPasswordReset: (email) => dispatch(sendPasswordReset(email)),
|
||||
});
|
||||
|
||||
export function SignInPage({ emailSignInStart, signInError, loginLoading }) {
|
||||
export function SignInPage({
|
||||
emailSignInStart,
|
||||
signInError,
|
||||
loginLoading,
|
||||
sendPasswordReset,
|
||||
passwordReset,
|
||||
}) {
|
||||
const handleFinish = (values) => {
|
||||
const { email, password } = values;
|
||||
emailSignInStart(email, password);
|
||||
};
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const handleReset = () => {
|
||||
const email = form.getFieldValue("email");
|
||||
sendPasswordReset(email);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="login-container">
|
||||
<div className="login-logo-container">
|
||||
@@ -35,10 +50,16 @@ export function SignInPage({ emailSignInStart, signInError, loginLoading }) {
|
||||
<Typography.Title>ImEX RPS</Typography.Title>
|
||||
</div>
|
||||
<Form onFinish={handleFinish} form={form} size="large">
|
||||
<Form.Item name="email" rules={[{ required: true }]}>
|
||||
<Form.Item
|
||||
name="email"
|
||||
rules={[{ required: true, message: "Please enter a valid email." }]}
|
||||
>
|
||||
<Input prefix={<UserOutlined />} placeholder="Email" />
|
||||
</Form.Item>
|
||||
<Form.Item name="password" rules={[{ required: true }]}>
|
||||
<Form.Item
|
||||
name="password"
|
||||
rules={[{ required: true, message: "Please enter your password." }]}
|
||||
>
|
||||
<Input
|
||||
prefix={<LockOutlined />}
|
||||
type="password"
|
||||
@@ -46,7 +67,7 @@ export function SignInPage({ emailSignInStart, signInError, loginLoading }) {
|
||||
/>
|
||||
</Form.Item>
|
||||
{signInError ? (
|
||||
<Alert type="error" message={signInError.message} />
|
||||
<Alert type="error" message={signInError.messagePretty} />
|
||||
) : null}
|
||||
<Button
|
||||
className="login-btn"
|
||||
@@ -56,7 +77,21 @@ export function SignInPage({ emailSignInStart, signInError, loginLoading }) {
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
return (
|
||||
<Button
|
||||
className="login-btn"
|
||||
disabled={!form.getFieldValue("email")}
|
||||
onClick={handleReset}
|
||||
>
|
||||
Reset Password
|
||||
</Button>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Form>
|
||||
{passwordReset.error && <div>{passwordReset.error}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import "antd/dist/antd.css";
|
||||
import LogRocket from "logrocket";
|
||||
import React from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
import { Provider } from "react-redux";
|
||||
@@ -8,6 +9,7 @@ import App from "./App/App";
|
||||
import "./index.css";
|
||||
import { persistor, store } from "./redux/store";
|
||||
require("dotenv").config();
|
||||
LogRocket.init("imex/rps");
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
|
||||
@@ -7,6 +7,8 @@ exports.default = {
|
||||
app: {
|
||||
toMain: {
|
||||
setAcceptableInsCoNm: "setAcceptableInsCoNm",
|
||||
setUserName: "setUserName",
|
||||
track: "analytics_track",
|
||||
},
|
||||
},
|
||||
store: {
|
||||
|
||||
@@ -5,7 +5,7 @@ import client from "../graphql/GraphQLClient";
|
||||
import {
|
||||
INSERT_NEW_JOB,
|
||||
QUERY_JOB_BY_CLM_NO,
|
||||
UPDATE_JOB,
|
||||
UPDATE_JOB
|
||||
} from "../graphql/jobs.queries";
|
||||
import { QUERY_GROUPS_BY_MAKE_TYPE } from "../graphql/veh_group.queries";
|
||||
import { store } from "../redux/store";
|
||||
@@ -15,8 +15,6 @@ export async function UpsertEstimate(job) {
|
||||
const shopId = store.getState().user.bodyshop.id;
|
||||
logger.info("Beginning Upserting job from Renderer.");
|
||||
const parsedYr = parseInt(job.v_model_yr);
|
||||
console.log("UpsertEstimate -> parsedYr", parsedYr);
|
||||
|
||||
logger.info(
|
||||
moment(job.loss_date).year() -
|
||||
(parsedYr >= 0 ? 2000 + parsedYr : 1900 + parsedYr)
|
||||
@@ -50,13 +48,11 @@ export async function UpsertEstimate(job) {
|
||||
});
|
||||
delete job.joblines;
|
||||
|
||||
const updatedJob = await client.mutate({
|
||||
await client.mutate({
|
||||
mutation: UPDATE_JOB,
|
||||
variables: { jobId: existingJobs.data.jobs[0].id, job: job },
|
||||
});
|
||||
logger.info("Job updated succesfully.");
|
||||
|
||||
console.log("UpsertEstimate -> updatedJob", updatedJob);
|
||||
} else {
|
||||
logger.info("Attemping to insert job record.");
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { all, call, takeLatest, select, put } from "redux-saga/effects";
|
||||
import { all, call, put, select, takeLatest } from "redux-saga/effects";
|
||||
import GetJobTarget from "../../util/GetJobTarget";
|
||||
import { setSelectedJobTargetPcSuccess } from "./application.actions";
|
||||
import ApplicationActionTypes from "./application.types";
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
import { all, call, takeLatest, select, put } from "redux-saga/effects";
|
||||
import Dinero from "dinero.js";
|
||||
import { all, call, put, select, takeLatest } from "redux-saga/effects";
|
||||
import client from "../../graphql/GraphQLClient";
|
||||
import { REPORTING_GET_JOBS } from "../../graphql/reporting.queries";
|
||||
import ipcTypes from "../../ipc.types";
|
||||
import {
|
||||
CalculateJobRpsDollars,
|
||||
CalculateJobRpsPc
|
||||
} from "../../util/CalculateJobRps";
|
||||
import GetJobTarget from "../../util/GetJobTarget";
|
||||
import {
|
||||
calculateScorecard,
|
||||
setReportingData,
|
||||
setScoreCard,
|
||||
setScoreCard
|
||||
} from "./reporting.actions";
|
||||
import ReportingApplicationTypes from "./reporting.types";
|
||||
import client from "../../graphql/GraphQLClient";
|
||||
import { REPORTING_GET_JOBS } from "../../graphql/reporting.queries";
|
||||
import Dinero from "dinero.js";
|
||||
import {
|
||||
CalculateJobRpsDollars,
|
||||
CalculateJobRpsPc,
|
||||
} from "../../util/CalculateJobRps";
|
||||
import GetJobTarget from "../../util/GetJobTarget";
|
||||
|
||||
const { log } = window;
|
||||
const { log, ipcRenderer } = window;
|
||||
|
||||
export function* onQueryReportData() {
|
||||
yield takeLatest(
|
||||
@@ -52,71 +53,81 @@ export function* onCalculateScoreCard() {
|
||||
);
|
||||
}
|
||||
export function* handleCalculateScoreCard({ payload: jobs }) {
|
||||
console.log("jobs", jobs);
|
||||
const targets = yield select((state) => state.user.bodyshop.targets);
|
||||
try {
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "CALCULATE_SCORECARD",
|
||||
});
|
||||
|
||||
const scoreCard = {
|
||||
shopRpsTotalDollars: Dinero(),
|
||||
shopRpsExpectedDollars: Dinero(),
|
||||
varianceDollars: null,
|
||||
variancePc: 0,
|
||||
allJobsSumDbPrice: Dinero(),
|
||||
allJobsSumActPrice: Dinero(),
|
||||
currentRpsPc: 0,
|
||||
targetRpsPc: 0,
|
||||
};
|
||||
const targets = yield select((state) => state.user.bodyshop.targets);
|
||||
|
||||
//Get the RPS on a per job basis.
|
||||
jobs = jobs.map((job) => {
|
||||
const { actPriceSum, jobRpsDollars } = CalculateJobRpsDollars(job, true);
|
||||
const { dbPriceSum, jobRpsPc } = CalculateJobRpsPc(
|
||||
job,
|
||||
jobRpsDollars,
|
||||
true
|
||||
);
|
||||
const jobTarget = GetJobTarget(job.group, job.v_age, targets);
|
||||
scoreCard.shopRpsTotalDollars = scoreCard.shopRpsTotalDollars.add(
|
||||
jobRpsDollars
|
||||
);
|
||||
const expectedRpsDollars = dbPriceSum.percentage(jobTarget * 100);
|
||||
scoreCard.shopRpsExpectedDollars = scoreCard.shopRpsExpectedDollars.add(
|
||||
expectedRpsDollars
|
||||
);
|
||||
|
||||
scoreCard.allJobsSumDbPrice = scoreCard.allJobsSumDbPrice.add(dbPriceSum);
|
||||
scoreCard.allJobsSumActPrice = scoreCard.allJobsSumActPrice.add(
|
||||
actPriceSum
|
||||
);
|
||||
|
||||
//sum db price * percentage expected.
|
||||
return {
|
||||
...job,
|
||||
actPriceSum,
|
||||
jobRpsDollars,
|
||||
dbPriceSum,
|
||||
jobRpsPc,
|
||||
jobTarget,
|
||||
expectedRpsDollars,
|
||||
const scoreCard = {
|
||||
shopRpsTotalDollars: Dinero(),
|
||||
shopRpsExpectedDollars: Dinero(),
|
||||
varianceDollars: null,
|
||||
variancePc: 0,
|
||||
allJobsSumDbPrice: Dinero(),
|
||||
allJobsSumActPrice: Dinero(),
|
||||
currentRpsPc: 0,
|
||||
targetRpsPc: 0,
|
||||
};
|
||||
});
|
||||
|
||||
scoreCard.varianceDollars = scoreCard.shopRpsTotalDollars.subtract(
|
||||
scoreCard.shopRpsExpectedDollars
|
||||
);
|
||||
//Get the RPS on a per job basis.
|
||||
jobs = jobs.map((job) => {
|
||||
const { actPriceSum, jobRpsDollars } = CalculateJobRpsDollars(job, true);
|
||||
const { dbPriceSum, jobRpsPc } = CalculateJobRpsPc(
|
||||
job,
|
||||
jobRpsDollars,
|
||||
true
|
||||
);
|
||||
const jobTarget = GetJobTarget(job.group, job.v_age, targets);
|
||||
scoreCard.shopRpsTotalDollars = scoreCard.shopRpsTotalDollars.add(
|
||||
jobRpsDollars
|
||||
);
|
||||
const expectedRpsDollars = dbPriceSum.percentage(jobTarget * 100);
|
||||
scoreCard.shopRpsExpectedDollars = scoreCard.shopRpsExpectedDollars.add(
|
||||
expectedRpsDollars
|
||||
);
|
||||
|
||||
scoreCard.variancePc =
|
||||
scoreCard.varianceDollars.getAmount() /
|
||||
scoreCard.shopRpsExpectedDollars.getAmount();
|
||||
scoreCard.allJobsSumDbPrice = scoreCard.allJobsSumDbPrice.add(dbPriceSum);
|
||||
scoreCard.allJobsSumActPrice = scoreCard.allJobsSumActPrice.add(
|
||||
actPriceSum
|
||||
);
|
||||
|
||||
scoreCard.currentRpsPc =
|
||||
scoreCard.shopRpsTotalDollars.getAmount() /
|
||||
scoreCard.allJobsSumDbPrice.getAmount();
|
||||
scoreCard.targetRpsPc =
|
||||
scoreCard.shopRpsExpectedDollars.getAmount() /
|
||||
scoreCard.allJobsSumDbPrice.getAmount();
|
||||
//Set the data.
|
||||
yield put(setScoreCard(scoreCard));
|
||||
yield put(setReportingData(jobs));
|
||||
//sum db price * percentage expected.
|
||||
return {
|
||||
...job,
|
||||
actPriceSum,
|
||||
jobRpsDollars,
|
||||
dbPriceSum,
|
||||
jobRpsPc,
|
||||
jobTarget,
|
||||
expectedRpsDollars,
|
||||
};
|
||||
});
|
||||
|
||||
scoreCard.varianceDollars = scoreCard.shopRpsTotalDollars.subtract(
|
||||
scoreCard.shopRpsExpectedDollars
|
||||
);
|
||||
|
||||
scoreCard.variancePc =
|
||||
scoreCard.varianceDollars.getAmount() /
|
||||
scoreCard.shopRpsExpectedDollars.getAmount();
|
||||
|
||||
scoreCard.currentRpsPc =
|
||||
scoreCard.shopRpsTotalDollars.getAmount() /
|
||||
scoreCard.allJobsSumDbPrice.getAmount();
|
||||
scoreCard.targetRpsPc =
|
||||
scoreCard.shopRpsExpectedDollars.getAmount() /
|
||||
scoreCard.allJobsSumDbPrice.getAmount();
|
||||
//Set the data.
|
||||
yield put(setScoreCard(scoreCard));
|
||||
yield put(setReportingData(jobs));
|
||||
} catch (error) {
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "CALCULATE_SCORE_CARD_ERROR",
|
||||
error: error,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function* reportingSagas() {
|
||||
|
||||
@@ -47,7 +47,7 @@ const userReducer = (state = INITIAL_STATE, action) => {
|
||||
return {
|
||||
...state,
|
||||
currentUser: action.payload,
|
||||
loingLoading: false,
|
||||
loginLoading: false,
|
||||
error: null,
|
||||
};
|
||||
case UserActionTypes.SIGN_OUT_SUCCESS:
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { message } from "antd";
|
||||
import LogRocket from "logrocket";
|
||||
import { all, call, put, takeLatest } from "redux-saga/effects";
|
||||
import {
|
||||
auth,
|
||||
@@ -18,8 +20,6 @@ import {
|
||||
signOutSuccess,
|
||||
unauthorizedUser,
|
||||
updateUserDetailsSuccess,
|
||||
validatePasswordResetFailure,
|
||||
validatePasswordResetSuccess,
|
||||
} from "./user.actions";
|
||||
import UserActionTypes from "./user.types";
|
||||
|
||||
@@ -30,6 +30,10 @@ export function* onEmailSignInStart() {
|
||||
}
|
||||
export function* signInWithEmail({ payload: { email, password } }) {
|
||||
try {
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "SIGN_IN_ATTEMPT",
|
||||
email: email,
|
||||
});
|
||||
const { user } = yield auth.signInWithEmailAndPassword(email, password);
|
||||
|
||||
const result = yield client.mutate({
|
||||
@@ -50,13 +54,16 @@ export function* signInWithEmail({ payload: { email, password } }) {
|
||||
yield put(signInFailure(JSON.stringify(result.errors)));
|
||||
}
|
||||
} catch (error) {
|
||||
yield put(signInFailure(error));
|
||||
yield put(
|
||||
signInFailure({ ...error, messagePretty: ErrorFormatter(error.code) })
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function* onCheckUserSession() {
|
||||
yield takeLatest(UserActionTypes.CHECK_USER_SESSION, isUserAuthenticated);
|
||||
}
|
||||
|
||||
export function* isUserAuthenticated() {
|
||||
try {
|
||||
const user = yield getCurrentUser();
|
||||
@@ -78,9 +85,11 @@ export function* isUserAuthenticated() {
|
||||
yield put(signInFailure(error));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onSignOutStart() {
|
||||
yield takeLatest(UserActionTypes.SIGN_OUT_START, signOutStart);
|
||||
}
|
||||
|
||||
export function* signOutStart() {
|
||||
try {
|
||||
ipcRenderer.send(ipcTypes.default.fileWatcher.toMain.stop);
|
||||
@@ -112,7 +121,15 @@ export function* onSignInSuccess() {
|
||||
|
||||
export function* signInSuccessSaga({ payload }) {
|
||||
//Query for the Correct Bodyshop
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.setUserName, payload.email);
|
||||
LogRocket.identify(payload.email, {
|
||||
email: payload.email,
|
||||
});
|
||||
|
||||
ipcRenderer.send(ipcTypes.default.app.toMain.track, {
|
||||
event: "SIGN_IN_SUCCESS",
|
||||
email: payload.email,
|
||||
});
|
||||
const shop = yield client.query({ query: QUERY_BODYSHOP });
|
||||
if (shop.data.bodyshops.length > 0) {
|
||||
yield put(setBodyshop(shop.data.bodyshops[0]));
|
||||
@@ -138,32 +155,14 @@ export function* onSendPasswordResetStart() {
|
||||
}
|
||||
export function* sendPasswordResetEmail({ payload }) {
|
||||
try {
|
||||
yield auth.sendPasswordResetEmail(payload, {
|
||||
url: "https://imex.online/passwordreset",
|
||||
});
|
||||
yield auth.sendPasswordResetEmail(payload);
|
||||
|
||||
yield put(sendPasswordResetSuccess());
|
||||
message.success("Password reset sent succesfully.");
|
||||
} catch (error) {
|
||||
yield put(sendPasswordResetFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* onValidatePasswordResetStart() {
|
||||
yield takeLatest(
|
||||
UserActionTypes.VALIDATE_PASSWORD_RESET_START,
|
||||
validatePasswordResetStart
|
||||
);
|
||||
}
|
||||
export function* validatePasswordResetStart({ payload: { password, code } }) {
|
||||
try {
|
||||
yield auth.confirmPasswordReset(code, password);
|
||||
yield put(validatePasswordResetSuccess());
|
||||
} catch (error) {
|
||||
console.log("function*validatePasswordResetStart -> error", error);
|
||||
yield put(validatePasswordResetFailure(error.message));
|
||||
}
|
||||
}
|
||||
|
||||
export function* userSagas() {
|
||||
yield all([
|
||||
call(onEmailSignInStart),
|
||||
@@ -172,6 +171,18 @@ export function* userSagas() {
|
||||
call(onUpdateUserDetails),
|
||||
call(onSignInSuccess),
|
||||
call(onSendPasswordResetStart),
|
||||
call(onValidatePasswordResetStart),
|
||||
]);
|
||||
}
|
||||
|
||||
const ErrorFormatter = (code) => {
|
||||
switch (code) {
|
||||
case "auth/invalid-email":
|
||||
return "Please enter a valid email.";
|
||||
case "auth/user-not-found":
|
||||
return "A user does not exist with that email.";
|
||||
case "auth/wrong-password":
|
||||
return "The email or password is incorrect.";
|
||||
default:
|
||||
return code;
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user