From 0d8d8a815d14f8ca0ba571a6a253d32e240e88cb Mon Sep 17 00:00:00 2001 From: Christiantyemele Date: Wed, 3 Apr 2024 17:59:52 +0100 Subject: [PATCH] feat(indexeddb): indexeddb storageservice implementation Signed-off-by: Christiantyemele --- .../src/Hooks/StorageContext.tsx | 236 ++++++++++++++++++ 1 file changed, 236 insertions(+) create mode 100644 power-pay-frontend/src/Hooks/StorageContext.tsx diff --git a/power-pay-frontend/src/Hooks/StorageContext.tsx b/power-pay-frontend/src/Hooks/StorageContext.tsx new file mode 100644 index 00000000..fe2347ff --- /dev/null +++ b/power-pay-frontend/src/Hooks/StorageContext.tsx @@ -0,0 +1,236 @@ +import {createContext, PropsWithChildren, useEffect, useState} from 'react'; + + +// Define the StorageContextData interface. +export interface StorageContextData { + item: Record; + setItem: (key: string, value: T) => Promise; + removeItem: (key: string) => Promise; + clear: () => Promise; +} + +// Define the StorageService interface. +interface StorageService { + clear: () => Promise; + getItem: (key: string) => Promise; + removeItem: (key: string) => Promise + + + +} +interface SetStorage { + setItem: (key: string, value: T) => Promise; +} +interface SetStorageIDB { + setItem: (value: object, key: IDBValidKey) => Promise; +} + +// Define the LocalStorageService class implementing the StorageService interface. +export class LocalStorageService implements StorageService, SetStorage { + async getItem(key: string): Promise { + const found = localStorage.getItem(key); + if (!found) return undefined; + return JSON.parse(found) as T; + } + + async setItem(key: string , value: T): Promise { + localStorage.setItem(key, JSON.stringify(value)); + return true; + } + + async removeItem(key: string): Promise { + localStorage.removeItem(key); + return true; + } + + async clear(): Promise { + localStorage.clear(); + return true; + } +} + +export class IndexedDBStorageService implements StorageService, SetStorageIDB { + private dbName: string; + private version: number; + private db: IDBDatabase + + constructor(dbName: string = 'dbname', version?: number) { + this.dbName = dbName; + + } + + async openDatabase(dbName?: string, Version?: number): Promise { + return new Promise((resolve, reject) => { + + const request = window.indexedDB.open(dbName ?? this.dbName); + + request.onerror = (event: Event) => { + reject((event.target as IDBOpenDBRequest).error); + }; + + request.onsuccess = (event: Event) => { + resolve((event.target as IDBOpenDBRequest).result); + }; + + request.onupgradeneeded = (event: Event) => { + + this.db = (event.target as IDBOpenDBRequest).result; + const objectstore = this.db.createObjectStore('objectstore', {keyPath: 'id'}) + }; + }); + } + + async clear(): Promise { + + if (!this.db) + await this.openDatabase() + + return new Promise((resolve, reject) => { + const transaction = + + this.db.transaction('objectstore', 'readwrite') + .objectStore('objectstore') + .clear(); + transaction.onsuccess = (event: Event) => { + resolve((event.target as IDBRequest).result) + } + transaction.onerror = (event: Event) => { + reject((event.target as IDBRequest).onerror) + } + }) + + } + + async getItem(keypath: any): Promise { + if (!this.db) + await this.openDatabase() + return new Promise((resolve, reject) => { + const transaction = this.db.transaction('objectstore', 'readonly') + + .objectStore('objectstore') + + .get(keypath) + + transaction.onsuccess = (event) => { + + resolve((event.target as IDBRequest).result) + } + transaction.onerror = (event: Event) => { + reject((event.target as IDBRequest).onerror) + } + }) + } + + async removeItem(key: string): Promise { + if (!this.db) + await this.openDatabase() + + return new Promise((resolve, reject) => { + const transaction = this.db.transaction('objectstore', 'readwrite') + + .objectStore('objectstore') + + .delete(key); + + transaction.onerror = (event: Event) => { + reject((event.target as IDBRequest).error); + }; + + transaction.onsuccess = (event: Event) => { + resolve((event.target as IDBRequest).result); + }; + }); + } + + async setItem(value: object, key?: IDBValidKey): Promise { + if (!this.db) + await this.openDatabase() + + return new Promise((resolve, reject) => { + const transaction = this.db.transaction('objectstore', 'readwrite') + .objectStore('objectstore') + + .add(value, key); + + + transaction.onerror = (event: Event) => { + + reject((event.target as IDBRequest).error); + }; + + transaction.onsuccess = (event: Event) => { + + resolve((event.target as IDBRequest).result); + + }; + }); + + } +} + +// Define a global constant for the key. +const + STORAGE_KEY = 'new_key'; + +// Create the StorageContext with default functions for getItem and setItem. +const + StorageContext = createContext | undefined>(undefined); + +// Define the StorageProvider component +export function + +StorageProvider({children, storageService}: PropsWithChildren<{ storageService: StorageService }>) { + const [storedValue, setStoredValue] = useState>({}); + + // Initialize the state with the value from the local storage if it exists. + useEffect(() => { + storageService + .getItem>(STORAGE_KEY) + .then((item) => { + if (item) { + setStoredValue(item); + } + }); + }, [storageService]); + + // Updates the local storage whenever the state changes. + useEffect(() => { + storageService.setItem(STORAGE_KEY, storedValue); + }, [storageService, storedValue]); + + // Remove the item from local storage and set the stored value to undefined + const clearItem = async (key: string): Promise => { + localStorage.removeItem(key); + setStoredValue((prevState) => { + const newState = {...prevState}; + delete newState[key]; + return newState; + }); + return true; + }; + + // Define the context value. + const contextValue: StorageContextData = { + item: storedValue, + setItem: async (key, value) => { + setStoredValue((prevState) => ({ + ...prevState, + [key]: value, + })); + return true; + }, + removeItem: async (key) => clearItem(key), + clear: async () => { + setStoredValue({}); + return true; + }, + }; + + return ( + + {children} + + ); +} + +export default StorageContext;