Add vendors listing with search, category filter, grid/list, pagination
This commit is contained in:
15
frontend/src/hooks/use-debounced-callback.ts
Normal file
15
frontend/src/hooks/use-debounced-callback.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { useEffect, useMemo, useRef } from 'react'
|
||||
|
||||
export function useDebouncedCallback<T extends (...args: never[]) => void>(fn: T, delay: number): T {
|
||||
const ref = useRef(fn)
|
||||
useEffect(() => {
|
||||
ref.current = fn
|
||||
})
|
||||
return useMemo(() => {
|
||||
let timer: ReturnType<typeof setTimeout> | undefined
|
||||
return ((...args: Parameters<T>) => {
|
||||
if (timer) clearTimeout(timer)
|
||||
timer = setTimeout(() => ref.current(...args), delay)
|
||||
}) as T
|
||||
}, [delay])
|
||||
}
|
||||
24
frontend/src/hooks/use-local-storage.ts
Normal file
24
frontend/src/hooks/use-local-storage.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
|
||||
export function useLocalStorage<T>(key: string, initialValue: T): [T, (v: T) => void] {
|
||||
const [value, setValue] = useState<T>(() => {
|
||||
if (typeof window === 'undefined') return initialValue
|
||||
try {
|
||||
const raw = window.localStorage.getItem(key)
|
||||
return raw != null ? (JSON.parse(raw) as T) : initialValue
|
||||
} catch {
|
||||
return initialValue
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
window.localStorage.setItem(key, JSON.stringify(value))
|
||||
} catch {
|
||||
/* storage unavailable */
|
||||
}
|
||||
}, [key, value])
|
||||
|
||||
const set = useCallback((v: T) => setValue(v), [])
|
||||
return [value, set]
|
||||
}
|
||||
Reference in New Issue
Block a user