added /more page for mobile (#4219)

* added /more page for mobile

* i18n

* Navigation improvements

* Reverting unused exports

* Improved performance for getting mobile/desktop items

* I take your forEach and up it with reduce

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: Alan <alannnc@gmail.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Peer Richelsen
2022-09-06 22:13:31 -06:00
committed by GitHub
co-authored by zomars Alan kodiakhq[bot]
parent 1561224dbb
commit 30f8d12563
3 changed files with 96 additions and 29 deletions
+15
View File
@@ -0,0 +1,15 @@
import { useLocale } from "@calcom/lib/hooks/useLocale";
import { MobileNavigationMoreItems } from "@calcom/ui/Shell";
import { Shell } from "@calcom/ui/v2";
export default function MorePage() {
const { t } = useLocale();
return (
<Shell>
<div className="max-w-screen-lg">
<MobileNavigationMoreItems />
<p className="mt-6 text-xs leading-tight text-gray-500 md:hidden">{t("more_page_footer")}</p>
</div>
</Shell>
);
}
@@ -1168,6 +1168,8 @@
"for_a_maximum_of": "For a maximum of",
"event_one": "event",
"event_other": "events",
"more": "More",
"more_page_footer": "We view the mobile application as an extension of the web application. If you are performing any complication actions, please refer back to the web application.",
"workflow_example_1": "Send email reminder 24 hours before event starts to host",
"workflow_example_2": "Send SMS reminder 1 hour before event starts to host",
"workflow_example_3": "Send custom email when event is cancelled to host",
+79 -29
View File
@@ -385,6 +385,7 @@ type NavigationItemType = {
};
const requiredCredentialNavigationItems = ["Routing Forms"];
const MORE_SEPARATOR_NAME = "more";
const navigation: NavigationItemType[] = [
{
name: "event_types_page_title",
@@ -401,20 +402,6 @@ const navigation: NavigationItemType[] = [
href: "/availability",
icon: Icon.FiClock,
},
{
name: "Routing Forms",
href: "/apps/routing_forms/forms",
icon: Icon.FiFileText,
isCurrent: ({ router }) => {
return router.asPath.startsWith("/apps/routing_forms/");
},
},
{
name: "workflows",
href: "/workflows",
icon: Icon.FiZap,
pro: true,
},
{
name: "apps",
href: "/apps",
@@ -434,6 +421,24 @@ const navigation: NavigationItemType[] = [
},
],
},
{
name: MORE_SEPARATOR_NAME,
href: "/more",
icon: Icon.FiMoreHorizontal,
},
{
name: "Routing Forms",
href: "/apps/routing_forms/forms",
icon: Icon.FiFileText,
isCurrent: ({ router }) => {
return router.asPath.startsWith("/apps/routing_forms/");
},
},
{
name: "workflows",
href: "/workflows",
icon: Icon.FiZap,
},
{
name: "settings",
href: "/settings",
@@ -441,10 +446,27 @@ const navigation: NavigationItemType[] = [
},
];
const moreSeparatorIndex = navigation.findIndex((item) => item.name === MORE_SEPARATOR_NAME);
// We create all needed navigation items for the different use cases
const { desktopNavigationItems, mobileNavigationBottomItems, mobileNavigationMoreItems } = navigation.reduce<
Record<string, NavigationItemType[]>
>(
(items, item, index) => {
// We filter out the "more" separator in desktop navigation
if (item.name !== MORE_SEPARATOR_NAME) items.desktopNavigationItems.push(item);
// Items for mobile bottom navigation
if (index < moreSeparatorIndex + 1) items.mobileNavigationBottomItems.push(item);
// Items for the "more" menu in mobile navigation
else items.mobileNavigationMoreItems.push(item);
return items;
},
{ desktopNavigationItems: [], mobileNavigationBottomItems: [], mobileNavigationMoreItems: [] }
);
const Navigation = () => {
return (
<nav className="mt-2 flex-1 space-y-1 md:px-2 lg:mt-5 lg:px-0">
{navigation.map((item) => (
{desktopNavigationItems.map((item) => (
<NavigationItem key={item.name} item={item} />
))}
<div className="text-gray-500 lg:hidden">
@@ -525,14 +547,12 @@ const MobileNavigation = () => {
<>
<nav
className={classNames(
"bottom-nav fixed bottom-0 z-30 -mx-4 flex w-full bg-white shadow md:hidden",
"bottom-nav fixed bottom-0 z-30 -mx-4 flex w-full border border-t border-gray-200 bg-gray-50 px-1 shadow md:hidden",
isEmbed && "hidden"
)}>
{navigation
.filter((i) => i.href !== "/settings/profile")
.map((item, itemIdx) => (
<MobileNavigationItem key={item.name} item={item} itemIdx={itemIdx} />
))}
{mobileNavigationBottomItems.map((item) => (
<MobileNavigationItem key={item.name} item={item} />
))}
</nav>
{/* add padding to content for mobile navigation*/}
<div className="block pt-12 md:hidden" />
@@ -542,10 +562,9 @@ const MobileNavigation = () => {
const MobileNavigationItem: React.FC<{
item: NavigationItemType;
itemIdx: number;
isChild?: boolean;
}> = (props) => {
const { item, itemIdx, isChild } = props;
const { item, isChild } = props;
const router = useRouter();
const { t, isLocaleReady } = useLocale();
const isCurrent: NavigationItemType["isCurrent"] = item.isCurrent || defaultIsCurrent;
@@ -556,15 +575,11 @@ const MobileNavigationItem: React.FC<{
return (
<Link key={item.name} href={item.href}>
<a
className={classNames(
itemIdx === 0 ? "rounded-l-lg" : "",
itemIdx === navigation.length - 1 ? "rounded-r-lg" : "",
"group relative min-w-0 flex-1 overflow-hidden bg-white py-2 px-2 text-center text-xs font-medium text-neutral-400 hover:bg-gray-50 hover:text-gray-700 focus:z-10 sm:text-sm [&[aria-current='page']]:text-gray-900"
)}
className="relative my-2 min-w-0 flex-1 overflow-hidden rounded-md py-2 px-1 text-center text-xs font-medium text-neutral-400 hover:bg-gray-200 hover:text-gray-700 focus:z-10 sm:text-sm [&[aria-current='page']]:text-gray-900"
aria-current={current ? "page" : undefined}>
{item.icon && (
<item.icon
className="mx-auto mb-1 block h-5 w-5 flex-shrink-0 text-center text-gray-400 group-hover:text-gray-500 [&[aria-current='page']]:text-gray-900"
className="mx-auto mb-1 block h-5 w-5 flex-shrink-0 text-center text-inherit [&[aria-current='page']]:text-gray-900"
aria-hidden="true"
aria-current={current ? "page" : undefined}
/>
@@ -579,6 +594,33 @@ const MobileNavigationItem: React.FC<{
);
};
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-b last:border-b-0" key={item.name}>
<Link href={item.href}>
<a className="flex items-center justify-between p-5 hover:bg-gray-100">
<span className="flex items-center font-semibold text-gray-700 ">
{item.icon && (
<item.icon className="h-5 w-5 flex-shrink-0 ltr:mr-3 rtl:ml-3" aria-hidden="true" />
)}
{isLocaleReady ? t(item.name) : <SkeletonText className="" />}
</span>
<Icon.FiArrowRight className="h-5 w-5 text-gray-500" />
</a>
</Link>
</li>
);
};
function DeploymentInfo() {
const query = useMeQuery();
const user = query.data;
@@ -757,3 +799,11 @@ function TopNav() {
</nav>
);
}
export const MobileNavigationMoreItems = () => (
<ul className="mt-2 rounded-md border">
{mobileNavigationMoreItems.map((item) => (
<MobileNavigationMoreItem key={item.name} item={item} />
))}
</ul>
);