sendou.ink/hooks/useMyRouter.ts
2021-06-17 21:45:18 +03:00

95 lines
2.1 KiB
TypeScript

import { NextRouter, useRouter } from "next/router";
import type { URLSearchParams as URLSearchParamsType } from "url";
import * as z from "zod";
type SearchParamsType =
| string
| string[]
| number
| number[]
| boolean
| boolean[]
| null
| undefined;
type SearchParamsTuple = [key: string, value: SearchParamsType];
export const adjustedSearchParams = (
url: string,
newParams: SearchParamsTuple[],
clearOthers: boolean
): URLSearchParams => {
const result = clearOthers
? new URLSearchParams()
: new URL(url).searchParams;
for (const [key, value] of newParams) {
result.delete(key);
if (!value && typeof value !== "boolean") {
continue;
}
if (Array.isArray(value)) {
for (const element of value) {
result.append(key, String(element));
}
continue;
}
result.set(key, String(value));
}
result.sort();
return result;
};
const isSearchParamsTuple = (
newParams: SearchParamsTuple | SearchParamsTuple[]
): newParams is SearchParamsTuple => {
return !Array.isArray(newParams[0]);
};
const setRouterSearchParams = (
router: NextRouter,
newParams: SearchParamsTuple | SearchParamsTuple[],
clearOthers: boolean
) => {
const newSearchParams = adjustedSearchParams(
window.location.href,
isSearchParamsTuple(newParams) ? [newParams] : newParams,
clearOthers
);
router.replace(
`${router.pathname}?${newSearchParams.toString()}`,
undefined,
{
shallow: true,
}
);
};
const resetSearchParams = (router: NextRouter) =>
router.replace(router.pathname, undefined, { shallow: true });
export const useMyRouter = (): NextRouter & {
resetSearchParams: () => void;
setSearchParams: (
newParams: SearchParamsTuple | SearchParamsTuple[],
clearOthers?: boolean
) => void;
} => {
const router = useRouter();
return {
...router,
resetSearchParams: () => resetSearchParams(router),
setSearchParams: (
newParams: SearchParamsTuple | SearchParamsTuple[],
clearOthers?: boolean
) => setRouterSearchParams(router, newParams, clearOthers ?? false),
};
};