Hotfix Settings Shell (#4222)

* Add settings section prop to shell

* Clean up

* Adjustments

* Update Shell.tsx

* Update SettingsLayout.tsx

* Mobile drawer fixes

* Update VerticalTabItem.tsx

Co-authored-by: zomars <zomars@me.com>
Co-authored-by: kodiakhq[bot] <49736102+kodiakhq[bot]@users.noreply.github.com>
This commit is contained in:
Joe Au-Yeung
2022-09-06 19:33:50 -06:00
committed by GitHub
co-authored by zomars kodiakhq[bot]
parent 6a6adf1c3c
commit 58b3067b2b
5 changed files with 111 additions and 32 deletions
+31 -5
View File
@@ -1,13 +1,13 @@
import type { User } from "@prisma/client";
import noop from "lodash/noop";
import { signOut, useSession } from "next-auth/react";
import Link from "next/link";
import { NextRouter, useRouter } from "next/router";
import React, { Fragment, ReactNode, useEffect, useState } from "react";
import React, { Dispatch, Fragment, ReactNode, SetStateAction, useEffect, useState } from "react";
import { Toaster } from "react-hot-toast";
import dayjs from "@calcom/dayjs";
import { useIsEmbed } from "@calcom/embed-core/embed-iframe";
import LicenseBanner from "@calcom/features/ee/common/components/LicenseBanner";
import TrialBanner from "@calcom/features/ee/common/components/TrialBanner";
import ImpersonatingBanner from "@calcom/features/ee/impersonation/components/ImpersonatingBanner";
import HelpMenuItem from "@calcom/features/ee/support/components/HelpMenuItem";
@@ -147,6 +147,8 @@ const Layout = (props: LayoutProps) => {
);
};
type DrawerState = [isOpen: boolean, setDrawerOpen: Dispatch<SetStateAction<boolean>>];
type LayoutProps = {
centered?: boolean;
title?: string;
@@ -155,7 +157,11 @@ type LayoutProps = {
children: ReactNode;
CTA?: ReactNode;
large?: boolean;
SettingsSidebarContainer?: ReactNode;
MobileNavigationContainer?: ReactNode;
SidebarContainer?: ReactNode;
TopNavContainer?: ReactNode;
drawerState?: DrawerState;
HeadingLeftIcon?: ReactNode;
backPath?: string; // renders back button to specified path
// use when content needs to expand with flex
@@ -679,17 +685,37 @@ export function ShellMain(props: LayoutProps) {
);
}
function MainContainer(props: LayoutProps) {
const SettingsSidebarContainerDefault = () => null;
function MainContainer({
SettingsSidebarContainer: SettingsSidebarContainerProp = <SettingsSidebarContainerDefault />,
MobileNavigationContainer: MobileNavigationContainerProp = <MobileNavigationContainer />,
TopNavContainer: TopNavContainerProp = <TopNavContainer />,
...props
}: LayoutProps) {
const [sideContainerOpen, setSideContainerOpen] = props.drawerState || [false, noop];
return (
<main className="relative z-0 flex flex-1 flex-col overflow-y-auto bg-white focus:outline-none ">
{/* show top navigation for md and smaller (tablet and phones) */}
<TopNavContainer />
{TopNavContainerProp}
{/* The following is used for settings navigation on medium and smaller screens */}
<div
className={classNames(
"absolute z-40 m-0 h-screen w-screen bg-black opacity-50",
sideContainerOpen ? "" : "hidden"
)}
onClick={() => {
setSideContainerOpen(false);
}}
/>
{SettingsSidebarContainerProp}
<div className="px-4 py-2 lg:py-8 lg:px-12">
<ErrorBoundary>
{!props.withoutMain ? <ShellMain {...props}>{props.children}</ShellMain> : props.children}
</ErrorBoundary>
{/* show bottom navigation for md and smaller (tablet and phones) */}
<MobileNavigationContainer />
{MobileNavigationContainerProp}
{/* <LicenseBanner /> */}
</div>
</main>
+1 -1
View File
@@ -9,7 +9,7 @@ export default function AdminLayout({
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
return (
<SettingsLayout {...rest}>
<div className="mx-auto flex max-w-4xl flex-row divide-y divide-gray-200 lg:p-12">
<div className="mx-auto flex max-w-4xl flex-row divide-y divide-gray-200 md:px-12">
<div className="flex flex-1 [&>*]:flex-1">{children}</div>
</div>
</SettingsLayout>
+71 -23
View File
@@ -1,6 +1,8 @@
import React, { ComponentProps } from "react";
import React, { ComponentProps, useState } from "react";
import { classNames } from "@calcom/lib";
import { useLocale } from "@calcom/lib/hooks/useLocale";
import Button from "@calcom/ui/v2/core/Button";
import { Icon } from "../../../Icon";
import { useMeta } from "../Meta";
@@ -10,7 +12,7 @@ import VerticalTabs, { VerticalTabItem } from "../navigation/tabs/VerticalTabs";
const tabs = [
{
name: "my_account",
href: "/settings/profile",
href: "/settings/my-account",
icon: Icon.FiUser,
children: [
{ name: "profile", href: "/settings/my-account/profile" },
@@ -19,7 +21,7 @@ const tabs = [
{ name: "conferencing", href: "/settings/my-account/conferencing" },
{ name: "appearance", href: "/settings/my-account/appearance" },
// TODO
{ name: "referrals", href: "/settings/my-account/referrals" },
// { name: "referrals", href: "/settings/my-account/referrals" },
],
},
{
@@ -47,15 +49,16 @@ const tabs = [
icon: Icon.FiTerminal,
children: [
//
{ name: "webhooks", href: "/settings/developer" },
{ name: "api_keys", href: "/settings/developer" },
{ name: "embeds", href: "/settings/developer" },
{ name: "webhooks", href: "/settings/developer/webhooks" },
{ name: "api_keys", href: "/settings/developer/api_keys" },
{ name: "embeds", href: "/settings/developer/embeds" },
],
},
{
name: "teams",
href: "/settings/teams",
icon: Icon.FiUsers,
children: [],
},
{
name: "admin",
@@ -71,28 +74,73 @@ const tabs = [
},
];
const SettingsSidebarContainer = ({ className = "" }) => {
return (
<VerticalTabs tabs={tabs} className={`py-3 pl-3 ${className}`}>
<VerticalTabItem
name="Settings"
href="/"
icon={Icon.FiArrowLeft}
textClassNames="text-md font-medium leading-none text-black"
className="mb-1"
/>
</VerticalTabs>
);
};
const MobileSettingsContainer = (props: { onSideContainerOpen?: () => void }) => {
const { t } = useLocale();
return (
<>
<nav className="flex items-center justify-between border-b border-gray-100 bg-gray-50 p-4 lg:hidden">
<div className=" flex items-center space-x-3 ">
<Button
StartIcon={Icon.FiMenu}
color="minimalSecondary"
size="icon"
onClick={props.onSideContainerOpen}
/>
<a href="/" className="flex items-center space-x-2 rounded-md px-3 py-1 hover:bg-gray-200">
<Icon.FiArrowLeft className="text-gray-700" />
<p className="font-semibold text-black">{t("settings")}</p>
</a>
</div>
</nav>
</>
);
};
export default function SettingsLayout({
children,
...rest
}: { children: React.ReactNode } & ComponentProps<typeof Shell>) {
const state = useState(false);
const [sideContainerOpen, setSideContainerOpen] = state;
return (
<Shell
flexChildrenContainer
{...rest}
SidebarContainer={
<VerticalTabs tabs={tabs} className="py-3 pl-3">
<VerticalTabItem
name="Settings"
href="/"
icon={Icon.FiArrowLeft}
textClassNames="text-md font-medium leading-none text-black"
className="mb-1"
/>
</VerticalTabs>
SidebarContainer={<SettingsSidebarContainer className="hidden lg:flex" />}
drawerState={state}
MobileNavigationContainer={null}
SettingsSidebarContainer={
<div
className={classNames(
"absolute inset-y-0 z-50 m-0 h-screen transform overflow-y-scroll border-gray-100 bg-gray-50 transition duration-200 ease-in-out",
sideContainerOpen ? "translate-x-0" : "-translate-x-full"
)}>
<SettingsSidebarContainer />
</div>
}
TopNavContainer={
<MobileSettingsContainer onSideContainerOpen={() => setSideContainerOpen(!sideContainerOpen)} />
}>
<div className="flex-1 [&>*]:flex-1">
<ShellHeader />
{children}
<div className="flex flex-1 [&>*]:flex-1">
<div className="color-black mt-8 justify-center px-4 sm:px-6 md:px-8 ">
<ShellHeader />
{children}
</div>
</div>
</Shell>
);
@@ -104,17 +152,17 @@ function ShellHeader() {
const { meta } = useMeta();
const { t, isLocaleReady } = useLocale();
return (
<header className="block justify-between px-4 pt-8 sm:flex sm:px-6 md:px-8">
<div className="mb-8 w-full">
<header className="mx-auto block max-w-4xl justify-between sm:flex md:px-12 md:pt-8">
<div className="mb-8 w-full border-b border-gray-200 pb-8">
{meta.title && isLocaleReady ? (
<h1 className="font-cal mb-1 text-xl font-bold capitalize tracking-wide text-gray-900">
<h1 className="font-cal mb-1 text-xl font-bold capitalize tracking-wide text-black">
{t(meta.title)}
</h1>
) : (
<div className="mb-1 h-6 w-24 animate-pulse rounded-md bg-gray-200" />
)}
{meta.description && isLocaleReady ? (
<p className="text-sm text-neutral-500 ltr:mr-4 rtl:ml-4">{t(meta.description)}</p>
<p className="text-sm text-gray-600 ltr:mr-4 rtl:ml-4">{t(meta.description)}</p>
) : (
<div className="mb-1 h-6 w-32 animate-pulse rounded-md bg-gray-200" />
)}
@@ -68,12 +68,14 @@ const VerticalTabItem: FC<VerticalTabItemProps> = ({ name, href, tabName, info,
props.textClassNames || "text-sm font-medium leading-none text-gray-600",
"group flex h-14 w-64 flex-row items-center rounded-md px-3 py-[10px] hover:bg-gray-100 group-hover:text-gray-700 [&[aria-current='page']]:bg-gray-200 [&[aria-current='page']]:text-gray-900",
props.disabled && "pointer-events-none !opacity-30",
(isChild || !props.icon) && "ml-9 mr-5 w-auto",
(isChild || !props.icon) && "ml-7 mr-5 w-auto",
!info ? "h-9" : "h-14",
props.className
)}
aria-current={isCurrent ? "page" : undefined}>
{props.icon && <props.icon className="mr-[10px] h-[16px] w-[16px] self-start stroke-[2px]" />}
{props.icon && (
<props.icon className="mt-2 mr-[10px] h-[16px] w-[16px] self-start stroke-[2px] md:mt-0" />
)}
<div>
<p>{t(name)}</p>
{info && <p className="pt-1 text-xs font-normal">{t(info)}</p>}
@@ -16,7 +16,10 @@ export interface NavTabProps {
const NavTabs: FC<NavTabProps> = ({ tabs, className = "", sticky, ...props }) => {
return (
<nav
className={classNames(`no-scrollbar flex flex-col space-y-1 ${className}`, sticky && "sticky top-0")}
className={classNames(
`no-scrollbar flex flex-col space-y-1 overflow-scroll ${className}`,
sticky && "sticky top-0"
)}
aria-label="Tabs"
{...props}>
{props.children}