import React, { Context, ReactNode, useState, useEffect, useRef, createContext, useMemo } from 'react'; import { EventEmitter } from 'events'; import { isEqual, isNull } from 'lodash'; import { Storage } from '@capacitor/core'; import Debug from 'debug'; import { IStoreContext, defaultContext, useStore } from './store'; const debug = Debug('deepcase:store:capacitor'); const capacitorStorageEvent = new EventEmitter(); export const CapacitorStoreContext = createContext(defaultContext); export const CapacitorStoreProvider = ({ context = CapacitorStoreContext, children, fetchInterval = 0, }: { context?: Context; children?: ReactNode; fetchInterval?: number; }) => { const [useStore] = useState(() => { return function useStore( key: string, defaultValue: T, ): [T, (value: T) => any, () => any] { const getStateRef = useRef(); const intervalRef = useRef(); const memoDefaultValue = useMemo(() => defaultValue, []); const [state, setState] = useState(memoDefaultValue); const [setValue] = useState(() => (value) => { debug('setValue', { key, defaultValue: memoDefaultValue, value }); Storage.set({ key, value: JSON.stringify(value) }).then(() => setState(value)); capacitorStorageEvent.emit(key, JSON.stringify(value)); }); const [unsetValue] = useState(() => () => { debug('unsetValue', { key, defaultValue: memoDefaultValue }); Storage.remove({ key }).then(() => setState(memoDefaultValue)); capacitorStorageEvent.emit(key, memoDefaultValue); }); getStateRef.current = () => Storage.get({ key }).then(async ({ value }) => { const { keys } = await Storage.keys(); if (!!~keys.indexOf(key)) { let valueParsed: any; try { valueParsed = JSON.parse(value); } catch (error) { debug('setStore:error', { error, key, defaultValue: memoDefaultValue, value }); } debug('getStore', { key, defaultValue: memoDefaultValue, valueParsed, value }); if (!isEqual(valueParsed, state)) { if (typeof(valueParsed) === 'undefined' || isNull(value)) setState(defaultValue); else setState(valueParsed); } } }); useEffect( () => { debug('init', { key, defaultValue: memoDefaultValue }); getStateRef.current(); const fn = (value) => { let valueParsed; try { valueParsed = JSON.parse(value); } catch (error) { debug('fn:error', { error, key, defaultValue: memoDefaultValue, value }); } if (typeof(valueParsed) === 'undefined' || isNull(valueParsed)) setState(memoDefaultValue); else setState(valueParsed); }; if (fetchInterval) intervalRef.current = setInterval(() => getStateRef.current(), fetchInterval); capacitorStorageEvent.on(key, fn); return () => { clearInterval(intervalRef.current); capacitorStorageEvent.off(key, fn); }; }, [], ); return [state, setValue, unsetValue]; }; }); return {children} ; }; export function useCapacitorStore(key: string, defaultValue: T, context = CapacitorStoreContext) { return useStore(key, defaultValue, context); }