From 8b7b6bee932e6b391df756d99b6da9ee093aad07 Mon Sep 17 00:00:00 2001 From: ceddybi Date: Tue, 5 Mar 2024 16:04:52 -0500 Subject: [PATCH] env: prod / dev --- src/api/index.ts | 25 +- src/index.ts | 655 ++++++++++++++-------------- src/menu.ts | 135 ++++++ src/utils/state/index.ts | 7 + src/utils/state/state.interfaces.ts | 2 + 5 files changed, 492 insertions(+), 332 deletions(-) create mode 100644 src/menu.ts diff --git a/src/api/index.ts b/src/api/index.ts index 5caf543..950a9da 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,24 +1,26 @@ // api with axios +import axios, { AxiosInstance } from 'axios'; import { getResume, getState, setState } from "../utils/state"; import _get from "lodash/get"; -import axios from 'axios'; import { isEmpty } from "lodash"; -export const isDev = process.env.APP_DEV ? (process.env.APP_DEV.trim() == "true") : false; +export const getBaseUrl = (isDev: boolean) => { + return isDev ? "http://localhost:3001" : "https://www.algojobs.ca"; +}; -export const baseURL = isDev ? "http://localhost:3001" : "https://www.algojobs.ca"; -const api = axios.create({ - baseURL, -}); +export const getApiInstance = (isDev: boolean): AxiosInstance => { + const baseURL = getBaseUrl(isDev); + return axios.create({ + baseURL, + }); +}; interface IResponse { status: number; // data: any; }; - - interface GetAuth { access_token: string; refresh_token: string; @@ -33,6 +35,7 @@ interface GetAuthApiRes { export const getAuthApi = async (args: GetAuth): Promise => { let state = await getState(); + const api = getApiInstance(state.dev || false); try { const response = await api.post('/api/auth', args); if (response.status !== 200) { @@ -80,6 +83,7 @@ interface IMainResponse extends IResponse { export const getMainApi = async (): Promise => { try { const state = await getState(); + const api = getApiInstance(state.dev || false); const resume = await getResume(); const access_token = _get(state, "auth.access_token"); const refresh_token = _get(state, "auth.refresh_token"); @@ -122,6 +126,7 @@ export const getMainApi = async (): Promise => { export const getAppApi = async (): Promise => { try { const state = await getState(); + const api = getApiInstance(state.dev || false); const resume = await getResume(); const access_token = _get(state, "auth.access_token"); const refresh_token = _get(state, "auth.refresh_token"); @@ -170,6 +175,4 @@ export const getAppApi = async (): Promise => { // questions, // resume sections, -// settings - -export default api; \ No newline at end of file +// settings \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 0940e2c..7c4d054 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,7 +1,9 @@ +import "./menu"; + import { APPEVENTS, AppEvents } from './events'; import { AppJob, Application, BEState, addApplied, getAllQuestion, getResume, getState, readQuestion, saveQuestion, saveResume, setState } from "./utils/state"; import { BrowserWindow, app, dialog, ipcMain, session, shell } from 'electron'; -import { baseURL, getAuthApi, isDev } from './api'; +import { getAuthApi, getBaseUrl } from './api'; import { gotoAppPage, gotoMainPage } from './config/app'; import _get from 'lodash/get'; @@ -9,385 +11,396 @@ import packageJson from '../package.json'; import path from 'node:path'; import { updateElectronApp } from "update-electron-app"; -if (!isDev) { updateElectronApp() } - -const appName = packageJson.name; -const appEvents = AppEvents.Instance; // This allows TypeScript to pick up the magic constants that's auto-generated by Forge's Webpack // plugin that tells the Electron app where to look for the Webpack-bundled app code (depending on // whether you're running in development or production). declare const MAIN_WINDOW_WEBPACK_ENTRY: string; declare const MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY: string; -let mainWindow: BrowserWindow = null; -if (process.defaultApp) { - if (process.argv.length >= 2) { - app.setAsDefaultProtocolClient(appName, process.execPath, [path.resolve(process.argv[1])]) +const indexApp = async () => { + const state = await getState(); + + const isDev = state.dev || false; + + const baseURL = getBaseUrl(isDev); + + if (!isDev) { updateElectronApp() } + const appName = packageJson.name; + const appEvents = AppEvents.Instance; + + let mainWindow: BrowserWindow = null; + + if (process.defaultApp) { + if (process.argv.length >= 2) { + app.setAsDefaultProtocolClient(appName, process.execPath, [path.resolve(process.argv[1])]) + } + } else { + app.setAsDefaultProtocolClient(appName) } -} else { - app.setAsDefaultProtocolClient(appName) -} -const gotTheLock = app.requestSingleInstanceLock() + const gotTheLock = app.requestSingleInstanceLock() -const getAppAuth = async (urlLinking?: string) => { + const getAppAuth = async (urlLinking?: string) => { - let access_token, refresh_token; + let access_token, refresh_token; - try { - if (urlLinking) { - const urlObj = new URL(urlLinking); - access_token = urlObj.searchParams.get('access_token'); - refresh_token = urlObj.searchParams.get('refresh_token'); + try { + if (urlLinking) { + const urlObj = new URL(urlLinking); + access_token = urlObj.searchParams.get('access_token'); + refresh_token = urlObj.searchParams.get('refresh_token'); - } else { - const state = await getState(); - access_token = state.auth.access_token; - refresh_token = state.auth.refresh_token; - } + } else { + const state = await getState(); + access_token = state.auth.access_token; + refresh_token = state.auth.refresh_token; + } - if (access_token && refresh_token) { - const getAuth = await getAuthApi({ access_token, refresh_token }); - if (!getAuth) { - throw new Error("Error logging in"); + if (access_token && refresh_token) { + const getAuth = await getAuthApi({ access_token, refresh_token }); + if (!getAuth) { + throw new Error("Error logging in"); + } } } + catch (error) { + console.log("Error", error?.message); + dialog.showErrorBox(error.message || "Error opening app", "Please try again"); + } } - catch (error) { - console.log("Error", error?.message); - dialog.showErrorBox(error.message || "Error opening app", "Please try again"); + if (!gotTheLock) { + app.quit() + } else { + app.on('second-instance', async (event, commandLine, workingDirectory) => { + // Someone tried to run a second instance, we should focus our window. + if (mainWindow) { + if (mainWindow.isMinimized()) mainWindow.restore() + mainWindow.focus() + } + + const url = commandLine.pop().slice(0, -1); + if (url) { + await getAppAuth(url); + } + + }) + + app.on('open-url', async (event, url) => { + if (url) { + await getAppAuth(url); + } + }) } -} -if (!gotTheLock) { - app.quit() -} else { - app.on('second-instance', async (event, commandLine, workingDirectory) => { - // Someone tried to run a second instance, we should focus our window. - if (mainWindow) { - if (mainWindow.isMinimized()) mainWindow.restore() - mainWindow.focus() - } - const url = commandLine.pop().slice(0, -1); - if (url) { - await getAppAuth(url); - } + // Handle creating/removing shortcuts on Windows when installing/uninstalling. + if (require('electron-squirrel-startup')) { + app.quit(); + } - }) + const createWindow = (): void => { + // Create the browser window. + mainWindow = new BrowserWindow({ + icon: path.join(__dirname, `assets/icon.${process.platform === "win32" ? "ico" : "png"}`), + height: 700, + width: 1000, + webPreferences: { + preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, + nodeIntegration: true, + // devTools: !isDev, + }, + }); + + // and load the index.html of the app. + // mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY); + mainWindow.loadURL(baseURL + "/app"); + + // Open the DevTools. + if (isDev) { mainWindow.webContents.openDevTools() }; + }; - app.on('open-url', async (event, url) => { - if (url) { - await getAppAuth(url); - } - }) -} + // This method will be called when Electron has finished + // initialization and is ready to create browser windows. + // Some APIs can only be used after this event occurs. + app.on('ready', () => { + session.defaultSession.protocol.registerFileProtocol('static', (request, callback) => { + const fileUrl = request.url.replace('static://', ''); + const filePath = path.join(app.getAppPath(), '.webpack/renderer', fileUrl); + // console.log("filePath", filePath); + callback(filePath); + }); + createWindow(); + getAppAuth(); + }); -// Handle creating/removing shortcuts on Windows when installing/uninstalling. -if (require('electron-squirrel-startup')) { - app.quit(); -} + // Quit when all windows are closed, except on macOS. There, it's common + // for applications and their menu bar to stay active until the user quits + // explicitly with Cmd + Q. + app.on('window-all-closed', () => { + if (process.platform !== 'darwin') { + app.quit(); + } + }); -const createWindow = (): void => { - // Create the browser window. - mainWindow = new BrowserWindow({ - icon: path.join(__dirname, `assets/icon.${process.platform === "win32" ? "ico" : "png"}`), - height: 700, - width: 1000, - webPreferences: { - preload: MAIN_WINDOW_PRELOAD_WEBPACK_ENTRY, - nodeIntegration: true, - // devTools: !isDev, - }, + app.on('activate', () => { + // console.log("activate"); + // On OS X it's common to re-create a window in the app when the + // dock icon is clicked and there are no other windows open. + if (BrowserWindow.getAllWindows().length === 0) { + createWindow(); + } }); - // and load the index.html of the app. - // mainWindow.loadURL(MAIN_WINDOW_WEBPACK_ENTRY); - mainWindow.loadURL(baseURL + "/app"); - - // Open the DevTools. - if (isDev) { mainWindow.webContents.openDevTools() }; -}; - -// This method will be called when Electron has finished -// initialization and is ready to create browser windows. -// Some APIs can only be used after this event occurs. -app.on('ready', () => { - session.defaultSession.protocol.registerFileProtocol('static', (request, callback) => { - const fileUrl = request.url.replace('static://', ''); - const filePath = path.join(app.getAppPath(), '.webpack/renderer', fileUrl); - // console.log("filePath", filePath); - callback(filePath); + ipcMain.handle('settings:save', async (event, settings) => { + const state = await getState(); + const newSettings = { ...state.settings, ...settings }; + const newState = { ...state, settings: newSettings }; + await setState(newState); + return newState; }); - createWindow(); - getAppAuth(); -}); - -// Quit when all windows are closed, except on macOS. There, it's common -// for applications and their menu bar to stay active until the user quits -// explicitly with Cmd + Q. -app.on('window-all-closed', () => { - if (process.platform !== 'darwin') { - app.quit(); + + const setListStartStop = async (isStart: boolean) => { + const state = await getState(); + const newState = { ...state, isListRunning: isStart }; + await setState(newState); + return newState; } -}); -app.on('activate', () => { - // console.log("activate"); - // On OS X it's common to re-create a window in the app when the - // dock icon is clicked and there are no other windows open. - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); + ipcMain.handle('list:start', async (event, url) => { + await setListStartStop(true); + await gotoMainPage(url); + return true; + }); + + ipcMain.handle('list:stop', async (event) => { + await setListStartStop(false); + appEvents.emit(APPEVENTS.LIST_STOP); + return true; + }); + + const setAppStartStop = async (isStart: boolean) => { + const state = await getState(); + const newState: BEState = { ...state, isAppRunning: isStart, activeJob: null }; + await setState(newState); + return newState; } -}); -ipcMain.handle('settings:save', async (event, settings) => { - const state = await getState(); - const newSettings = { ...state.settings, ...settings }; - const newState = { ...state, settings: newSettings }; - await setState(newState); - return newState; -}); + appEvents.on(APPEVENTS.APP_START, async (job: AppJob) => { + // console.log("appEvents.on(APPEVENTS.APP_STOP", job); + await runApplying(job); + }); -const setListStartStop = async (isStart: boolean) => { - const state = await getState(); - const newState = { ...state, isListRunning: isStart }; - await setState(newState); - return newState; -} + async function runApplying(ondemandJob?: AppJob): Promise { + let jobs: AppJob[] = []; + let state: any = {}; + let activeJob: AppJob = null; + let cantRun = false; + try { + state = await getState(); + jobs = state.jobs; + activeJob = state.activeJob; + + cantRun = !!activeJob || !state.isAppRunning; + + if (cantRun) { + if (!ondemandJob) { + return null; + } + } -ipcMain.handle('list:start', async (event, url) => { - await setListStartStop(true); - await gotoMainPage(url); - return true; -}); + // console.log("startApplying", jobs.length); + const firstJob = ondemandJob ? ondemandJob : jobs[0]; -ipcMain.handle('list:stop', async (event) => { - await setListStartStop(false); - appEvents.emit(APPEVENTS.LIST_STOP); - return true; -}); + if (firstJob) { + await setState({ ...state, activeJob: firstJob }); + await gotoAppPage(firstJob); -const setAppStartStop = async (isStart: boolean) => { - const state = await getState(); - const newState: BEState = { ...state, isAppRunning: isStart, activeJob: null }; - await setState(newState); - return newState; -} + await new Promise((resolve, reject) => { + setTimeout(() => { + resolve(true); + }, 1000); + }); + } -appEvents.on(APPEVENTS.APP_START, async (job: AppJob) => { - // console.log("appEvents.on(APPEVENTS.APP_STOP", job); - await runApplying(job); -}); - -async function runApplying(ondemandJob?: AppJob): Promise { - let jobs: AppJob[] = []; - let state: any = {}; - let activeJob: AppJob = null; - let cantRun = false; - try { - state = await getState(); - jobs = state.jobs; - activeJob = state.activeJob; - - cantRun = !!activeJob || !state.isAppRunning; - - if (cantRun) { - if (!ondemandJob) { - return null; + } + catch (error) { + console.log("Error startApplying", error?.message); + return null; + + } finally { + const state = await getState(); + // get next job + const nextJob = state.jobs[1]; + if (nextJob && !cantRun) { + // console.log("nextJob", nextJob); + appEvents.emit(APPEVENTS.APP_START, null); } + } + } - // console.log("startApplying", jobs.length); - const firstJob = ondemandJob ? ondemandJob : jobs[0]; + ipcMain.handle('app:skip', async (event, app: Application) => { + if (!app) return; - if (firstJob) { - await setState({ ...state, activeJob: firstJob }); - await gotoAppPage(firstJob); + const jobId = _get(app, "job.id", ""); + const newState = await getState(); - await new Promise((resolve, reject) => { - setTimeout(() => { - resolve(true); - }, 1000); - }); + if (newState.skippedApps) { + if (newState.skippedApps.some((a) => a.job?.id === jobId)) { + return; + } + newState.skippedApps.push(app); + } else { + newState.skippedApps = [app]; } + newState.activeJob = null; - } - catch (error) { - console.log("Error startApplying", error?.message); - return null; + if (newState.jobs) { + newState.jobs = newState.jobs.filter((j) => j.id !== jobId); + } + + await setState(newState); + + appEvents.emit(APPEVENTS.APP_STOP, jobId); + + return newState; + }); + + ipcMain.handle('app:complete', async (event, app: Application) => { + if (!app) return; + const jobId = _get(app, "job.id", ""); + const newState = await addApplied(app.job); + const completedApps = newState.completedApps || []; + newState.skippedApps = (newState.skippedApps || []).filter((a) => a.job?.id !== app.job?.id); + if (!completedApps.some((a) => a.job?.id === jobId)) { + newState.completedApps = [...(completedApps), app]; + }; + await setState(newState); + appEvents.emit(APPEVENTS.APP_STOP, jobId); + return newState; + }); + + ipcMain.handle('app:start:ondemand', async (event, job) => { + // console.log("app:start"); + // await setAppStartStop(true); + appEvents.emit(APPEVENTS.APP_START, job); + return true; + }); + + ipcMain.handle('app:start', async (event) => { + // console.log("app:start"); + await setAppStartStop(true); + appEvents.emit(APPEVENTS.APP_START, null); + return true; + }); + + ipcMain.handle('app:stop', async (event, app: Application) => { + // console.log("app:stop"); + const jobId = _get(app, "job.id", ""); + await setAppStartStop(false); + appEvents.emit(APPEVENTS.APP_STOP, jobId); + return true; + }); - } finally { + ipcMain.handle('state', async (event) => { const state = await getState(); - // get next job - const nextJob = state.jobs[1]; - if (nextJob && !cantRun) { - // console.log("nextJob", nextJob); - appEvents.emit(APPEVENTS.APP_START, null); - } + return state; + }); - } -} + ipcMain.handle('state:set', async (event, newState: BEState) => { + const state = await setState(newState); + return state; + }); -ipcMain.handle('app:skip', async (event, app: Application) => { - if (!app) return; + ipcMain.handle('questions:read', async (event, question) => { + // console.log("questions:read", question); + const savedQuestion = await readQuestion(question as any); + return savedQuestion; + }); - const jobId = _get(app, "job.id", ""); - const newState = await getState(); - if (newState.skippedApps) { - if (newState.skippedApps.some((a) => a.job?.id === jobId)) { - return; - } - newState.skippedApps.push(app); - } else { - newState.skippedApps = [app]; - } - newState.activeJob = null; + ipcMain.handle('questions:getall', async (event) => { + const questions = await getAllQuestion(); + // console.log("questions:getall", questions.length); + return questions; + }); - if (newState.jobs) { - newState.jobs = newState.jobs.filter((j) => j.id !== jobId); - } + ipcMain.handle('questions:save', async (event, question) => { + // console.log("questions:save", question); + const savedQuestion = await saveQuestion(question as any); + return savedQuestion; + }); - await setState(newState); + ipcMain.handle('resume:get', async (event, question) => { + const savedResume = await getResume(); + return savedResume; + }); - appEvents.emit(APPEVENTS.APP_STOP, jobId); + ipcMain.handle('resume:save', async (event, resume) => { + const savedResume = await saveResume(resume as any); + return savedResume; + }); - return newState; -}); + ipcMain.handle('open:link', async (event, ogLink) => { + const link = `${baseURL}/signin/app`; + await shell.openExternal(link); + return true; + }); -ipcMain.handle('app:complete', async (event, app: Application) => { - if (!app) return; - const jobId = _get(app, "job.id", ""); - const newState = await addApplied(app.job); - const completedApps = newState.completedApps || []; - newState.skippedApps = (newState.skippedApps || []).filter((a) => a.job?.id !== app.job?.id); - if (!completedApps.some((a) => a.job?.id === jobId)) { - newState.completedApps = [...(completedApps), app]; - }; - await setState(newState); - appEvents.emit(APPEVENTS.APP_STOP, jobId); - return newState; -}); - -ipcMain.handle('app:start:ondemand', async (event, job) => { - // console.log("app:start"); - // await setAppStartStop(true); - appEvents.emit(APPEVENTS.APP_START, job); - return true; -}); - -ipcMain.handle('app:start', async (event) => { - // console.log("app:start"); - await setAppStartStop(true); - appEvents.emit(APPEVENTS.APP_START, null); - return true; -}); - -ipcMain.handle('app:stop', async (event, app: Application) => { - // console.log("app:stop"); - const jobId = _get(app, "job.id", ""); - await setAppStartStop(false); - appEvents.emit(APPEVENTS.APP_STOP, jobId); - return true; -}); - -ipcMain.handle('state', async (event) => { - const state = await getState(); - return state; -}); - -ipcMain.handle('state:set', async (event, newState: BEState) => { - const state = await setState(newState); - return state; -}); - -ipcMain.handle('questions:read', async (event, question) => { - // console.log("questions:read", question); - const savedQuestion = await readQuestion(question as any); - return savedQuestion; -}); - - -ipcMain.handle('questions:getall', async (event) => { - const questions = await getAllQuestion(); - // console.log("questions:getall", questions.length); - return questions; -}); - -ipcMain.handle('questions:save', async (event, question) => { - // console.log("questions:save", question); - const savedQuestion = await saveQuestion(question as any); - return savedQuestion; -}); - -ipcMain.handle('resume:get', async (event, question) => { - const savedResume = await getResume(); - return savedResume; -}); - -ipcMain.handle('resume:save', async (event, resume) => { - const savedResume = await saveResume(resume as any); - return savedResume; -}); - -ipcMain.handle('open:link', async (event, ogLink) => { - const link = `${baseURL}/signin/app`; - await shell.openExternal(link); - return true; -}); - -const setSpeed = async (isApp: boolean, value: number, setDefault = false) => { - const state = await getState(); - const newSettings = { ...state.settings }; + const setSpeed = async (isApp: boolean, value: number, setDefault = false) => { + const state = await getState(); + const newSettings = { ...state.settings }; + + if (setDefault) { + newSettings.speedApply = 500; + newSettings.speedJobs = 100; + const newState: BEState = { ...state, settings: newSettings }; + await setState(newState); + return newState; + }; - if (setDefault) { - newSettings.speedApply = 500; - newSettings.speedJobs = 100; + newSettings[isApp ? "speedApply" : "speedJobs"] = value; const newState: BEState = { ...state, settings: newSettings }; await setState(newState); return newState; - }; + } - newSettings[isApp ? "speedApply" : "speedJobs"] = value; - const newState: BEState = { ...state, settings: newSettings }; - await setState(newState); - return newState; -} + ipcMain.handle('change:speed', async (event, isAppSpeed) => { + const [isApp, speed] = isAppSpeed; + const speedSet = await setSpeed(isApp, speed); + return speedSet; + }); -ipcMain.handle('change:speed', async (event, isAppSpeed) => { - const [isApp, speed] = isAppSpeed; - const speedSet = await setSpeed(isApp, speed); - return speedSet; -}); + ipcMain.handle('speed:default', async (event,) => { + const resetSpeed = await setSpeed(null, null, true); + return resetSpeed; + }); + + ipcMain.handle('logout', async (event, ogLink) => { + const state = await getState(); + const newState = { ...state, auth: {} as any }; + await setState(newState); + return true; + }); -ipcMain.handle('speed:default', async (event,) => { - const resetSpeed = await setSpeed(null, null, true); - return resetSpeed; -}); + ipcMain.handle('events', async (event, args) => { + const { name, data } = args || {}; + if (!name || !data) return false; + appEvents.emit(name, data); + return true; + }); -ipcMain.handle('logout', async (event, ogLink) => { - const state = await getState(); - const newState = { ...state, auth: {} as any }; - await setState(newState); - return true; -}); - -ipcMain.handle('events', async (event, args) => { - const { name, data } = args || {}; - if(!name || !data) return false; - appEvents.emit(name, data); - return true; -}); - -ipcMain.handle('my-invokable-ipc', async (event, ...args) => { - const state = await getState(); - // const browser = await getBrowser(); - // const page = await browser.newPage(); - // console.log('args', { browser, page }); - - const newState = { ...state, count: state.count + 1 }; - await setState(newState); - return newState; -}) \ No newline at end of file + ipcMain.handle('my-invokable-ipc', async (event, ...args) => { + const state = await getState(); + // const browser = await getBrowser(); + // const page = await browser.newPage(); + // console.log('args', { browser, page }); + + const newState = { ...state, count: state.count + 1 }; + await setState(newState); + return newState; + }) +} + +indexApp(); diff --git a/src/menu.ts b/src/menu.ts new file mode 100644 index 0000000..72cb535 --- /dev/null +++ b/src/menu.ts @@ -0,0 +1,135 @@ +import { Menu, app } from 'electron'; +import { getState, setIsDev } from './utils/state'; + +const isMac = process.platform === 'darwin' + +const renderMenu = async () => { + const state = await getState(); + const isDev = state.dev; + const template = [ + // { role: 'appMenu' } + ...(isMac + ? [{ + label: app.name, + submenu: [ + { role: 'about' }, + { type: 'separator' }, + { role: 'services' }, + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideOthers' }, + { role: 'unhide' }, + { type: 'separator' }, + { role: 'quit' } + ] + }] + : []), + // { role: 'fileMenu' } + { + label: 'File', + submenu: [ + isMac ? { role: 'close' } : { role: 'quit' } + ] + }, + // { role: 'editMenu' } + { + label: 'Edit', + submenu: [ + { role: 'undo' }, + { role: 'redo' }, + { type: 'separator' }, + { role: 'cut' }, + { role: 'copy' }, + { role: 'paste' }, + ...(isMac + ? [ + { role: 'pasteAndMatchStyle' }, + { role: 'delete' }, + { role: 'selectAll' }, + { type: 'separator' }, + { + label: 'Speech', + submenu: [ + { role: 'startSpeaking' }, + { role: 'stopSpeaking' } + ] + } + ] + : [ + { role: 'delete' }, + { type: 'separator' }, + { role: 'selectAll' } + ]), + + { + label: 'Env', + submenu: [ + { + label: `Prod ${!isDev ? '✅' : ''}`, click: async () => { + await setIsDev(false); + app.relaunch(); + app.exit(); + } + }, + { + label: `Dev ${isDev ? '✅' : ''}`, click: async () => { + await setIsDev(true); + app.relaunch(); + app.exit(); + } + } + ] + } + ] + }, + // { role: 'viewMenu' } + { + label: 'View', + submenu: [ + { role: 'reload' }, + { role: 'forceReload' }, + { role: 'toggleDevTools' }, + { type: 'separator' }, + { role: 'resetZoom' }, + { role: 'zoomIn' }, + { role: 'zoomOut' }, + { type: 'separator' }, + { role: 'togglefullscreen' } + ] + }, + // { role: 'windowMenu' } + { + label: 'Window', + submenu: [ + { role: 'minimize' }, + { role: 'zoom' }, + ...(isMac + ? [ + { type: 'separator' }, + { role: 'front' }, + { type: 'separator' }, + { role: 'window' } + ] + : [ + { role: 'close' } + ]) + ] + }, + { + role: 'help', + submenu: [ + { + label: 'How to use AIJ', + click: async () => { + const { shell } = require('electron') + await shell.openExternal('https://www.algojobs.ca/how-to') + } + } + ] + } + ] + + const menu = Menu.buildFromTemplate(template as any) + Menu.setApplicationMenu(menu) +}; +renderMenu(); diff --git a/src/utils/state/index.ts b/src/utils/state/index.ts index 6bc9dd4..686d329 100644 --- a/src/utils/state/index.ts +++ b/src/utils/state/index.ts @@ -35,6 +35,13 @@ export function getAppDataPath() { } } +export const setIsDev = async (dev: boolean) => { + const state = await getState(); + const newState = { ...state, dev }; + await setState(newState); + return newState; +}; + export const getState = async (): Promise => { try { const statePath = getAppDataPath(); diff --git a/src/utils/state/state.interfaces.ts b/src/utils/state/state.interfaces.ts index 4ad432b..b42be96 100644 --- a/src/utils/state/state.interfaces.ts +++ b/src/utils/state/state.interfaces.ts @@ -50,6 +50,7 @@ export interface Application { }; export interface BEState { + dev: boolean; apps: Application[]; completedApps: Application[]; skippedApps: Application[]; @@ -57,6 +58,7 @@ export interface BEState { jobs: AppJob[]; activeJob: AppJob; applied: AppJob[]; + deletedJobs: AppJob[]; questions: QuestionAnswer[];