From b94489888e75e980fe15d0b8e4902a8cac4a2e97 Mon Sep 17 00:00:00 2001 From: Ionut Anin Date: Mon, 19 Feb 2024 16:50:06 +0200 Subject: [PATCH] feat: extension background storage (#98) * extension storage config, sync background storage with popup context storage * code review updates * fix storage import --- src/background/Background.ts | 14 ++++++- src/components/switch.tsx | 5 ++- src/messageHandlers/getStorageData.ts | 13 +++++++ .../isMonetizationReadyHandler.ts | 4 +- src/popup/pages/Home.tsx | 1 + .../__tests__/popup-context.test.tsx | 9 +++++ src/providers/popup.provider.tsx | 13 ++++++- src/types/message.d.ts | 2 + src/utils/storage.ts | 39 ++++++++++++++++++- 9 files changed, 92 insertions(+), 8 deletions(-) create mode 100644 src/messageHandlers/getStorageData.ts diff --git a/src/background/Background.ts b/src/background/Background.ts index b7ca80a5..019cd86c 100644 --- a/src/background/Background.ts +++ b/src/background/Background.ts @@ -1,17 +1,22 @@ -import { Runtime, runtime, tabs } from 'webextension-polyfill' +import browser, { Runtime, runtime, tabs } from 'webextension-polyfill' import { PaymentFlowService } from '@/background/grantFlow' +import { defaultData } from '@/utils/storage' import getSendingPaymentPointerHandler from '../messageHandlers/getSendingPaymentPointerHandler' +import getStorageData from '../messageHandlers/getStorageData' import isMonetizationReadyHandler from '../messageHandlers/isMonetizationReadyHandler' import setIncomingPointerHandler from '../messageHandlers/setIncomingPointerHandler' import { tabChangeHandler, tabUpdateHandler } from './tabHandlers' +const storage = browser.storage.local + class Background { private messageHandlers: any = [ isMonetizationReadyHandler, setIncomingPointerHandler, getSendingPaymentPointerHandler, + getStorageData, ] private subscriptions: any = [] // TO DO: remove these from background into storage or state & use injection @@ -19,7 +24,12 @@ class Background { spentAmount: number = 0 paymentStarted = false - constructor() {} + constructor() { + storage + .set({ data: defaultData }) + .then(() => console.log('Default data stored successfully')) + .catch((error: any) => console.error('Error storing data:', error)) + } subscribeToMessages() { this.subscriptions = this.messageHandlers.map((handler: any) => { diff --git a/src/components/switch.tsx b/src/components/switch.tsx index 5771072c..fdeef9c5 100644 --- a/src/components/switch.tsx +++ b/src/components/switch.tsx @@ -33,10 +33,11 @@ export interface SwitchProps extends VariantProps, React.HTMLAttributes { checked?: boolean + onChange?: (_event: React.ChangeEvent) => void } export const Switch = forwardRef(function Switch( - { size, className, ...props }, + { size, className, onChange = () => {}, ...props }, ref, ) { return ( @@ -45,6 +46,8 @@ export const Switch = forwardRef(function Switch( role="switch" ref={ref} type="checkbox" + checked={props.checked} + onChange={onChange} {...props} className="peer absolute opacity-0 -translate-x-[100%] pointer-events-none" /> diff --git a/src/messageHandlers/getStorageData.ts b/src/messageHandlers/getStorageData.ts new file mode 100644 index 00000000..1152a519 --- /dev/null +++ b/src/messageHandlers/getStorageData.ts @@ -0,0 +1,13 @@ +import browser from 'webextension-polyfill' + +const storage = browser.storage.local + +const getStorageData = async () => { + const data = await storage.get('data') + return { + type: 'SUCCESS', + data, + } +} + +export default { callback: getStorageData, type: 'GET_STORAGE_DATA' } diff --git a/src/messageHandlers/isMonetizationReadyHandler.ts b/src/messageHandlers/isMonetizationReadyHandler.ts index 9bb2cfc5..07081b77 100644 --- a/src/messageHandlers/isMonetizationReadyHandler.ts +++ b/src/messageHandlers/isMonetizationReadyHandler.ts @@ -4,10 +4,10 @@ export type IsMonetizationReadyData = { monetization: boolean } -const isMometizationReadyCallback = async (data: IsMonetizationReadyData) => { +const isMonetizationReadyCallback = async (data: IsMonetizationReadyData) => { await updateIcon(data.monetization) return true } -export default { callback: isMometizationReadyCallback, type: 'IS_MONETIZATION_READY' } +export default { callback: isMonetizationReadyCallback, type: 'IS_MONETIZATION_READY' } diff --git a/src/popup/pages/Home.tsx b/src/popup/pages/Home.tsx index 46a81f0e..a9df4810 100644 --- a/src/popup/pages/Home.tsx +++ b/src/popup/pages/Home.tsx @@ -71,6 +71,7 @@ export const Home = () => { const getSendingPaymentPointer = async () => { const response = await sendMessage({ type: 'GET_SENDING_PAYMENT_POINTER' }) + console.log('getSendingPaymentPointer', response) setSendingPaymentPointer(response.data.sendingPaymentPointerUrl) const { sendingPaymentPointerUrl: paymentPointer, amount } = response.data diff --git a/src/providers/__tests__/popup-context.test.tsx b/src/providers/__tests__/popup-context.test.tsx index cb6996be..63fbe7e5 100644 --- a/src/providers/__tests__/popup-context.test.tsx +++ b/src/providers/__tests__/popup-context.test.tsx @@ -3,6 +3,15 @@ import React, { useContext } from 'react' import { defaultData, PopupContext, PopupProvider } from '../popup.provider' +jest.mock('webextension-polyfill', () => ({ + runtime: { + onMessage: { + addListener: jest.fn(), + removeListener: jest.fn(), + }, + }, +})) + const TestComponent = () => { const { data, setData } = useContext(PopupContext) diff --git a/src/providers/popup.provider.tsx b/src/providers/popup.provider.tsx index db7634d2..4f2e10b6 100644 --- a/src/providers/popup.provider.tsx +++ b/src/providers/popup.provider.tsx @@ -1,4 +1,6 @@ -import React, { createContext, useState } from 'react' +import React, { createContext, useEffect, useState } from 'react' + +import { getStorageData } from '@/utils/storage' import { PopupContextValue, TPopupContext } from './providers.interface' @@ -29,6 +31,15 @@ export const PopupContext = createContext({ export const PopupProvider: React.FC = ({ children }) => { const [data, setData] = useState(defaultData) + useEffect(() => { + ;(async () => { + const storageData = await getStorageData() + setData(storageData as TPopupContext) + })() + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + return {children} } diff --git a/src/types/message.d.ts b/src/types/message.d.ts index 8f46fc77..1fe988d8 100644 --- a/src/types/message.d.ts +++ b/src/types/message.d.ts @@ -11,6 +11,8 @@ declare type EXTMessageType = | 'PAYMENT_SUCCESS' | 'PAUSE_PAYMENTS' | 'LOAD' + | 'GET_STORAGE_DATA' + | 'SET_STORAGE_DATA' declare type EXTMessage = { type: EXTMessageType diff --git a/src/utils/storage.ts b/src/utils/storage.ts index 24995aeb..8461674a 100755 --- a/src/utils/storage.ts +++ b/src/utils/storage.ts @@ -1,3 +1,38 @@ -import { storage } from 'webextension-polyfill' +import { TPopupContext } from '@/providers/providers.interface' +import { sendMessage } from '@/utils/sendMessages' -export default storage.sync ? storage.sync : storage.local +export interface ExtensionStorageData { + amount: number + amountType: { + recurring: boolean + } + rateOfPay: number + wmEnabled: boolean + accessTokenQuote: string + accessTokenOutgoing: string + refreshToken: string + manageUrl: string +} + +export const defaultData: ExtensionStorageData = { + amount: 0, + amountType: { + recurring: true, + }, + rateOfPay: 0.36, + wmEnabled: true, + accessTokenQuote: '', + accessTokenOutgoing: '', + refreshToken: '', + manageUrl: '', +} + +export const getStorageData = async () => { + try { + const response = await sendMessage({ type: 'GET_STORAGE_DATA' }) + return response?.data as TPopupContext + } catch (error) { + console.error('Error fetching storage data:', error) + return null + } +}