* wip * fix * fix * refactor * rename to routingServerSidePropsConfig * refactor * refactor * add routing-link to useIsBookingPage hook * remove Head component * fix * redirect user to apps/routing-forms/forms if user goes to apps/routing-forms * refactor * remove log * remove client component not needed * clean up code * remove unneeded metadata * clean up further * clean up further 2 * fix type check * routing-link does not need shell * Fix title for Routing Form public link and also remove any * Remove ; in HTML * Remove unnecessary page reload --------- Co-authored-by: Hariom Balhara <hariombalhara@gmgmail.com>
162 lines
6.0 KiB
TypeScript
162 lines
6.0 KiB
TypeScript
import Link from "next/link";
|
|
import { usePathname } from "next/navigation";
|
|
import React, { Fragment } from "react";
|
|
|
|
import { classNames } from "@calcom/lib";
|
|
import { useLocale } from "@calcom/lib/hooks/useLocale";
|
|
import { Tooltip, Icon, SkeletonText } from "@calcom/ui";
|
|
import type { IconName } from "@calcom/ui";
|
|
|
|
import { useShouldDisplayNavigationItem } from "./useShouldDisplayNavigationItem";
|
|
|
|
export type NavigationItemType = {
|
|
name: string;
|
|
href: string;
|
|
isLoading?: boolean;
|
|
onClick?: React.MouseEventHandler<HTMLAnchorElement | HTMLButtonElement>;
|
|
target?: HTMLAnchorElement["target"];
|
|
badge?: React.ReactNode;
|
|
icon?: IconName;
|
|
child?: NavigationItemType[];
|
|
pro?: true;
|
|
onlyMobile?: boolean;
|
|
onlyDesktop?: boolean;
|
|
moreOnMobile?: boolean;
|
|
isCurrent?: ({
|
|
item,
|
|
isChild,
|
|
pathname,
|
|
}: {
|
|
item: Pick<NavigationItemType, "href">;
|
|
isChild?: boolean;
|
|
pathname: string | null;
|
|
}) => boolean;
|
|
};
|
|
|
|
const defaultIsCurrent: NavigationItemType["isCurrent"] = ({ isChild, item, pathname }) => {
|
|
return isChild ? item.href === pathname : item.href ? pathname?.startsWith(item.href) ?? false : false;
|
|
};
|
|
|
|
export const NavigationItem: React.FC<{
|
|
index?: number;
|
|
item: NavigationItemType;
|
|
isChild?: boolean;
|
|
}> = (props) => {
|
|
const { item, isChild } = props;
|
|
const { t, isLocaleReady } = useLocale();
|
|
const pathname = usePathname();
|
|
const isCurrent: NavigationItemType["isCurrent"] = item.isCurrent || defaultIsCurrent;
|
|
const current = isCurrent({ isChild: !!isChild, item, pathname });
|
|
const shouldDisplayNavigationItem = useShouldDisplayNavigationItem(props.item);
|
|
|
|
if (!shouldDisplayNavigationItem) return null;
|
|
|
|
return (
|
|
<Fragment>
|
|
<Tooltip side="right" content={t(item.name)} className="lg:hidden">
|
|
<Link
|
|
data-test-id={item.name}
|
|
href={item.href}
|
|
aria-label={t(item.name)}
|
|
target={item.target}
|
|
className={classNames(
|
|
"todesktop:py-[7px] text-default group flex items-center rounded-md px-2 py-1.5 text-sm font-medium transition",
|
|
item.child ? `[&[aria-current='page']]:!bg-transparent` : `[&[aria-current='page']]:bg-emphasis`,
|
|
isChild
|
|
? `[&[aria-current='page']]:text-emphasis [&[aria-current='page']]:bg-emphasis hidden h-8 pl-16 lg:flex lg:pl-11 ${
|
|
props.index === 0 ? "mt-0" : "mt-px"
|
|
}`
|
|
: "[&[aria-current='page']]:text-emphasis mt-0.5 text-sm",
|
|
isLocaleReady
|
|
? "hover:bg-subtle todesktop:[&[aria-current='page']]:bg-emphasis todesktop:hover:bg-transparent hover:text-emphasis"
|
|
: ""
|
|
)}
|
|
aria-current={current ? "page" : undefined}>
|
|
{item.icon && (
|
|
<Icon
|
|
name={item.isLoading ? "rotate-cw" : item.icon}
|
|
className={classNames(
|
|
"todesktop:!text-blue-500 mr-2 h-4 w-4 flex-shrink-0 rtl:ml-2 md:ltr:mx-auto lg:ltr:mr-2 [&[aria-current='page']]:text-inherit",
|
|
item.isLoading && "animate-spin"
|
|
)}
|
|
aria-hidden="true"
|
|
aria-current={current ? "page" : undefined}
|
|
/>
|
|
)}
|
|
{isLocaleReady ? (
|
|
<span
|
|
className="hidden w-full justify-between truncate text-ellipsis lg:flex"
|
|
data-testid={`${item.name}-test`}>
|
|
{t(item.name)}
|
|
{item.badge && item.badge}
|
|
</span>
|
|
) : (
|
|
<SkeletonText className="h-[20px] w-full" />
|
|
)}
|
|
</Link>
|
|
</Tooltip>
|
|
{item.child &&
|
|
isCurrent({ pathname, isChild, item }) &&
|
|
item.child.map((item, index) => <NavigationItem index={index} key={item.name} item={item} isChild />)}
|
|
</Fragment>
|
|
);
|
|
};
|
|
|
|
export const MobileNavigationItem: React.FC<{
|
|
item: NavigationItemType;
|
|
isChild?: boolean;
|
|
}> = (props) => {
|
|
const { item, isChild } = props;
|
|
const pathname = usePathname();
|
|
const { t, isLocaleReady } = useLocale();
|
|
const isCurrent: NavigationItemType["isCurrent"] = item.isCurrent || defaultIsCurrent;
|
|
const current = isCurrent({ isChild: !!isChild, item, pathname });
|
|
const shouldDisplayNavigationItem = useShouldDisplayNavigationItem(props.item);
|
|
|
|
if (!shouldDisplayNavigationItem) return null;
|
|
return (
|
|
<Link
|
|
key={item.name}
|
|
href={item.href}
|
|
target={item.target}
|
|
className="[&[aria-current='page']]:text-emphasis hover:text-default text-muted relative my-2 min-w-0 flex-1 overflow-hidden rounded-md !bg-transparent p-1 text-center text-xs font-medium focus:z-10 sm:text-sm"
|
|
aria-current={current ? "page" : undefined}>
|
|
{item.badge && <div className="absolute right-1 top-1">{item.badge}</div>}
|
|
{item.icon && (
|
|
<Icon
|
|
name={item.icon}
|
|
className="[&[aria-current='page']]:text-emphasis mx-auto mb-1 block h-5 w-5 flex-shrink-0 text-center text-inherit"
|
|
aria-hidden="true"
|
|
aria-current={current ? "page" : undefined}
|
|
/>
|
|
)}
|
|
{isLocaleReady ? <span className="block truncate">{t(item.name)}</span> : <SkeletonText />}
|
|
</Link>
|
|
);
|
|
};
|
|
|
|
export const MobileNavigationMoreItem: React.FC<{
|
|
item: NavigationItemType;
|
|
isChild?: boolean;
|
|
}> = (props) => {
|
|
const { item } = props;
|
|
const { t, isLocaleReady } = useLocale();
|
|
const shouldDisplayNavigationItem = useShouldDisplayNavigationItem(props.item);
|
|
|
|
if (!shouldDisplayNavigationItem) return null;
|
|
|
|
return (
|
|
<li className="border-subtle border-b last:border-b-0" key={item.name}>
|
|
<Link href={item.href} className="hover:bg-subtle flex items-center justify-between p-5 transition">
|
|
<span className="text-default flex items-center font-semibold ">
|
|
{item.icon && (
|
|
<Icon name={item.icon} className="h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3" aria-hidden="true" />
|
|
)}
|
|
{isLocaleReady ? t(item.name) : <SkeletonText />}
|
|
</span>
|
|
<Icon name="arrow-right" className="text-subtle h-5 w-5" />
|
|
</Link>
|
|
</li>
|
|
);
|
|
};
|