feat: game page search, cached filters #105
@ -7,3 +7,4 @@ export * from './useNSFWList'
|
||||
export * from './useReactions'
|
||||
export * from './useNDKContext'
|
||||
export * from './useScrollDisable'
|
||||
export * from './useLocalStorage'
|
||||
|
50
src/hooks/useLocalStorage.tsx
Normal file
50
src/hooks/useLocalStorage.tsx
Normal file
@ -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<T>(
|
||||
key: string,
|
||||
initialValue: T
|
||||
): [T, React.Dispatch<React.SetStateAction<T>>] {
|
||||
const getSnapshot = () => getLocalStorageItem(key, initialValue)
|
||||
|
||||
const data = React.useSyncExternalStore(useLocalStorageSubscribe, getSnapshot)
|
||||
|
||||
const setState: React.Dispatch<React.SetStateAction<T>> = React.useCallback(
|
||||
(v: React.SetStateAction<T>) => {
|
||||
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]
|
||||
}
|
8
src/utils/consts.ts
Normal file
8
src/utils/consts.ts
Normal file
@ -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
|
||||
}
|
@ -3,3 +3,5 @@ export * from './nostr'
|
||||
export * from './url'
|
||||
export * from './utils'
|
||||
export * from './zap'
|
||||
export * from './localStorage'
|
||||
export * from './consts'
|
||||
|
32
src/utils/localStorage.ts
Normal file
32
src/utils/localStorage.ts
Normal file
@ -0,0 +1,32 @@
|
||||
export function getLocalStorageItem<T>(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 }))
|
||||
}
|
Loading…
Reference in New Issue
Block a user