| | import { useRouter } from 'next/router' |
| | import { useState, useEffect, useRef, useCallback } from 'react' |
| |
|
| | export type QueryParams = { |
| | 'search-overlay-input': string |
| | 'search-overlay-ask-ai': string |
| | debug: string |
| | 'articles-category': string |
| | 'articles-filter': string |
| | 'articles-page': string |
| | } |
| |
|
| | const initialKeys: (keyof QueryParams)[] = [ |
| | |
| | 'search-overlay-input', |
| | 'search-overlay-ask-ai', |
| | |
| | 'debug', |
| | |
| | 'articles-category', |
| | 'articles-filter', |
| | 'articles-page', |
| | ] |
| |
|
| | |
| | export function useMultiQueryParams(options?: { |
| | useHistory?: boolean |
| | excludeFromHistory?: (keyof QueryParams)[] |
| | }) { |
| | const router = useRouter() |
| | const pushTimeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null) |
| | const useHistory = options?.useHistory ?? false |
| | |
| | const excludeFromHistory = options?.excludeFromHistory ?? [] |
| |
|
| | const getInitialParams = (): QueryParams => { |
| | const searchParams = |
| | typeof window !== 'undefined' |
| | ? new URLSearchParams(window.location.search) |
| | : new URLSearchParams(router.asPath.split('?')[1] || '') |
| | const params: QueryParams = { |
| | 'search-overlay-input': searchParams.get('search-overlay-input') || '', |
| | 'search-overlay-ask-ai': searchParams.get('search-overlay-ask-ai') || '', |
| | debug: searchParams.get('debug') || '', |
| | 'articles-category': searchParams.get('articles-category') || '', |
| | 'articles-filter': searchParams.get('articles-filter') || '', |
| | 'articles-page': searchParams.get('articles-page') || '', |
| | } |
| | return params |
| | } |
| |
|
| | const [params, setParams] = useState<QueryParams>(getInitialParams) |
| |
|
| | |
| | useEffect(() => { |
| | setParams(getInitialParams()) |
| | }, [router.pathname]) |
| |
|
| | |
| | useEffect(() => { |
| | if (!useHistory) return |
| |
|
| | const handleRouteChange = () => { |
| | |
| | |
| | setParams((currentParams) => { |
| | const newParams = getInitialParams() |
| | |
| | for (const key of excludeFromHistory) { |
| | newParams[key] = currentParams[key] |
| | } |
| | return newParams |
| | }) |
| | } |
| |
|
| | router.events.on('routeChangeComplete', handleRouteChange) |
| | return () => { |
| | router.events.off('routeChangeComplete', handleRouteChange) |
| | } |
| | }, [router.events, useHistory, excludeFromHistory]) |
| |
|
| | const updateParams = useCallback( |
| | (updates: Partial<QueryParams>, shouldPushHistory = false) => { |
| | |
| | setParams((currentParams) => { |
| | const newParams = { ...currentParams, ...updates } |
| | const [asPathWithoutHash] = router.asPath.split('#') |
| | const [asPathRoot, asPathQuery = ''] = asPathWithoutHash.split('?') |
| | const searchParams = new URLSearchParams(asPathQuery) |
| | for (const key of initialKeys) { |
| | if (key === 'search-overlay-ask-ai') { |
| | if (newParams[key] === 'true') { |
| | searchParams.set(key, 'true') |
| | } else { |
| | searchParams.delete(key) |
| | } |
| | } else { |
| | if (newParams[key]) { |
| | searchParams.set(key, newParams[key]) |
| | } else { |
| | searchParams.delete(key) |
| | } |
| | } |
| | } |
| | const paramsString = searchParams.toString() ? `?${searchParams.toString()}` : '' |
| | let newUrl = `${asPathRoot}${paramsString}` |
| | if (asPathRoot !== '/' && router.locale) { |
| | newUrl = `${router.locale}${asPathRoot}${paramsString}` |
| | } |
| | if (!newUrl.startsWith('/')) { |
| | newUrl = `/${newUrl}` |
| | } |
| |
|
| | |
| | if (pushTimeoutRef.current) clearTimeout(pushTimeoutRef.current) |
| | pushTimeoutRef.current = setTimeout(async () => { |
| | |
| | |
| | const scrollY = window.scrollY |
| | const scrollX = window.scrollX |
| |
|
| | |
| | const routerMethod = shouldPushHistory ? router.push : router.replace |
| | await routerMethod(newUrl, undefined, { |
| | shallow: true, |
| | locale: router.locale, |
| | scroll: false, |
| | }) |
| |
|
| | |
| | |
| | window.scrollTo(scrollX, scrollY) |
| | }, 100) |
| |
|
| | return newParams |
| | }) |
| | }, |
| | [router], |
| | ) |
| |
|
| | return { params, updateParams } |
| | } |
| |
|