dress/resources/js/hooks/use-current-url.ts

101 lines
2.7 KiB
TypeScript

import type { InertiaLinkProps } from '@inertiajs/react';
import { usePage } from '@inertiajs/react';
import { toUrl } from '@/lib/utils';
export type IsCurrentUrlFn = (
urlToCheck: NonNullable<InertiaLinkProps['href']>,
currentUrl?: string,
startsWith?: boolean,
) => boolean;
export type IsCurrentOrParentUrlFn = (
urlToCheck: NonNullable<InertiaLinkProps['href']>,
currentUrl?: string,
) => boolean;
export type WhenCurrentUrlFn = <TIfTrue, TIfFalse = null>(
urlToCheck: NonNullable<InertiaLinkProps['href']>,
ifTrue: TIfTrue,
ifFalse?: TIfFalse,
) => TIfTrue | TIfFalse;
export type UseCurrentUrlReturn = {
currentUrl: string;
isCurrentUrl: IsCurrentUrlFn;
isCurrentOrParentUrl: IsCurrentOrParentUrlFn;
whenCurrentUrl: WhenCurrentUrlFn;
};
export function useCurrentUrl(): UseCurrentUrlReturn {
const page = usePage();
const currentUrlPath = new URL(
page.url,
typeof window !== 'undefined'
? window.location.origin
: 'http://localhost',
).pathname;
const isCurrentUrl: IsCurrentUrlFn = (
urlToCheck: NonNullable<InertiaLinkProps['href']>,
currentUrl?: string,
startsWith: boolean = false,
) => {
const urlString = toUrl(urlToCheck);
const currentPath = currentUrl ?? currentUrlPath;
const clean = (p: string) => {
if (!p) {
return '/';
}
// Remove query and hash, then trailing slash
let path = p.split('?')[0].split('#')[0];
if (path.startsWith('http')) {
try {
path = new URL(path).pathname;
} catch {
// Ignore
}
}
return path.replace(/\/+$/, '') || '/';
};
const normCurrent = clean(currentPath);
const normCheck = clean(urlString);
if (startsWith) {
if (normCheck === '/') {
return normCurrent === '/';
}
return normCurrent.startsWith(normCheck);
}
return normCurrent === normCheck;
};
const isCurrentOrParentUrl: IsCurrentOrParentUrlFn = (
urlToCheck: NonNullable<InertiaLinkProps['href']>,
currentUrl?: string,
) => {
return isCurrentUrl(urlToCheck, currentUrl, true);
};
const whenCurrentUrl: WhenCurrentUrlFn = <TIfTrue, TIfFalse = null>(
urlToCheck: NonNullable<InertiaLinkProps['href']>,
ifTrue: TIfTrue,
ifFalse: TIfFalse = null as TIfFalse,
): TIfTrue | TIfFalse => {
return isCurrentUrl(urlToCheck) ? ifTrue : ifFalse;
};
return {
currentUrl: currentUrlPath,
isCurrentUrl,
isCurrentOrParentUrl,
whenCurrentUrl,
};
}