next/router#NextRouter TypeScript Examples
The following examples show how to use
next/router#NextRouter.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Routing.utils.ts From frontend.ro with MIT License | 7 votes |
static isRouteActive(router: NextRouter, url: UrlObject) {
// This is a naive implementation based on what we need right now.
// In other words, we found out that only those 2 checks get the job done.
// We may need to add additional checks, depending on future usecases.
if (url.pathname !== undefined && router.pathname !== url.pathname) {
return false;
}
if (
url.query !== undefined
&& Object.keys(url.query).some((key) => url.query[key] !== router.query[key])
) {
return false;
}
return true;
}
Example #2
Source File: utils.ts From next-instantsearch with MIT License | 7 votes |
onSearchStateChange = (searchState: any, Router: NextRouter) => {
const urlObject = url.parse(Router.asPath);
const urlParams = qs.parse(urlObject.query || "");
const href = {
pathname: Router.pathname,
query: Router.query,
};
const as = urlObject.pathname + createURL({ ...urlParams, ...searchState });
Router.replace(href, as, { shallow: true });
}
Example #3
Source File: filters.utils.ts From condo with MIT License | 7 votes |
export async function updateQuery (router: NextRouter, newFilters?: FiltersFromQueryType, sort?: string[], offset?: number): Promise<boolean> {
if (!offset && 'offset' in router.query) {
router.query['offset'] = '0'
}
const possibleFilters = pickBy(newFilters, (value) => !isEmpty(value))
const possibleQueryData = { ...router.query, sort, offset }
if (isEmpty(possibleFilters)) {
delete possibleQueryData['filters']
} else {
possibleQueryData['filters'] = JSON.stringify(possibleFilters)
}
const query = qs.stringify(
possibleQueryData,
{ arrayFormat: 'comma', skipNulls: true, addQueryPrefix: true },
)
return await router.push(router.route + query)
}
Example #4
Source File: test-utils.tsx From lucide with ISC License | 7 votes |
mockRouter: NextRouter = {
basePath: '',
pathname: '/',
route: '/',
asPath: '/',
query: {},
push: jest.fn(),
replace: jest.fn(),
reload: jest.fn(),
back: jest.fn(),
prefetch: jest.fn(),
beforePopState: jest.fn(),
events: {
on: jest.fn(),
off: jest.fn(),
emit: jest.fn(),
},
isFallback: false,
}
Example #5
Source File: SourcePage.tsx From apps with GNU Affero General Public License v3.0 | 6 votes |
jest.mock('next/router', () => ({
useRouter: jest.fn().mockImplementation(
() =>
({
isFallback: false,
query: {},
} as unknown as NextRouter),
),
}));
Example #6
Source File: index.ts From bada-frame with GNU General Public License v3.0 | 6 votes |
export async function checkSubscriptionPurchase(
setDialogMessage: SetDialogMessage,
router: NextRouter,
setLoading: SetLoading
) {
const { session_id: sessionId, status, reason } = router.query ?? {};
try {
if (status === RESPONSE_STATUS.fail) {
handleFailureReason(reason as string, setDialogMessage, setLoading);
} else if (status === RESPONSE_STATUS.success) {
try {
const subscription = await billingService.verifySubscription(
sessionId as string
);
setDialogMessage({
title: constants.SUBSCRIPTION_PURCHASE_SUCCESS_TITLE,
close: { variant: 'success' },
content: constants.SUBSCRIPTION_PURCHASE_SUCCESS(
subscription?.expiryTime
),
});
} catch (e) {
setDialogMessage({
title: constants.ERROR,
content: CustomError.SUBSCRIPTION_VERIFICATION_ERROR,
close: {},
});
}
}
} catch (e) {
// ignore
}
}
Example #7
Source File: TagPage.tsx From apps with GNU Affero General Public License v3.0 | 6 votes |
jest.mock('next/router', () => ({
useRouter: jest.fn().mockImplementation(
() =>
({
isFallback: false,
query: {},
} as unknown as NextRouter),
),
}));
Example #8
Source File: language-select.tsx From bedrock-dot-dev with GNU General Public License v3.0 | 6 votes |
checkRoute = async (router: NextRouter, nextLocale: string): Promise<boolean> => {
const version = (router.query?.slug || []).slice(0, -1)
// ignore paths that are not under the docs page
if (!router.route.startsWith('/docs')) return true
if (version.length === 1 && TagsValues.includes(version[0])) return true
else if (version.length === 2) {
// get the docs manifest
if (!docsManifest) {
console.log('Fetching docs manifest...')
try {
const response = await fetch('/static/docs.json')
docsManifest = (await response.json()) as BedrockVersionsFile
} catch (e) {
console.error('Could not get docs manifest!')
}
}
// check that the version has the locale
const availableLocales = docsManifest?.byLocale?.[version[1]] ?? []
return availableLocales.includes(nextLocale as Locale)
}
return false
}
Example #9
Source File: utils.ts From liferay-grow with MIT License | 6 votes |
getCurrentStep = (router: NextRouter): string => {
return router.pathname.replace('/welcome/', '');
}
Example #10
Source File: RouterPrinter.tsx From next-page-tester with MIT License | 6 votes |
export function RouterPrinter({ routerMock }: { routerMock?: NextRouter }) {
const router = routerMock || useRouter();
const { query, pathname, asPath, route, basePath } = router;
return (
<>
Router:
{stringify({ asPath, pathname, query, route, basePath })}
</>
);
}
Example #11
Source File: _error.tsx From keycapsets.com with GNU General Public License v3.0 | 6 votes |
function Error(props: ErrorProps) {
const { statusCode } = props;
const title = `Error Keycapsets`;
const description = `This page doesn't exist...`;
const [isSearchError, setIsSearchError] = useState<boolean>(false);
const router: NextRouter = useRouter();
useEffect(() => {
if (router.query.set) {
setIsSearchError(true);
}
}, [router.query]);
function searchByWrongQuery() {
const reboundUrl = `/?search=${router.query.set}`;
router.push(reboundUrl);
}
return (
<div className="container error-page">
{!isSearchError ? (
<Heading mainTitle={`An error occurred`} subTitle={statusCode} backgroundColor="#f8abab" />
) : (
<div className="rebound-search-error">
<h1 className={`title no-bold center`}>There is no set on this page.</h1>
<h4 className={`title-sub italic center`}>Would you like to search for {router.query.set}?</h4>
<Button variant="primary" size="lg" className="center" onClick={searchByWrongQuery}>
Search for {router.query.set} on keycapsets.com
</Button>
</div>
)}
</div>
);
}
Example #12
Source File: SearchPage.tsx From apps with GNU Affero General Public License v3.0 | 6 votes |
it('should request search feed', async () => {
const query = { q: 'daily' };
mocked(useRouter).mockImplementation(
() =>
({
pathname: '/search',
query,
} as unknown as NextRouter),
);
renderComponent([
createFeedMock(defaultFeedPage, SEARCH_POSTS_QUERY, {
first: 7,
loggedIn: true,
query: 'daily',
unreadOnly: false,
}),
]);
await waitFor(async () => {
const elements = await screen.findAllByTestId('postItem');
expect(elements.length).toBeTruthy();
});
});
Example #13
Source File: Nav.tsx From vignette-web with MIT License | 5 votes |
// en: `ENG`,
// ja: `日本`,
// ko: `한국`,
// 'zh-CN': `中国`,
// 'zh-TW': `中国`,
// fil: `FIL`,
// fr: `FR`,
// id: `IDN`,
// de: `DE`,
// it: `IT`,
// nl: `NL`,
function MyListbox({ router }: { router: NextRouter }) {
const [selectedLocale, setSelectedLocale] = useState(router.locale)
return (
<div>
<Listbox
value={selectedLocale}
onChange={(selected) => {
setSelectedLocale(selected)
setCookies(`NEXT_LOCALE`, selected)
router.push(router.asPath, undefined, {
locale: selected,
})
}}
>
<Listbox.Button className="relative flex w-full cursor-default items-center rounded-lg bg-transparent pl-1 text-left text-sm font-semibold outline-none sm:font-normal">
<ReactCountryFlag
countryCode={locales[selectedLocale as string].flag}
svg
/>
<span className="mx-1">
{locales[selectedLocale as string].shortName}
</span>
<BiChevronDown />
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="w-18 absolute z-100 mt-1 max-h-96 overflow-auto rounded-md border bg-white text-black shadow-lg focus:outline-none dark:border-neutral-700 dark:bg-[#181a1b] dark:text-white">
{Object.keys(locales).map((key) => (
/* Use the `active` state to conditionally style the active option. */
/* Use the `selected` state to conditionally style the selected option. */
<Listbox.Option key={key} value={key} as={Fragment}>
{({ active, selected }) => (
<li
className={`flex cursor-default items-center px-2 py-1 sm:px-1 lg:py-0 ${
active
? `bg-gray-100 dark:bg-neutral-700 `
: `bg-white dark:bg-[#181a1b]`
}`}
>
<ReactCountryFlag countryCode={locales[key].flag} svg />
<span className="mx-1 text-sm text-black dark:text-white">
{locales[key].name}
</span>
{selected && (
<AiOutlineCheck className="fill-black dark:fill-white" />
)}
</li>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</Listbox>
</div>
)
}
Example #14
Source File: index.tsx From next-translate-routes with MIT License | 5 votes |
enhanceNextRouter = ({ push, replace, prefetch, locale, ...otherRouterProps }: NextRouter): NextRouter => {
const { debug } = getNtrData()
return {
push: (url: Url, as?: Url, options?: TransitionOptions) => {
const translatedUrl =
as ||
(options?.locale || locale
? translateUrl(url, options?.locale || (locale as string), { format: 'object' })
: url)
if (debug) {
console.log('[next-translate-routes] - router.push.', { url, as, options, translatedUrl, locale })
}
return push(translatedUrl, as, options)
},
replace: (url: Url, as?: Url, options?: TransitionOptions) => {
const translatedUrl =
as ||
(options?.locale || locale
? translateUrl(url, options?.locale || (locale as string), { format: 'object' })
: url)
if (debug) {
console.log('[next-translate-routes] - router.replace.', { url, as, options, translatedUrl, locale })
}
return replace(translatedUrl, as, options)
},
prefetch: (inputUrl: string, asPath?: string, options?: PrefetchOptions) => {
const as =
asPath ||
(options?.locale || locale
? (translateUrl(inputUrl, options?.locale || (locale as string), { format: 'string' }) as string)
: inputUrl)
if (debug) {
console.log('[next-translate-routes] - router.prefetch.', { inputUrl, asPath, options, as, locale })
}
return prefetch(inputUrl, as, options)
},
locale,
...otherRouterProps,
}
}
Example #15
Source File: BlogNav.tsx From vignette-web with MIT License | 5 votes |
// en: `ENG`,
// ja: `日本`,
// ko: `한국`,
// 'zh-CN': `中国`,
// 'zh-TW': `中国`,
// fil: `FIL`,
// fr: `FR`,
// id: `IDN`,
// de: `DE`,
// it: `IT`,
// nl: `NL`,
function MyListbox({ router }: { router: NextRouter }) {
const [selectedLocale, setSelectedLocale] = useState(router.locale)
return (
<div>
<Listbox
value={selectedLocale}
onChange={(selected) => {
setSelectedLocale(selected)
setCookies(`NEXT_LOCALE`, selected)
router.push(router.asPath, undefined, {
locale: selected,
})
}}
>
<Listbox.Button className="relative flex w-full cursor-default items-center rounded-lg bg-transparent pl-1 text-left text-sm font-semibold outline-none sm:font-normal">
<ReactCountryFlag
countryCode={locales[selectedLocale as string].flag}
svg
/>
<span className="mx-1">
{locales[selectedLocale as string].shortName}
</span>
<BiChevronDown />
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options className="w-18 absolute z-100 mt-1 max-h-96 overflow-auto rounded-md border bg-white text-black shadow-lg focus:outline-none dark:border-neutral-700 dark:bg-[#181a1b] dark:text-white">
{Object.keys(locales).map((key) => (
/* Use the `active` state to conditionally style the active option. */
/* Use the `selected` state to conditionally style the selected option. */
<Listbox.Option key={key} value={key} as={Fragment}>
{({ active, selected }) => (
<li
className={`flex cursor-default items-center px-2 py-1 sm:px-1 lg:py-0 ${
active
? `bg-gray-100 dark:bg-neutral-700 `
: `bg-white dark:bg-[#181a1b]`
}`}
>
<ReactCountryFlag countryCode={locales[key].flag} svg />
<span className="mx-1 text-sm text-black dark:text-white">
{locales[key].name}
</span>
{selected && (
<AiOutlineCheck className="fill-black dark:fill-white" />
)}
</li>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</Listbox>
</div>
)
}
Example #16
Source File: CustomRouter.ts From apps with GNU Affero General Public License v3.0 | 5 votes |
export default class CustomRouter implements NextRouter {
asPath = '/';
back(): void {
window.history.back();
}
basePath = '/';
beforePopState(): void {
// No need to do anything
}
events = {
on: () => {
// No need to do anything
},
off: () => {
// No need to do anything
},
} as unknown as MittEmitter<RouterEvent>;
isFallback = false;
isLocaleDomain = false;
isPreview = false;
isReady = true;
pathname = '/';
prefetch(): Promise<void> {
return Promise.resolve();
}
async push(url: Url): Promise<boolean> {
window.location.href = url as string;
return true;
}
query = {};
reload(): void {
window.location.reload();
}
async replace(url: Url): Promise<boolean> {
window.location.href = url as string;
return true;
}
route = '/';
}
Example #17
Source File: subscribe.tsx From samuelkraft-next with MIT License | 5 votes |
Subscribe = ({ title, header = true, className }: SubscribeProps) => {
const { query } = useRouter() as NextRouter
const inputEl = useRef(null)
const [message, setMessage] = useState('')
const [loading, setLoading] = useState(false)
const subscribe = async e => {
e.preventDefault()
setLoading(true)
const res = await fetch('/api/subscribe', {
body: JSON.stringify({
email: inputEl.current.value,
}),
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
})
const { error } = await res.json()
if (error) {
setLoading(false)
setMessage(error)
return
}
inputEl.current.value = ''
setLoading(false)
setMessage('Thanks! Check you inbox for a confirmation email ✨')
}
const wrapperClassName = cn(styles.wrapper, className)
if (query.confirmed) {
return (
<div className={wrapperClassName}>
<header className={styles.header}>
<CheckCircle style={{ color: 'green' }} />
<h4 className={styles.title}>Thanks for confirming your email!</h4>
</header>
<p className={styles.description} style={{ marginBottom: 0 }}>
You're on the list and will get updates when new content is published.
</p>
</div>
)
}
return (
<form onSubmit={subscribe} className={wrapperClassName}>
{header && (
<>
<header className={styles.header}>
<Send />
<p className={styles.title}>{title || 'Enjoyed this post? Subscribe to the newsletter!'}</p>
</header>
<p className={styles.description}>
A newsletter in the realm between <em className={styles.em}>design & development</em>. Learn animations, CSS, web
development tips & tricks and creating delightful and useful interfaces!
</p>
<p className={styles.description}>No spam, unsubcribe at any time!</p>
</>
)}
<label htmlFor="email-input" className="sr-only">
Email address
</label>
<div className={cn(styles.inputWrapper, message && styles.hidden)}>
<input className={styles.input} id="email-input" name="email" placeholder="Email address" ref={inputEl} required type="email" />
<Button disabled={loading} type="submit">
Subscribe
</Button>
{message && <div className={styles.message}>{message}</div>}
</div>
</form>
)
}
Example #18
Source File: errors.tsx From kratos-selfservice-ui-react-nextjs with Apache License 2.0 | 5 votes |
// A small function to help us deal with errors coming from fetching a flow.
export function handleGetFlowError<S>(
router: NextRouter,
flowType: 'login' | 'registration' | 'settings' | 'recovery' | 'verification',
resetFlow: Dispatch<SetStateAction<S | undefined>>
) {
return async (err: AxiosError) => {
switch (err.response?.data.error?.id) {
case 'session_aal2_required':
// 2FA is enabled and enforced, but user did not perform 2fa yet!
window.location.href = err.response?.data.redirect_browser_to
return
case 'session_already_available':
// User is already signed in, let's redirect them home!
await router.push('/')
return
case 'session_refresh_required':
// We need to re-authenticate to perform this action
window.location.href = err.response?.data.redirect_browser_to
return
case 'self_service_flow_return_to_forbidden':
// The flow expired, let's request a new one.
toast.error('The return_to address is not allowed.')
resetFlow(undefined)
await router.push('/' + flowType)
return
case 'self_service_flow_expired':
// The flow expired, let's request a new one.
toast.error('Your interaction expired, please fill out the form again.')
resetFlow(undefined)
await router.push('/' + flowType)
return
case 'security_csrf_violation':
// A CSRF violation occurred. Best to just refresh the flow!
toast.error(
'A security violation was detected, please fill out the form again.'
)
resetFlow(undefined)
await router.push('/' + flowType)
return
case 'security_identity_mismatch':
// The requested item was intended for someone else. Let's request a new flow...
resetFlow(undefined)
await router.push('/' + flowType)
return
case 'browser_location_change_required':
// Ory Kratos asked us to point the user to this URL.
window.location.href = err.response.data.redirect_browser_to
return
}
switch (err.response?.status) {
case 410:
// The flow expired, let's request a new one.
resetFlow(undefined)
await router.push('/' + flowType)
return
}
// We are not able to handle the error? Return it.
return Promise.reject(err)
}
}
Example #19
Source File: setup.ts From apps with GNU Affero General Public License v3.0 | 5 votes |
jest.mock('next/router', () => ({
useRouter: jest.fn().mockImplementation(
() =>
({
query: {},
} as unknown as NextRouter),
),
}));
Example #20
Source File: use.router.ts From ui with GNU Affero General Public License v3.0 | 5 votes |
useRouter = (): NextRouter => {
const router = useNextRouter()
router.query = { ...router.query, ...parseQuery(router.asPath) }
return router
}
Example #21
Source File: RedditAuth.tsx From keycapsets.com with GNU General Public License v3.0 | 5 votes |
function RedditAuth(props: RedditAuthProps): JSX.Element {
const { text, disabled, asLink = false } = props;
const router: NextRouter = useRouter();
const client = useApolloClient();
const setUser = useStore((state) => state.setUser);
useEffect(() => {
const hash = window.location.hash;
if (hash !== '') {
const fragments = router.asPath
.split('#')[1]
.split('&')
.reduce<Record<string, string>>((res, fragment) => {
const [key, value] = fragment.split('=');
return {
...res,
[key]: value,
};
}, {});
getAccesToken(fragments.access_token, fragments.state);
}
}, [router.query]);
async function getAccesToken(token: string, state: unknown) {
const {
data: { redditLogin },
} = await client.mutate({
mutation: REDDIT_LOGIN,
variables: {
token,
},
});
setUser(redditLogin?.user);
loginUser(redditLogin);
const routes = {
next: `${router.query.next}`,
edit: '/user/edit',
home: '/',
};
const route = router.query.next !== undefined ? 'next' : redditLogin.firstLogin ? 'edit' : 'home';
console.log(redditLogin, 'after login route...', route);
router.push(routes[route]);
}
return asLink ? (
<a onClick={handleRedditAuth}>
<RedditIcon variant="dark" />
{text}
</a>
) : (
<Button variant="primary" size="md" onClick={handleRedditAuth} isDisabled={disabled}>
<RedditIcon variant="white" size={16} />
{text}
</Button>
);
}
Example #22
Source File: router-mocking.test.tsx From next-page-tester with MIT License | 5 votes |
describe('Router mocking', () => {
describe('page using "useRouter"', () => {
it('receives expected router object', async () => {
const { render } = await getPage({
nextRoot,
route: '/with-router/99?foo=bar#moo',
});
const { nextRoot: actual } = render();
const { container: expected } = renderWithinNextRoot(
<WithRouter
routerMock={{
asPath: '/with-router/99?foo=bar#moo',
pathname: '/with-router/[id]',
query: {
id: '99',
foo: 'bar',
},
route: '/with-router/[id]',
basePath: '',
}}
/>
);
expectDOMElementsToMatch(actual, expected);
});
});
describe('router option', () => {
it('page receives custom router object', async () => {
const routerMock = {
route: 'mocked',
};
const { render } = await getPage({
nextRoot,
route: '/with-router/99',
router: () => routerMock as NextRouter,
});
const { nextRoot: actual } = render();
const { container: expected } = renderWithinNextRoot(
<WithRouter routerMock={routerMock} />
);
expectDOMElementsToMatch(actual, expected);
});
});
});
Example #23
Source File: setup.ts From apps with GNU Affero General Public License v3.0 | 5 votes |
jest.mock('next/router', () => ({
useRouter: jest.fn().mockImplementation(
() =>
({
query: {},
} as unknown as NextRouter),
),
}));
Example #24
Source File: etc.ts From dendron with GNU Affero General Public License v3.0 | 5 votes |
export function getNoteRouterQuery(router: NextRouter) {
return router.query as Partial<NoteRouterQuery>;
}
Example #25
Source File: Hooks.ts From frontend.ro with MIT License | 5 votes |
function useAnonymousOnly(router: NextRouter, isLoggedIn: boolean, nextHref: string) {
if (isLoggedIn && nextHref) {
if (typeof window !== 'undefined') {
router.replace(nextHref);
}
}
}
Example #26
Source File: decorators.tsx From storybook-addon-next-router with MIT License | 5 votes |
WithNextRouter = (
Story: React.FC<unknown>,
context: StoryContext
): JSX.Element => {
const { Provider, ...parameters } = context.parameters.nextRouter ?? {};
if (Provider === undefined) throw new Error('NextContext.Provider is undefined, please add it to parameters.nextRouter.Provider');
Router.router = {
locale: context?.globals?.locale,
route: '/',
pathname: '/',
query: {},
asPath: '/',
push(...args: unknown[]) {
action('nextRouter.push')(...args);
return Promise.resolve(true);
},
replace(...args: unknown[]) {
action('nextRouter.replace')(...args);
return Promise.resolve(true);
},
reload(...args: unknown[]) {
action('nextRouter.reload')(...args);
},
back(...args: unknown[]) {
action('nextRouter.back')(...args);
},
prefetch(...args: unknown[]) {
action('nextRouter.prefetch')(...args);
return Promise.resolve();
},
beforePopState(...args: unknown[]) {
action('nextRouter.beforePopState')(...args);
},
events: {
on(...args: unknown[]) {
action('nextRouter.events.on')(...args);
},
off(...args: unknown[]) {
action('nextRouter.events.off')(...args);
},
emit(...args: unknown[]) {
action('nextRouter.events.emit')(...args);
},
},
isFallback: false,
...parameters,
} as typeof Router.router;
return (
<Provider value={Router.router as NextRouter}>
<Story />
</Provider>
);
}
Example #27
Source File: Tools.ts From core with GNU Affero General Public License v3.0 | 5 votes |
export function redirectTo(router: NextRouter, to: string) {
router.push(KoreanbotsEndPoints[to] || to)
return
}
Example #28
Source File: index.tsx From next-translate-routes with MIT License | 5 votes |
withRouter = <P extends Record<string, any>>(Component: ComponentType<{ router: NextRouter } & P>) =>
Object.assign((props: P) => <Component router={useNextRouter()} {...props} />, {
displayName: `withRouter(${Component.displayName})`,
})
Example #29
Source File: SearchSets.tsx From keycapsets.com with GNU General Public License v3.0 | 4 votes |
function SearchSets() {
const router: NextRouter = useRouter();
const [searchValue, searchInput, setSearchInputValue] = useInput({
placeholder: 'E.g. ePBT, Minimal or SA',
autoFocus: true,
icon: <SearchIcon size={16} color="#bbc0c9" />,
});
const filters = useStore((state) => state.filters);
const setFilters = useStore((state) => state.setFilters);
// TODO: this supported the use of search?= query in URL...
useEffect(() => {
const searchQuery = router.query.search;
if (searchQuery !== undefined) {
// @ts-expect-error
setSearchInputValue(searchQuery);
setFilters({
...filters,
name: Array.isArray(searchQuery) ? searchQuery[0] : searchQuery,
});
}
}, [router.query.search]);
useEffect(() => {
let timeout: NodeJS.Timeout;
clearTimeout(timeout);
timeout = setTimeout(() => {
if (searchValue !== '' || searchValue !== undefined) {
filterOnOptions(searchValue);
}
}, 400);
return () => clearTimeout(timeout);
}, [searchValue]);
function filterOnOptions(searchValue) {
const match = (a, b) => a.some((v) => b.includes(v));
const keywords = searchValue.toLowerCase().split(' ');
let toRemove = [];
let brand = [];
let material = [];
let profile = [];
let availability = 'none';
ALL_OPTIONS.filter((option) => {
const label = option.label.toLowerCase().split(' ');
const value = option.value.toLowerCase().split(' ');
if (match(keywords, label) || match(keywords, value)) {
switch (option.type) {
case BRAND_FILTER:
brand.push(option.value);
break;
case MATERIAL_FILTER:
material.push(option.value);
break;
case PROFILE_FILTER:
profile.push(option.value);
break;
case AVAILABILITY_FILTER:
availability = option.value;
break;
}
toRemove.push(...label, ...value);
}
});
if (match(keywords, ['pbt']) && !match(keywords, ['epbt', 'enjoy'])) {
brand = brand.filter((brand: string) => brand !== 'epbt');
}
const name = keywords
.filter((keyword: string) => !toRemove.includes(keyword))
.join(' ')
.trim();
setFilters({
...filters,
type: profile,
name,
brand,
material,
availability,
});
}
return <div className="search-input">{searchInput}</div>;
}