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:
co-authored by
zomars
kodiakhq[bot]
parent
6a6adf1c3c
commit
58b3067b2b
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user