'use client' import { useCallback } from 'react' import { usePathname, useRouter, useSearchParams } from 'next/navigation' interface UseQueryTabOptions { /** Valid tab values, in the order they should be checked. */ values: readonly T[] /** Falls back to this when the query param is missing or invalid; also the value that gets omitted from the URL. */ defaultValue: T /** Query string key to read/write. Defaults to `tab`. */ param?: string } /** * Keeps a tab selection in sync with the URL (`?tab=...` by default) via `router.replace`, * so the active tab survives reloads and is shareable/bookmarkable. */ export const useQueryTab = ({ values, defaultValue, param = 'tab', }: UseQueryTabOptions): [T, (key: React.Key) => void] => { const router = useRouter() const pathname = usePathname() const searchParams = useSearchParams() const rawValue = searchParams.get(param) const selectedTab = (values as readonly string[]).includes(rawValue ?? '') ? (rawValue as T) : defaultValue const setTab = useCallback( (key: React.Key) => { const tab = String(key) const params = new URLSearchParams(searchParams.toString()) if (tab === defaultValue) params.delete(param) else params.set(param, tab) const query = params.toString() router.replace(query ? `${pathname}?${query}` : pathname, { scroll: false }) }, [searchParams, router, pathname, defaultValue, param] ) return [selectedTab, setTab] }