From 6e07f4b8be564da4ff7a1c4b98804ac7c6af9ac8 Mon Sep 17 00:00:00 2001 From: enes Date: Tue, 29 Oct 2024 13:21:12 +0100 Subject: [PATCH] feat(filter): remember filters, add localstorage hook and utils --- src/hooks/index.ts | 1 + src/hooks/useLocalStorage.tsx | 50 +++++++++++++++++++++++++++++++++++ src/utils/consts.ts | 8 ++++++ src/utils/index.ts | 2 ++ src/utils/localStorage.ts | 32 ++++++++++++++++++++++ 5 files changed, 93 insertions(+) create mode 100644 src/hooks/useLocalStorage.tsx create mode 100644 src/utils/consts.ts create mode 100644 src/utils/localStorage.ts diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 2148b14..3daf9f4 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -7,3 +7,4 @@ export * from './useNSFWList' export * from './useReactions' export * from './useNDKContext' export * from './useScrollDisable' +export * from './useLocalStorage' diff --git a/src/hooks/useLocalStorage.tsx b/src/hooks/useLocalStorage.tsx new file mode 100644 index 0000000..8dc9893 --- /dev/null +++ b/src/hooks/useLocalStorage.tsx @@ -0,0 +1,50 @@ +import React from 'react' +import { + getLocalStorageItem, + removeLocalStorageItem, + setLocalStorageItem +} from 'utils' + +const useLocalStorageSubscribe = (callback: () => void) => { + window.addEventListener('storage', callback) + return () => window.removeEventListener('storage', callback) +} + +export function useLocalStorage( + key: string, + initialValue: T +): [T, React.Dispatch>] { + const getSnapshot = () => getLocalStorageItem(key, initialValue) + + const data = React.useSyncExternalStore(useLocalStorageSubscribe, getSnapshot) + + const setState: React.Dispatch> = React.useCallback( + (v: React.SetStateAction) => { + try { + const nextState = + typeof v === 'function' + ? (v as (prevState: T) => T)(JSON.parse(data)) + : v + + if (nextState === undefined || nextState === null) { + removeLocalStorageItem(key) + } else { + setLocalStorageItem(key, JSON.stringify(nextState)) + } + } catch (e) { + console.warn(e) + } + }, + [key, data] + ) + + React.useEffect(() => { + // Set local storage only when it's empty + const data = window.localStorage.getItem(key) + if (data === null) { + setLocalStorageItem(key, JSON.stringify(initialValue)) + } + }, [key, initialValue]) + + return [JSON.parse(data) as T, setState] +} diff --git a/src/utils/consts.ts b/src/utils/consts.ts new file mode 100644 index 0000000..ff8e47b --- /dev/null +++ b/src/utils/consts.ts @@ -0,0 +1,8 @@ +import { FilterOptions, SortBy, NSFWFilter, ModeratedFilter } from 'types' + +export const DEFAULT_FILTER_OPTIONS: FilterOptions = { + sort: SortBy.Latest, + nsfw: NSFWFilter.Hide_NSFW, + source: window.location.host, + moderated: ModeratedFilter.Moderated +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 35ad5bc..06e7ca4 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -3,3 +3,5 @@ export * from './nostr' export * from './url' export * from './utils' export * from './zap' +export * from './localStorage' +export * from './consts' diff --git a/src/utils/localStorage.ts b/src/utils/localStorage.ts new file mode 100644 index 0000000..7d3e8aa --- /dev/null +++ b/src/utils/localStorage.ts @@ -0,0 +1,32 @@ +export function getLocalStorageItem(key: string, defaultValue: T): string { + try { + const data = window.localStorage.getItem(key) + if (data === null) return JSON.stringify(defaultValue) + return data + } catch (err) { + console.error(`Error while fetching local storage value: `, err) + return JSON.stringify(defaultValue) + } +} + +export function setLocalStorageItem(key: string, value: string) { + try { + window.localStorage.setItem(key, value) + dispatchLocalStorageEvent(key, value) + } catch (err) { + console.error(`Error while saving local storage value: `, err) + } +} + +export function removeLocalStorageItem(key: string) { + try { + window.localStorage.removeItem(key) + dispatchLocalStorageEvent(key, null) + } catch (err) { + console.error(`Error while deleting local storage value: `, err) + } +} + +function dispatchLocalStorageEvent(key: string, newValue: string | null) { + window.dispatchEvent(new StorageEvent('storage', { key, newValue })) +}