From 46282a04061204594dadd825468b851f96c7b125 Mon Sep 17 00:00:00 2001 From: Sriram Hariharan Date: Sat, 4 Mar 2023 20:33:35 -0600 Subject: [PATCH] added deviceId, ExtensionStore, working on CoursePopup --- package-lock.json | 51 +++++++++++++++---- package.json | 3 +- src/background/background.ts | 6 +-- src/background/events/onInstall.ts | 21 +------- src/background/events/onUpdate.ts | 8 ++- src/background/handler/hotReloadingHandler.ts | 8 +-- .../storage/DevStore.ts} | 2 +- src/background/storage/ExtensionStore.ts | 31 +++++++++++ .../storage/OptionsStore.ts} | 2 +- .../storage/SessionStore.ts} | 2 +- src/background/util/hotReloadTab.ts | 4 +- src/background/util/openDebugTab.ts | 8 +-- src/debug/index.tsx | 6 +-- .../CoursePopup/CoursePopup.module.scss | 0 .../injected/CoursePopup/CoursePopup.tsx | 16 ++++++ 15 files changed, 119 insertions(+), 49 deletions(-) rename src/{shared/storage/devStore.ts => background/storage/DevStore.ts} (92%) create mode 100644 src/background/storage/ExtensionStore.ts rename src/{shared/storage/optionsStore.ts => background/storage/OptionsStore.ts} (88%) rename src/{shared/storage/sessionStore.ts => background/storage/SessionStore.ts} (80%) create mode 100644 src/views/components/injected/CoursePopup/CoursePopup.module.scss create mode 100644 src/views/components/injected/CoursePopup/CoursePopup.tsx diff --git a/package-lock.json b/package-lock.json index c1547496..14ce8ed0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,8 @@ "clean-webpack-plugin": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "sass": "^1.57.1" + "sass": "^1.57.1", + "uuid": "^9.0.0" }, "devDependencies": { "@semantic-release/exec": "^6.0.3", @@ -10027,6 +10028,15 @@ "which": "^2.0.2" } }, + "node_modules/node-notifier/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/node-releases": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.8.tgz", @@ -15272,6 +15282,15 @@ "websocket-driver": "^0.7.4" } }, + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/source-list-map": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", @@ -16683,10 +16702,9 @@ } }, "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==", "bin": { "uuid": "dist/bin/uuid" } @@ -24729,6 +24747,14 @@ "shellwords": "^0.1.1", "uuid": "^8.3.0", "which": "^2.0.2" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } } }, "node-releases": { @@ -28540,6 +28566,14 @@ "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" + }, + "dependencies": { + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true + } } }, "source-list-map": { @@ -29607,10 +29641,9 @@ "dev": true }, "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz", + "integrity": "sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==" }, "v8-compile-cache-lib": { "version": "3.0.1", diff --git a/package.json b/package.json index 3a05fe5d..c1abcb11 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "clean-webpack-plugin": "^4.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", - "sass": "^1.57.1" + "sass": "^1.57.1", + "uuid": "^9.0.0" }, "devDependencies": { "@semantic-release/exec": "^6.0.3", diff --git a/src/background/background.ts b/src/background/background.ts index a2a6abb9..f4e09b21 100644 --- a/src/background/background.ts +++ b/src/background/background.ts @@ -5,7 +5,7 @@ import onInstall from './events/onInstall'; import onNewChromeSession from './events/onNewChromeSession'; import onServiceWorkerAlive from './events/onServiceWorkerAlive'; import onUpdate from './events/onUpdate'; -import { sessionStore } from '../shared/storage/sessionStore'; +import { SessionStore } from './storage/SessionStore'; import browserActionHandler from './handler/browserActionHandler'; import hotReloadingHandler from './handler/hotReloadingHandler'; import tabManagementHandler from './handler/tabManagementHandler'; @@ -38,9 +38,9 @@ const messageListener = new MessageListener({ messageListener.listen(); -sessionStore.getChromeSessionId().then(async chromeSessionId => { +SessionStore.getChromeSessionId().then(async chromeSessionId => { if (!chromeSessionId) { - await sessionStore.setChromeSessionId(generateRandomId(10)); + await SessionStore.setChromeSessionId(generateRandomId(10)); onNewChromeSession(); } }); diff --git a/src/background/events/onInstall.ts b/src/background/events/onInstall.ts index 2863b997..010f2084 100644 --- a/src/background/events/onInstall.ts +++ b/src/background/events/onInstall.ts @@ -1,26 +1,9 @@ import { SECOND } from 'src/shared/util/time'; +import { ExtensionStore } from '../storage/ExtensionStore'; /** * Called when the extension is first installed or synced onto a new machine */ export default async function onInstall() { - // set the uninstall url - chrome.runtime.setUninstallURL('https://www.google.com'); - logOnInstallEvent(); -} - -/** - * making sure we are not sending duplicate install event for users that have synced browsers - * sync storage get's cleared on browser uninstall, so re-installing the browser will trigger the event - */ -function logOnInstallEvent() { - setTimeout(async () => { - const manifest = chrome.runtime.getManifest(); - const INSTALL_KEY = `${manifest.short_name}-installed`; - const storage = await chrome.storage.sync.get(INSTALL_KEY); - if (!storage[INSTALL_KEY]) { - // TODO: send install event - await chrome.storage.sync.set({ [INSTALL_KEY]: true }); - } - }, 5 * SECOND); + await ExtensionStore.setVersion(chrome.runtime.getManifest().version); } diff --git a/src/background/events/onUpdate.ts b/src/background/events/onUpdate.ts index f7436ee7..9d8c7d23 100644 --- a/src/background/events/onUpdate.ts +++ b/src/background/events/onUpdate.ts @@ -1,9 +1,15 @@ import { hotReloadTab } from 'src/background/util/hotReloadTab'; +import { ExtensionStore } from '../storage/ExtensionStore'; /** * Called when the extension is updated (or when the extension is reloaded in development mode) */ -export default function onUpdate() { +export default async function onUpdate() { + await Promise.all([ + ExtensionStore.setLastUpdate(Date.now()), + ExtensionStore.setVersion(chrome.runtime.getManifest().version), + ]); + if (process.env.NODE_ENV === 'development') { hotReloadTab(); } diff --git a/src/background/handler/hotReloadingHandler.ts b/src/background/handler/hotReloadingHandler.ts index c0edff0f..193ff4f6 100644 --- a/src/background/handler/hotReloadingHandler.ts +++ b/src/background/handler/hotReloadingHandler.ts @@ -1,18 +1,18 @@ import HotReloadingMessages from 'src/shared/messages/HotReloadingMessages'; import { MessageHandler } from 'chrome-extension-toolkit'; -import { devStore } from 'src/shared/storage/devStore'; +import { DevStore } from 'src/background/storage/DevStore'; const hotReloadingHandler: MessageHandler = { async reloadExtension({ sendResponse }) { - const isExtensionReloading = await devStore.getIsExtensionReloading(); + const isExtensionReloading = await DevStore.getIsExtensionReloading(); if (!isExtensionReloading) return sendResponse(); - const isTabReloading = await devStore.getIsExtensionReloading(); + const isTabReloading = await DevStore.getIsExtensionReloading(); if (isTabReloading) { const tabs = await chrome.tabs.query({ active: true, currentWindow: true }); const tabToReload = tabs[0]; - await devStore.setReloadTabId(tabToReload?.id); + await DevStore.setReloadTabId(tabToReload?.id); } chrome.runtime.reload(); }, diff --git a/src/shared/storage/devStore.ts b/src/background/storage/DevStore.ts similarity index 92% rename from src/shared/storage/devStore.ts rename to src/background/storage/DevStore.ts index 1705e7d8..81c83a6a 100644 --- a/src/shared/storage/devStore.ts +++ b/src/background/storage/DevStore.ts @@ -16,7 +16,7 @@ interface IDevStore { reloadTabId?: number; } -export const devStore = createStore('DEV_STORE', { +export const DevStore = createStore('DEV_STORE', { debugTabId: undefined, isTabReloading: true, wasDebugTabVisible: false, diff --git a/src/background/storage/ExtensionStore.ts b/src/background/storage/ExtensionStore.ts new file mode 100644 index 00000000..843a171f --- /dev/null +++ b/src/background/storage/ExtensionStore.ts @@ -0,0 +1,31 @@ +import { v4 as uuidv4 } from 'uuid'; +import { createStore } from 'chrome-extension-toolkit'; + +/** + * A store that is used for storing user options + */ +interface IExtensionStore { + /** These values are cached in storage, so that we can know the previous version that the extension was before the current update. Is only used for onUpdate */ + version: string; + /** When was the last update */ + lastUpdate: number; + /** A unique identifier generated for the current user in lieu of a userId */ + deviceId: string; +} + +const base = createStore('EXTENSION_STORE', { + version: chrome.runtime.getManifest().version, + lastUpdate: Date.now(), + deviceId: '', +}); + +export const ExtensionStore = base.modify({ + async getDeviceId() { + const deviceId = await base.getDeviceId(); + if (deviceId) { + return deviceId; + } + const newDeviceId = uuidv4(); + return newDeviceId; + }, +}); diff --git a/src/shared/storage/optionsStore.ts b/src/background/storage/OptionsStore.ts similarity index 88% rename from src/shared/storage/optionsStore.ts rename to src/background/storage/OptionsStore.ts index 69a550e2..74523067 100644 --- a/src/shared/storage/optionsStore.ts +++ b/src/background/storage/OptionsStore.ts @@ -10,7 +10,7 @@ interface IOptionsStore { shouldScrollToLoad: boolean; } -export const optionsStore = createStore('OPTIONS_STORE', { +export const OptionsStore = createStore('OPTIONS_STORE', { shouldHighlightConflicts: true, shouldScrollToLoad: true, }); diff --git a/src/shared/storage/sessionStore.ts b/src/background/storage/SessionStore.ts similarity index 80% rename from src/shared/storage/sessionStore.ts rename to src/background/storage/SessionStore.ts index ede5d30e..71b666a9 100644 --- a/src/shared/storage/sessionStore.ts +++ b/src/background/storage/SessionStore.ts @@ -4,7 +4,7 @@ interface ISessionStore { chromeSessionId?: string; } -export const sessionStore = createStore( +export const SessionStore = createStore( 'SESSION_STORE', { chromeSessionId: undefined, diff --git a/src/background/util/hotReloadTab.ts b/src/background/util/hotReloadTab.ts index 5e6cdef5..29b0b83a 100644 --- a/src/background/util/hotReloadTab.ts +++ b/src/background/util/hotReloadTab.ts @@ -1,4 +1,4 @@ -import { devStore } from 'src/shared/storage/devStore'; +import { DevStore } from 'src/background/storage/DevStore'; /** * A list of websites that we don't want to reload when the extension reloads (becuase it'd be hella annoying lmao) @@ -24,7 +24,7 @@ const HOT_RELOADING_WHITELIST = [ * @returns a promise that resolves when the tab is reloaded */ export async function hotReloadTab(): Promise { - const { getIsTabReloading, getReloadTabId } = devStore; + const { getIsTabReloading, getReloadTabId } = DevStore; const [isTabReloading, reloadTabId] = await Promise.all([getIsTabReloading(), getReloadTabId()]); diff --git a/src/background/util/openDebugTab.ts b/src/background/util/openDebugTab.ts index 971e2448..cf59a072 100644 --- a/src/background/util/openDebugTab.ts +++ b/src/background/util/openDebugTab.ts @@ -1,16 +1,16 @@ -import { devStore } from 'src/shared/storage/devStore'; +import { DevStore } from 'src/background/storage/DevStore'; /** * Open the debug tab as the first tab */ export async function openDebugTab() { if (process.env.NODE_ENV === 'development') { - const debugTabId = await devStore.getDebugTabId(); + const debugTabId = await DevStore.getDebugTabId(); const isAlreadyOpen = await (await chrome.tabs.query({})).some(tab => tab.id === debugTabId); if (isAlreadyOpen) return; - const wasVisible = await devStore.getWasDebugTabVisible(); + const wasVisible = await DevStore.getWasDebugTabVisible(); const tab = await chrome.tabs.create({ url: chrome.runtime.getURL('debug.html'), @@ -19,6 +19,6 @@ export async function openDebugTab() { index: 0, }); - await devStore.setDebugTabId(tab.id); + await DevStore.setDebugTabId(tab.id); } } diff --git a/src/debug/index.tsx b/src/debug/index.tsx index 55c762a8..0394c292 100644 --- a/src/debug/index.tsx +++ b/src/debug/index.tsx @@ -1,7 +1,7 @@ import './hotReload'; import React, { useEffect } from 'react'; import { render } from 'react-dom'; -import { devStore } from 'src/shared/storage/devStore'; +import { DevStore } from 'src/background/storage/DevStore'; const manifest = chrome.runtime.getManifest(); @@ -70,9 +70,9 @@ function DevDashboard() { useEffect(() => { const onVisibilityChange = () => { if (document.visibilityState === 'visible') { - devStore.setWasDebugTabVisible(true); + DevStore.setWasDebugTabVisible(true); } else { - devStore.setWasDebugTabVisible(false); + DevStore.setWasDebugTabVisible(false); } }; document.addEventListener('visibilitychange', onVisibilityChange); diff --git a/src/views/components/injected/CoursePopup/CoursePopup.module.scss b/src/views/components/injected/CoursePopup/CoursePopup.module.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/views/components/injected/CoursePopup/CoursePopup.tsx b/src/views/components/injected/CoursePopup/CoursePopup.tsx new file mode 100644 index 00000000..9dbf12e2 --- /dev/null +++ b/src/views/components/injected/CoursePopup/CoursePopup.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { Course } from 'src/shared/types/Course'; +import styles from './CoursePopup.module.scss'; + +interface Props { + course: Course; +} + +export default function CoursePopup({ course }: Props) { + return ( +
+

{course.fullName}

+

{course.description}

+
+ ); +}