diff --git a/_reference/ems/MPI_1/3698420.ENV b/_reference/ems/MPI_1/3698420.ENV new file mode 100644 index 0000000..392749f Binary files /dev/null and b/_reference/ems/MPI_1/3698420.ENV differ diff --git a/_reference/ems/MPI_1/3698420.LIN b/_reference/ems/MPI_1/3698420.LIN new file mode 100644 index 0000000..de703f2 Binary files /dev/null and b/_reference/ems/MPI_1/3698420.LIN differ diff --git a/_reference/ems/MPI_1/3698420.PFH b/_reference/ems/MPI_1/3698420.PFH new file mode 100644 index 0000000..787eacc Binary files /dev/null and b/_reference/ems/MPI_1/3698420.PFH differ diff --git a/_reference/ems/MPI_1/3698420.PFL b/_reference/ems/MPI_1/3698420.PFL new file mode 100644 index 0000000..d97d93c Binary files /dev/null and b/_reference/ems/MPI_1/3698420.PFL differ diff --git a/_reference/ems/MPI_1/3698420.PFM b/_reference/ems/MPI_1/3698420.PFM new file mode 100644 index 0000000..5aaa152 Binary files /dev/null and b/_reference/ems/MPI_1/3698420.PFM differ diff --git a/_reference/ems/MPI_1/3698420.PFO b/_reference/ems/MPI_1/3698420.PFO new file mode 100644 index 0000000..c8a3ace Binary files /dev/null and b/_reference/ems/MPI_1/3698420.PFO differ diff --git a/_reference/ems/MPI_1/3698420.PFP b/_reference/ems/MPI_1/3698420.PFP new file mode 100644 index 0000000..42bff61 Binary files /dev/null and b/_reference/ems/MPI_1/3698420.PFP differ diff --git a/_reference/ems/MPI_1/3698420.PFT b/_reference/ems/MPI_1/3698420.PFT new file mode 100644 index 0000000..bcbb9c1 Binary files /dev/null and b/_reference/ems/MPI_1/3698420.PFT differ diff --git a/_reference/ems/MPI_1/3698420.STL b/_reference/ems/MPI_1/3698420.STL new file mode 100644 index 0000000..27f2d55 Binary files /dev/null and b/_reference/ems/MPI_1/3698420.STL differ diff --git a/_reference/ems/MPI_1/3698420.TTL b/_reference/ems/MPI_1/3698420.TTL new file mode 100644 index 0000000..b392bb1 Binary files /dev/null and b/_reference/ems/MPI_1/3698420.TTL differ diff --git a/_reference/ems/MPI_1/3698420.VEN b/_reference/ems/MPI_1/3698420.VEN new file mode 100644 index 0000000..bd56765 Binary files /dev/null and b/_reference/ems/MPI_1/3698420.VEN differ diff --git a/_reference/ems/MPI_1/3698420A.AD1 b/_reference/ems/MPI_1/3698420A.AD1 new file mode 100644 index 0000000..2333b75 Binary files /dev/null and b/_reference/ems/MPI_1/3698420A.AD1 differ diff --git a/_reference/ems/MPI_1/3698420A.dbt b/_reference/ems/MPI_1/3698420A.dbt new file mode 100644 index 0000000..dd431fe Binary files /dev/null and b/_reference/ems/MPI_1/3698420A.dbt differ diff --git a/_reference/ems/MPI_1/3698420B.AD2 b/_reference/ems/MPI_1/3698420B.AD2 new file mode 100644 index 0000000..b606e0b Binary files /dev/null and b/_reference/ems/MPI_1/3698420B.AD2 differ diff --git a/_reference/ems/MPI_1/3698420B.dbt b/_reference/ems/MPI_1/3698420B.dbt new file mode 100644 index 0000000..b2b5bc2 Binary files /dev/null and b/_reference/ems/MPI_1/3698420B.dbt differ diff --git a/_reference/ems/MPI_1/3698420V.VEH b/_reference/ems/MPI_1/3698420V.VEH new file mode 100644 index 0000000..37bb1cc Binary files /dev/null and b/_reference/ems/MPI_1/3698420V.VEH differ diff --git a/_reference/ems/MPI_1/3698420V.dbt b/_reference/ems/MPI_1/3698420V.dbt new file mode 100644 index 0000000..e367c32 Binary files /dev/null and b/_reference/ems/MPI_1/3698420V.dbt differ diff --git a/electron-builder.yml b/electron-builder.yml index e987354..21eeb04 100644 --- a/electron-builder.yml +++ b/electron-builder.yml @@ -18,8 +18,13 @@ nsis: shortcutName: ${productName} uninstallDisplayName: ${productName} createDesktopShortcut: always + azureSignOptions: + endpoint: https://eus.codesigning.azure.net + certificateProfileName: ImEXRPS + codeSigningAccountName: ImEX mac: entitlementsInherit: build/entitlements.mac.plist + category: public.app-category.business extendInfo: - NSCameraUsageDescription: Application requests access to the device's camera. - NSMicrophoneUsageDescription: Application requests access to the device's microphone. @@ -39,7 +44,8 @@ appImage: artifactName: ${name}-${version}.${ext} npmRebuild: false publish: - provider: generic - url: https://example.com/auto-updates + provider: s3 + bucket: bodyshop-desktop-updater + region: ca-central-1 electronDownload: mirror: https://npmmirror.com/mirrors/electron/ diff --git a/package-lock.json b/package-lock.json index 2df45fb..3751bc8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "@electron-toolkit/eslint-config-ts": "^3.0.0", "@electron-toolkit/tsconfig": "^1.0.1", "@playwright/test": "^1.51.0", + "@types/lodash": "^4.17.16", "@types/node": "^22.13.10", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", @@ -3312,6 +3313,13 @@ "@types/node": "*" } }, + "node_modules/@types/lodash": { + "version": "4.17.16", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", + "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", diff --git a/package.json b/package.json index 573c7fd..a853c1f 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@electron-toolkit/eslint-config-ts": "^3.0.0", "@electron-toolkit/tsconfig": "^1.0.1", "@playwright/test": "^1.51.0", + "@types/lodash": "^4.17.16", "@types/node": "^22.13.10", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", diff --git a/src/main/decoder/decode-ad1.interface.ts b/src/main/decoder/decode-ad1.interface.ts new file mode 100644 index 0000000..d83ca12 --- /dev/null +++ b/src/main/decoder/decode-ad1.interface.ts @@ -0,0 +1,147 @@ +interface ParsedAD1 { + // Insurance company information + ins_co_id?: string; + ins_co_nm?: string; + ins_addr1?: string; + ins_addr2?: string; + ins_city?: string; + ins_st?: string; + ins_zip?: string; + ins_ctry?: string; + ins_ea?: string; + ins_ph1?: string; + ins_ph1x?: string; + ins_ph2?: string; + ins_ph2x?: string; + ins_fax?: string; + ins_faxx?: string; + ins_ct_ln?: string; + ins_ct_fn?: string; + ins_title?: string; + ins_ct_ph?: string; + ins_ct_phx?: string; + + // Policy information + policy_no?: string; + ded_amt?: string; + ded_status?: string; + asgn_no?: string; + asgn_date?: string; + asgn_type?: string; + + // Claim information + clm_no?: string; + clm_ofc_id?: string; + clm_ofc_nm?: string; + clm_addr1?: string; + clm_addr2?: string; + clm_city?: string; + clm_st?: string; + clm_zip?: string; + clm_ctry?: string; + clm_ph1?: string; + clm_ph1x?: string; + clm_ph2?: string; + clm_ph2x?: string; + clm_fax?: string; + clm_faxx?: string; + clm_ct_ln?: string; + clm_ct_fn?: string; + clm_title?: string; + clm_ct_ph?: string; + clm_ct_phx?: string; + clm_ea?: string; + + // Payment information + payee_nms?: string; + pay_type?: string; + pay_date?: string; + pay_chknm?: string; + pay_amt?: string; + + // Agent information + agt_co_id?: string; + agt_co_nm?: string; + agt_addr1?: string; + agt_addr2?: string; + agt_city?: string; + agt_st?: string; + agt_zip?: string; + agt_ctry?: string; + agt_ph1?: string; + agt_ph1x?: string; + agt_ph2?: string; + agt_ph2x?: string; + agt_fax?: string; + agt_faxx?: string; + agt_ct_ln?: string; + agt_ct_fn?: string; + agt_ct_ph?: string; + agt_ct_phx?: string; + agt_ea?: string; + agt_lic_no?: string; + + // Loss information + loss_date?: string; + loss_type?: string; + loss_desc?: string; + theft_ind?: string; + cat_no?: string; + tlos_ind?: string; + cust_pr?: string; + loss_cat?: string; + + // Insured information + insd_ln?: string; + insd_fn?: string; + insd_title?: string; + insd_co_nm?: string; + insd_addr1?: string; + insd_addr2?: string; + insd_city?: string; + insd_st?: string; + insd_zip?: string; + insd_ctry?: string; + insd_ph1?: string; + insd_ph2?: string; + insd_fax?: string; + insd_faxx?: string; + insd_ea?: string; + + // Owner information + ownr_ln?: string; + ownr_fn?: string; + ownr_title?: string; + ownr_co_nm?: string; + ownr_addr1?: string; + ownr_addr2?: string; + ownr_city?: string; + ownr_st?: string; + ownr_zip?: string; + ownr_ctry?: string; + ownr_ph1?: string; + ownr_ph2?: string; + ownr_ea?: string; + + // Owner data object - referenced in the code + owner: { + data: OwnerRecordInterface; + }; +} + +interface OwnerRecordInterface { + ownr_ln: string; + ownr_fn: string; + ownr_title: string; + ownr_co_nm: string; + ownr_addr1: string; + ownr_addr2: string; + ownr_city: string; + ownr_st: string; + ownr_zip: string; + ownr_ctry: string; + ownr_ph1: string; + ownr_ph2: string; + ownr_ea: string; + shopid: string; +} diff --git a/src/main/decoder/decode-ad1.ts b/src/main/decoder/decode-ad1.ts new file mode 100644 index 0000000..69e2aa1 --- /dev/null +++ b/src/main/decoder/decode-ad1.ts @@ -0,0 +1,219 @@ +import { DBFFile } from "dbffile"; +import log from "electron-log/main"; +import _ from "lodash"; +import deepLowerCaseKeys from "../../util/deepLowercaseKeys"; + +const DecodeAD1 = async (extensionlessFilePath: string): Promise => { + let dbf; + try { + dbf = await DBFFile.open(`${extensionlessFilePath}A.AD1`); + } catch (error) { + log.error("Error opening AD1 File.", error); + dbf = await DBFFile.open(`${extensionlessFilePath}.AD1`); + log.log("Found AD1 file using regular CIECA Id."); + } + + if (!dbf) { + log.error(`Could not find any AD1 files at ${extensionlessFilePath}`); + return { + id: 0, + }; + } + + const rawDBFRecord = await dbf.readRecords(1); + + //AD1 will always have only 1 row. + //Commented lines have been cross referenced with existing partner fields. + + const rawAd1Data = deepLowerCaseKeys( + _.pick(rawDBFRecord[0], [ + //TODO: Add typings for EMS File Formats. + "INS_CO_ID", + "INS_CO_NM", + "INS_ADDR1", + "INS_ADDR2", + "INS_CITY", + "INS_ST", + "INS_ZIP", + "INS_CTRY", + "INS_EA", + "POLICY_NO", + "DED_AMT", + "DED_STATUS", + "ASGN_NO", + "ASGN_DATE", + "ASGN_TYPE", + "CLM_NO", + "CLM_OFC_ID", + "CLM_OFC_NM", + "CLM_ADDR1", + "CLM_ADDR2", + "CLM_CITY", + "CLM_ST", + "CLM_ZIP", + "CLM_CTRY", + "CLM_PH1", + "CLM_PH1X", + "CLM_PH2", + "CLM_PH2X", + "CLM_FAX", + "CLM_FAXX", + "CLM_CT_LN", + "CLM_CT_FN", + "CLM_TITLE", + "CLM_CT_PH", + "CLM_CT_PHX", + "CLM_EA", + "PAYEE_NMS", + "PAY_TYPE", + "PAY_DATE", + "PAY_CHKNM", + "PAY_AMT", + "AGT_CO_ID", + "AGT_CO_NM", + "AGT_ADDR1", + "AGT_ADDR2", + "AGT_CITY", + "AGT_ST", + "AGT_ZIP", + "AGT_CTRY", + "AGT_PH1", + "AGT_PH1X", + "AGT_PH2", + "AGT_PH2X", + "AGT_FAX", + "AGT_FAXX", + "AGT_CT_LN", + "AGT_CT_FN", + "AGT_CT_PH", + "AGT_CT_PHX", + "AGT_EA", + "AGT_LIC_NO", + "LOSS_DATE", + "LOSS_TYPE", + "LOSS_DESC", + "THEFT_IND", + "CAT_NO", + "TLOS_IND", + "CUST_PR", + "INSD_LN", + "INSD_FN", + "INSD_TITLE", + "INSD_CO_NM", + "INSD_ADDR1", + "INSD_ADDR2", + "INSD_CITY", + "INSD_ST", + "INSD_ZIP", + "INSD_CTRY", + "INSD_PH1", + //"INSD_PH1X", + "INSD_PH2", + //"INSD_PH2X", + "INSD_FAX", + "INSD_FAXX", + "INSD_EA", + "OWNR_LN", + "OWNR_FN", + "OWNR_TITLE", + "OWNR_CO_NM", + "OWNR_ADDR1", + "OWNR_ADDR2", + "OWNR_CITY", + "OWNR_ST", + "OWNR_ZIP", + "OWNR_CTRY", + "OWNR_PH1", + //"OWNR_PH1X", + "OWNR_PH2", + //"OWNR_PH2X", + //"OWNR_FAX", + //"OWNR_FAXX", + "OWNR_EA", + "INS_PH1", + "INS_PH1X", + "INS_PH2", + "INS_PH2X", + "INS_FAX", + "INS_FAXX", + "INS_CT_LN", + "INS_CT_FN", + "INS_TITLE", + "INS_CT_PH", + "INS_CT_PHX", + "LOSS_CAT", + ]) + ); + + //Copy specific logic for manipulation. + //If ownr_ph1 is missing, use ownr_ph2 + if (!rawAd1Data.ownr_ph1) { + rawAd1Data.ownr_ph1 = rawAd1Data.ownr_ph2; + } + + let ownerRecord: OwnerRecordInterface; + //Check if the owner information is there. If not, use the insured information as a fallback. + if ( + _.isEmpty(rawAd1Data.ownr_ln) && + _.isEmpty(rawAd1Data.ownr_fn) && + _.isEmpty(rawAd1Data.ownr_co_nm) + ) { + //They're all empty. Using the insured information as a fallback. + // //Build up the owner record to insert it alongside the job. + ownerRecord = { + ownr_ln: rawAd1Data.insd_ln, + ownr_fn: rawAd1Data.insd_fn, + ownr_title: rawAd1Data.insd_title, + ownr_co_nm: rawAd1Data.insd_co_nm, + ownr_addr1: rawAd1Data.insd_addr1, + ownr_addr2: rawAd1Data.insd_addr2, + ownr_city: rawAd1Data.insd_city, + ownr_st: rawAd1Data.insd_st, + ownr_zip: rawAd1Data.insd_zip, + ownr_ctry: rawAd1Data.insd_ctry, + ownr_ph1: rawAd1Data.insd_ph1, + ownr_ph2: rawAd1Data.insd_ph2, + ownr_ea: rawAd1Data.insd_ea, + + shopid: "UUID", //TODO: Need to add the shop uuid to this set of functions. + }; + } else { + //Use the owner information. + ownerRecord = { + ownr_ln: rawAd1Data.ownr_ln, + ownr_fn: rawAd1Data.ownr_fn, + ownr_title: rawAd1Data.ownr_title, + ownr_co_nm: rawAd1Data.ownr_co_nm, + ownr_addr1: rawAd1Data.ownr_addr1, + ownr_addr2: rawAd1Data.ownr_addr2, + ownr_city: rawAd1Data.ownr_city, + ownr_st: rawAd1Data.ownr_st, + ownr_zip: rawAd1Data.ownr_zip, + ownr_ctry: rawAd1Data.ownr_ctry, + ownr_ph1: rawAd1Data.ownr_ph1, + ownr_ph2: rawAd1Data.ownr_ph2, + ownr_ea: rawAd1Data.ownr_ea, + shopid: "UUID", + }; + } + + return { ...rawAd1Data, owner: { data: ownerRecord } }; +}; +export default DecodeAD1; + +interface OwnerRecordInterface { + ownr_ln: string; + ownr_fn: string; + ownr_title: string; + ownr_co_nm: string; + ownr_addr1: string; + ownr_addr2: string; + ownr_city: string; + ownr_st: string; + ownr_zip: string; + ownr_ctry: string; + ownr_ph1: string; + ownr_ph2: string; + ownr_ea: string; + shopid: string; +} diff --git a/src/main/decoder/decoder.ts b/src/main/decoder/decoder.ts new file mode 100644 index 0000000..2e23fd9 --- /dev/null +++ b/src/main/decoder/decoder.ts @@ -0,0 +1,19 @@ +import log from "electron-log/main"; +import path from "path"; +import DecodeAD1 from "./decode-ad1"; + +async function ImportJob(filepath: string): Promise { + const parsedFilePath = path.parse(filepath); + const extensionlessFilePath = path.join( + parsedFilePath.dir, + parsedFilePath.name + ); + log.debug("Importing Job", extensionlessFilePath); + + const decodedJob = {}; + + const ad1: ParsedAD1 = await DecodeAD1(extensionlessFilePath); + log.debug("AD1", ad1); +} + +export default ImportJob; diff --git a/src/main/index.test.ts b/src/main/index.test.ts index 083cb32..f80e836 100644 --- a/src/main/index.test.ts +++ b/src/main/index.test.ts @@ -1,7 +1,7 @@ import { _electron as electron } from "playwright"; import { test, expect } from "@playwright/test"; -test("example test", async () => { +test("Basic Electron app compilation.", async () => { const electronApp = await electron.launch({ args: ["."] }); const isPackaged = await electronApp.evaluate(async ({ app }) => { // This runs in Electron's main process, parameter here is always @@ -14,8 +14,6 @@ test("example test", async () => { // Wait for the first BrowserWindow to open // and return its Page object const window = await electronApp.firstWindow(); - await window.screenshot({ path: "intro.png" }); - // close app await electronApp.close(); }); diff --git a/src/main/index.ts b/src/main/index.ts index a2a5616..300a370 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -4,13 +4,23 @@ import log from "electron-log/main"; import { join } from "path"; import icon from "../../resources/icon.png?asset"; import ErrorTypeCheck from "../util/errorTypeCheck"; -import "./store/store"; +import store from "./store/store"; + log.initialize(); function createWindow(): void { // Create the browser window. + const { width, height, x, y } = store.get("app.windowBounds") as { + width: number; + height: number; + x: number | undefined; + y: number | undefined; + }; + const mainWindow = new BrowserWindow({ - width: 900, - height: 670, + width, + height, + x, + y, show: false, autoHideMenuBar: true, ...(process.platform === "linux" ? { icon } : {}), @@ -21,6 +31,17 @@ function createWindow(): void { }, }); + // Store window properties for later + const storeWindowState = (): void => { + const [width, height] = mainWindow.getSize(); + const [x, y] = mainWindow.getPosition(); + store.set("app.windowBounds", { width, height, x, y }); + }; + mainWindow.on("resized", storeWindowState); + mainWindow.on("maximize", storeWindowState); + mainWindow.on("unmaximize", storeWindowState); + mainWindow.on("moved", storeWindowState); + mainWindow.on("ready-to-show", () => { mainWindow.show(); }); diff --git a/src/main/ipc/ipcMainConfig.ts b/src/main/ipc/ipcMainConfig.ts index ccfae5a..0eaff7c 100644 --- a/src/main/ipc/ipcMainConfig.ts +++ b/src/main/ipc/ipcMainConfig.ts @@ -1,6 +1,8 @@ -import { ipcMain } from "electron"; +import { app, ipcMain } from "electron"; import log from "electron-log/main"; +import path from "path"; import ipcTypes from "../../util/ipcTypes.json"; +import ImportJob from "../decoder/decoder"; import { StartWatcher } from "../watcher/watcher"; import { SettingsWatchedFilePathsAdd, @@ -10,7 +12,7 @@ import { import { ipcMainHandleAuthStateChanged } from "./ipcMainHandler.user"; // Log all IPC messages and their payloads -const logIpcMessages = () => { +const logIpcMessages = (): void => { // Get all message types from ipcTypes.toMain Object.keys(ipcTypes.toMain).forEach((key) => { const messageType = ipcTypes.toMain[key]; @@ -42,6 +44,24 @@ ipcMain.on(ipcTypes.toMain.test, (payload: any) => //Auth handler ipcMain.on(ipcTypes.toMain.authStateChanged, ipcMainHandleAuthStateChanged); +//Add debug handlers if in development +if (import.meta.env.DEV) { + log.debug("[IPC Debug Functions] Adding Debug Handlers"); + + ipcMain.on( + ipcTypes.toMain.debug.decodeEstimate, + async (event, payload): Promise => { + const relativeEmsFilepath = `_reference/ems/MPI_1/3698420.ENV`; + // Get the app's root directory and create an absolute path + const rootDir = app.getAppPath(); + const absoluteFilepath = path.join(rootDir, relativeEmsFilepath); + + log.debug("[IPC Debug Function] Decode test Estimate", absoluteFilepath); + await ImportJob(absoluteFilepath); + } + ); +} + //Settings Handlers ipcMain.handle( ipcTypes.toMain.settings.filepaths.get, diff --git a/src/main/store/store.ts b/src/main/store/store.ts index 7ddde6c..997214c 100644 --- a/src/main/store/store.ts +++ b/src/main/store/store.ts @@ -11,7 +11,15 @@ const store = new Store({ pollingInterval: 30000, }, }, - user: null, + app: { + windowBounds: { + width: 800, + height: 600, + x: undefined, + y: undefined, + }, + user: null, + }, }, }); diff --git a/src/main/watcher/watcher.ts b/src/main/watcher/watcher.ts index a833ee3..eb8f0ee 100644 --- a/src/main/watcher/watcher.ts +++ b/src/main/watcher/watcher.ts @@ -4,8 +4,9 @@ import log from "electron-log/main"; import path from "path"; import errorTypeCheck from "../../util/errorTypeCheck"; import store from "../store/store"; +import ImportJob from "../decoder/decoder"; -var watcher: FSWatcher; +let watcher: FSWatcher; async function StartWatcher(): Promise { const filePaths = store.get("settings.filepaths") || []; @@ -34,8 +35,7 @@ async function StartWatcher(): Promise { watcher = chokidar.watch(filePaths, { ignored: (filepath, stats) => { const p = path.parse(filepath); - - return !stats?.isFile() && p.ext !== "" && p.ext.toUpperCase() !== ".ENV"; + return !stats?.isFile() && p.ext !== "" && p.ext.toUpperCase() !== ".ENV"; //Only watch for .ENV files. }, usePolling: store.get("settings.polling").enabled || false, interval: store.get("settings.polling").pollingInterval || 1000, @@ -77,7 +77,7 @@ async function StartWatcher(): Promise { return true; } -function onWatcherReady() { +function onWatcherReady(): void { log.info("Watcher ready!"); // const b = BrowserWindow.getAllWindows()[0]; // b.webContents.send(ipcTypes.default.fileWatcher.toRenderer.startSuccess); @@ -102,8 +102,8 @@ async function StopWatcher(): Promise { return false; } -async function HandleNewFile(path) { - //await ImportJob(path); +async function HandleNewFile(path): Promise { + await ImportJob(path); log.log("Received a new file", path); } diff --git a/src/renderer/src/App.tsx b/src/renderer/src/App.tsx index 225ab52..60dcfe0 100644 --- a/src/renderer/src/App.tsx +++ b/src/renderer/src/App.tsx @@ -11,6 +11,7 @@ import {} from "react-error-boundary"; import { ErrorBoundary } from "react-error-boundary"; import ErrorBoundaryFallback from "./components/ErrorBoundaryFallback/ErrorBoundaryFallback"; import Settings from "./components/Settings/Settings"; +import Home from "./components/Home/Home"; const App: React.FC = () => { const [user, setUser] = useState(null); @@ -36,7 +37,7 @@ const App: React.FC = () => { <> - AuthHome} /> + } /> } /> diff --git a/src/renderer/src/components/Home/Home.tsx b/src/renderer/src/components/Home/Home.tsx new file mode 100644 index 0000000..0b37986 --- /dev/null +++ b/src/renderer/src/components/Home/Home.tsx @@ -0,0 +1,21 @@ +import { Button } from "antd"; +import ipcTypes from "../../../../util/ipcTypes.json"; + +const Home: React.FC = () => { + return ( +
+

Home

+ +
+ ); +}; + +export default Home; diff --git a/src/renderer/src/components/Settings/Settings.WatchedPaths.tsx b/src/renderer/src/components/Settings/Settings.WatchedPaths.tsx index 282f7a6..a661306 100644 --- a/src/renderer/src/components/Settings/Settings.WatchedPaths.tsx +++ b/src/renderer/src/components/Settings/Settings.WatchedPaths.tsx @@ -16,7 +16,7 @@ const SettingsWatchedPaths: React.FC = () => { }); }, []); - const handleAddPath = () => { + const handleAddPath = (): void => { window.electron.ipcRenderer .invoke(ipcTypes.toMain.settings.filepaths.add) .then((paths: string[]) => { @@ -24,7 +24,7 @@ const SettingsWatchedPaths: React.FC = () => { }); }; - const handleRemovePath = (path: string) => { + const handleRemovePath = (path: string): void => { window.electron.ipcRenderer .invoke(ipcTypes.toMain.settings.filepaths.remove, path) .then((paths: string[]) => { diff --git a/src/util/deepLowercaseKeys.ts b/src/util/deepLowercaseKeys.ts new file mode 100644 index 0000000..9847d6e --- /dev/null +++ b/src/util/deepLowercaseKeys.ts @@ -0,0 +1,32 @@ +/** + * Deep renames all keys in an object to lowercase + * @param obj - The object to transform + * @returns A new object with all keys converted to lowercase + */ +function deepLowerCaseKeys(obj: any): T { + if (!obj || typeof obj !== "object") { + return obj; + } + + // Handle arrays + if (Array.isArray(obj)) { + return obj.map((item) => deepLowerCaseKeys(item)) as unknown as T; + } + + // Handle objects + return Object.keys(obj).reduce( + (result, key) => { + const value = obj[key]; + const lowercaseKey = key.toLowerCase(); + + result[lowercaseKey] = + typeof value === "object" && value !== null + ? deepLowerCaseKeys(value) + : value; + + return result; + }, + {} as Record + ) as T; +} +export default deepLowerCaseKeys; diff --git a/src/util/ipcTypes.json b/src/util/ipcTypes.json index bc1096c..3466e7f 100644 --- a/src/util/ipcTypes.json +++ b/src/util/ipcTypes.json @@ -2,6 +2,9 @@ "toMain": { "test": "toMain_test", "authStateChanged": "toMain_authStateChanged", + "debug": { + "decodeEstimate": "toMain_debug_decodeEstimate" + }, "watcher": { "start": "toMain_watcher_start", "stop": "toMain_watcher_stop"