diff options
Diffstat (limited to 'src/utils/hooks/use-redirection')
| -rw-r--r-- | src/utils/hooks/use-redirection/index.ts | 1 | ||||
| -rw-r--r-- | src/utils/hooks/use-redirection/use-redirection.test.ts | 80 | ||||
| -rw-r--r-- | src/utils/hooks/use-redirection/use-redirection.ts | 41 |
3 files changed, 122 insertions, 0 deletions
diff --git a/src/utils/hooks/use-redirection/index.ts b/src/utils/hooks/use-redirection/index.ts new file mode 100644 index 0000000..c81c82c --- /dev/null +++ b/src/utils/hooks/use-redirection/index.ts @@ -0,0 +1 @@ +export * from './use-redirection'; diff --git a/src/utils/hooks/use-redirection/use-redirection.test.ts b/src/utils/hooks/use-redirection/use-redirection.test.ts new file mode 100644 index 0000000..c14ac4c --- /dev/null +++ b/src/utils/hooks/use-redirection/use-redirection.test.ts @@ -0,0 +1,80 @@ +import { describe, it } from '@jest/globals'; +import { renderHook } from '@testing-library/react'; +import nextRouterMock from 'next-router-mock'; +import { MemoryRouterProvider } from 'next-router-mock/MemoryRouterProvider'; +import { useRedirection } from './use-redirection'; + +describe('useRedirection', () => { + it('redirects to another page', async () => { + const initialPath = '/initial-path'; + const redirectPath = '/redirect-path'; + + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + expect.assertions(2); + + await nextRouterMock.push('/initial-path'); + + expect(nextRouterMock.asPath).toBe(initialPath); + + renderHook(() => useRedirection({ to: redirectPath }), { + wrapper: MemoryRouterProvider, + }); + + expect(nextRouterMock.asPath).toBe(redirectPath); + }); + + it('can replace the url in the history', async () => { + const initialPath = '/initial-path'; + const redirectPath = '/redirect-path'; + + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + expect.assertions(2); + + await nextRouterMock.push('/initial-path'); + + expect(nextRouterMock.asPath).toBe(initialPath); + + renderHook(() => useRedirection({ isReplacing: true, to: redirectPath }), { + wrapper: MemoryRouterProvider, + }); + + expect(nextRouterMock.asPath).toBe(redirectPath); + + /* Ideally we should check if when we use `back()` the current path is + * still the redirectPath but it is not yet implemented in the mock. */ + }); + + it('can conditionally redirect to another page', async () => { + const paths = { + initial: '/initial-path', + matching: '/matching-path', + redirect: '/redirect-path', + }; + + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + expect.assertions(3); + + await nextRouterMock.push('/initial-path'); + + expect(nextRouterMock.asPath).toBe(paths.initial); + + const { rerender } = renderHook( + () => + useRedirection({ + to: paths.redirect, + whenPathMatches: (path) => path === paths.matching, + }), + { + wrapper: MemoryRouterProvider, + } + ); + + expect(nextRouterMock.asPath).toBe(paths.initial); + + await nextRouterMock.push(paths.matching); + + rerender(); + + expect(nextRouterMock.asPath).toBe(paths.redirect); + }); +}); diff --git a/src/utils/hooks/use-redirection/use-redirection.ts b/src/utils/hooks/use-redirection/use-redirection.ts new file mode 100644 index 0000000..1592a33 --- /dev/null +++ b/src/utils/hooks/use-redirection/use-redirection.ts @@ -0,0 +1,41 @@ +import { useRouter } from 'next/router'; +import { useEffect } from 'react'; + +export type UseRedirectionConfig = { + /** + * Should the url be replaced in the history? + * + * @default false + */ + isReplacing?: boolean; + /** + * The destination. + */ + to: string; + /** + * Redirect only when the current path matches the condition. + * + * @param {string} path - The current slug. + * @returns {boolean} True if the path matches. + */ + whenPathMatches?: (path: string) => boolean; +}; + +export const useRedirection = ({ + isReplacing = false, + to, + whenPathMatches, +}: UseRedirectionConfig) => { + const router = useRouter(); + + useEffect(() => { + const shouldRedirect = whenPathMatches + ? whenPathMatches(router.asPath) + : true; + + if (shouldRedirect) { + if (isReplacing) router.replace(to, undefined, { shallow: true }); + else router.push(to); + } + }, [isReplacing, router, to, whenPathMatches]); +}; |
