From 05992f800f5544cc3e901ab73bf8ff5cfe17dee9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Miszczyszyn?= Date: Thu, 7 Jan 2021 19:41:23 +0100 Subject: [PATCH] chore: Dodano hook useSearch (#119) --- hooks/useSearch.tsx | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 hooks/useSearch.tsx diff --git a/hooks/useSearch.tsx b/hooks/useSearch.tsx new file mode 100644 index 00000000..f23f0f37 --- /dev/null +++ b/hooks/useSearch.tsx @@ -0,0 +1,54 @@ +import { useRouter } from 'next/router'; +import { useCallback, useMemo } from 'react'; +import type { InferType, ObjectSchema } from 'yup'; + +const replacementsPattern = /\[([^[\]\s]+)\]/gi; + +export const useSearch = >(schema: S) => { + const { pathname, query: routerQuery, push } = useRouter(); + + /** + * Next.js query is different from what we usuallly consider a "query" + * In Next, for the following route /admin/[blogId], the URL /admin/123?isPublic=true + * is considered to have TWO query items: { blogId: 123, isPublic: true } + * What we want instead, is to have params = { blogId: 123 } and query = { isPublic: true } + */ + const { params, query } = useMemo(() => { + const matches = [...pathname.matchAll(replacementsPattern)]; + const params = Object.fromEntries( + Object.entries(routerQuery).filter(([key]) => + matches.some(([, replacement]) => key === replacement), + ), + ); + const query = schema.cast( + Object.fromEntries(Object.entries(routerQuery).filter(([key]) => !(key in params))), + ) as InferType; + + return { + params, + query, + }; + }, [pathname, routerQuery, schema]); + + console.log({ params, query }); + + const changeQuery = useCallback( + (query: InferType) => { + const filteredQuery = Object.fromEntries( + Object.entries(query).filter(([key]) => !(key in params)), + ); + + const result = schema.validateSync(filteredQuery); + + void push({ + query: { + ...routerQuery, + ...result, + }, + }); + }, + [params, push, routerQuery, schema], + ); + + return useMemo(() => ({ changeQuery, params, query }), [params, query, changeQuery]); +};