From 588748d78ebf65021997460ebd2b648f95782656 Mon Sep 17 00:00:00 2001 From: zomars Date: Mon, 19 Sep 2022 00:14:57 +0100 Subject: [PATCH] Simplifies Vertical and Horizontal tabs --- apps/web/components/Embed.tsx | 72 +++------ .../v2/eventtype/EventTypeSingleLayout.tsx | 143 +++++++++--------- apps/web/pages/event-types/[type].tsx | 4 +- packages/ui/v2/core/layouts/BookingLayout.tsx | 4 +- .../v2/core/layouts/InstalledAppsLayout.tsx | 4 +- .../navigation/tabs/HorizontalTabItem.tsx | 55 ++----- .../core/navigation/tabs/HorizontalTabs.tsx | 11 +- .../core/navigation/tabs/VerticalTabItem.tsx | 62 ++------ .../v2/core/navigation/tabs/VerticalTabs.tsx | 18 +-- 9 files changed, 134 insertions(+), 239 deletions(-) diff --git a/apps/web/components/Embed.tsx b/apps/web/components/Embed.tsx index d0091afa64..780ca6af3e 100644 --- a/apps/web/components/Embed.tsx +++ b/apps/web/components/Embed.tsx @@ -8,8 +8,7 @@ import { useLocale } from "@calcom/lib/hooks/useLocale"; import { Dialog, DialogClose, DialogContent } from "@calcom/ui/Dialog"; import { Icon } from "@calcom/ui/Icon"; import { InputLeading, Label, TextArea, TextField } from "@calcom/ui/form/fields"; -import { HorizontalTabs, showToast } from "@calcom/ui/v2"; -import { Button, Switch } from "@calcom/ui/v2"; +import { Button, HorizontalTabs, showToast, Switch } from "@calcom/ui/v2"; import { EMBED_LIB_URL, WEBAPP_URL } from "@lib/config/constants"; @@ -452,7 +451,7 @@ const embeds: { const tabs = [ { name: "HTML", - embedTabName: "embed-code", + href: "embedTabName=embed-code", icon: Icon.FiCode, type: "code", Component: forwardRef< @@ -503,7 +502,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "HTML", embedType, calLink, previ }, { name: "React", - embedTabName: "embed-react", + href: "embedTabName=embed-react", icon: Icon.FiCode, type: "code", Component: forwardRef< @@ -543,7 +542,7 @@ ${getEmbedTypeSpecificString({ embedFramework: "react", embedType, calLink, prev }, { name: "Preview", - embedTabName: "embed-preview", + href: "embedTabName=embed-preview", icon: Icon.FiEye, type: "iframe", Component: forwardRef< @@ -606,12 +605,9 @@ const ChooseEmbedTypesDialogContent = () => { key={index} data-testid={embed.type} onClick={() => { - router.push({ - query: { - ...router.query, - embedType: embed.type, - }, - }); + const newQuery = new URLSearchParams(router.asPath); + newQuery.set("embedType", embed.type); + router.push(`${router.asPath.split("?")[0]}?${newQuery.toString()}`); }}>
{embed.illustration} @@ -635,6 +631,13 @@ const EmbedTypeCodeAndPreviewDialogContent = ({ const { t } = useLocale(); const router = useRouter(); const iframeRef = useRef(null); + const s = (href: string) => { + const searchParams = new URLSearchParams(router.asPath); + const [a, b] = href.split("="); + searchParams.set(a, b); + return `${router.asPath.split("?")[0]}?${searchParams.toString()}`; + }; + const parsedTabs = tabs.map((t) => ({ ...t, href: s(t.href) })); const embedCodeRefs: Record> = {}; tabs .filter((tab) => tab.type === "code") @@ -676,16 +679,6 @@ const EmbedTypeCodeAndPreviewDialogContent = ({ }); }; - // Use embed-code as default tab - if (!router.query.embedTabName) { - router.query.embedTabName = "embed-code"; - router.push({ - query: { - ...router.query, - }, - }); - } - if (!embed || !embedUrl) { close(); return null; @@ -785,14 +778,10 @@ const EmbedTypeCodeAndPreviewDialogContent = ({
- + {tabs.map((tab) => { return (
+ key={tab.href} + className={classNames(router.asPath === tab.href ? "flex flex-grow flex-col" : "hidden")}>
{tab.type === "code" ? ( ({ const router = useRouter(); className = classNames(className, "hidden lg:inline-flex"); const openEmbedModal = () => { - const query = { - ...router.query, - dialog: "embed", - embedUrl, - }; - router.push( - { - pathname: router.pathname, - query, - }, - undefined, - { shallow: true } - ); + const searchParams = new URLSearchParams(router.asPath); + searchParams.set("dialog", "embed"); + searchParams.set("embedUrl", embedUrl); + router.push(`${router.asPath.split("?")[0]}?${searchParams.toString()}`, undefined, { shallow: true }); }; const Component = as ?? Button; diff --git a/apps/web/components/v2/eventtype/EventTypeSingleLayout.tsx b/apps/web/components/v2/eventtype/EventTypeSingleLayout.tsx index 810896aabc..7524857639 100644 --- a/apps/web/components/v2/eventtype/EventTypeSingleLayout.tsx +++ b/apps/web/components/v2/eventtype/EventTypeSingleLayout.tsx @@ -1,6 +1,6 @@ -import { useRouter } from "next/router"; +import { TFunction } from "next-i18next"; import { EventTypeSetupInfered, FormValues } from "pages/v2/event-types/[type]"; -import { useEffect, useMemo, useState } from "react"; +import { useMemo, useState } from "react"; import { Loader } from "react-feather"; import { UseFormReturn } from "react-hook-form"; @@ -9,20 +9,18 @@ import { CAL_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { HttpError } from "@calcom/lib/http-error"; import { trpc, TRPCClientError } from "@calcom/trpc/react"; -import ConfirmationDialogContent from "@calcom/ui/ConfirmationDialogContent"; import { Icon } from "@calcom/ui/Icon"; import { Button, ButtonGroup, - Tooltip, - showToast, - VerticalTabItemProps, - VerticalTabs, HorizontalTabs, - Switch, Label, - HorizontalTabItemProps, + showToast, + Switch, + Tooltip, + VerticalTabs, } from "@calcom/ui/v2"; +import ConfirmationDialogContent from "@calcom/ui/v2/core/ConfirmationDialogContent"; import { Dialog } from "@calcom/ui/v2/core/Dialog"; import Dropdown, { DropdownMenuContent, @@ -46,6 +44,59 @@ type Props = { formMethods: UseFormReturn; }; +function getNavigation(props: { + t: TFunction; + eventType: Props["eventType"]; + enabledAppsNumber: number; + enabledWorkflowsNumber: number; +}) { + const { eventType, t, enabledAppsNumber, enabledWorkflowsNumber } = props; + return [ + { + name: "event_setup_tab_title", + href: `/event-types/${eventType.id}?tabName=setup`, + icon: Icon.FiLink, + info: `${eventType.length} Mins`, // TODO: Get this from props + }, + { + name: "availability", + href: `/event-types/${eventType.id}?tabName=availability`, + icon: Icon.FiCalendar, + info: `Working Hours`, // TODO: Get this from props + }, + { + name: "event_limit_tab_title", + href: `/event-types/${eventType.id}?tabName=limits`, + icon: Icon.FiClock, + info: `event_limit_tab_description`, + }, + { + name: "event_advanced_tab_title", + href: `/event-types/${eventType.id}?tabName=advanced`, + icon: Icon.FiSliders, + info: `event_advanced_tab_description`, + }, + { + name: "recurring", + href: `/event-types/${eventType.id}?tabName=recurring`, + icon: Icon.FiRepeat, + info: `recurring_event_tab_description`, + }, + { + name: "apps", + href: `/event-types/${eventType.id}?tabName=apps`, + icon: Icon.FiGrid, + info: `${enabledAppsNumber} ${t("active")}`, + }, + { + name: "workflows", + href: `/event-types/${eventType.id}?tabName=workflows`, + icon: Icon.FiZap, + info: `${enabledWorkflowsNumber} ${t("active")}`, + }, + ]; +} + function EventTypeSingleLayout({ children, eventType, @@ -57,7 +108,6 @@ function EventTypeSingleLayout({ formMethods, }: Props) { const utils = trpc.useContext(); - const router = useRouter(); const { t } = useLocale(); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); @@ -82,73 +132,17 @@ function EventTypeSingleLayout({ // Define tab navigation here const EventTypeTabs = useMemo(() => { - const navigation: (VerticalTabItemProps & HorizontalTabItemProps)[] = [ - { - name: "event_setup_tab_title", - tabName: "setup", - icon: Icon.FiLink, - info: `${eventType.length} Mins`, // TODO: Get this from props - }, - { - name: "availability", - tabName: "availability", - icon: Icon.FiCalendar, - info: `Working Hours`, // TODO: Get this from props - }, - { - name: "event_limit_tab_title", - tabName: "limits", - icon: Icon.FiClock, - info: `event_limit_tab_description`, - }, - { - name: "event_advanced_tab_title", - tabName: "advanced", - icon: Icon.FiSliders, - info: `event_advanced_tab_description`, - }, - { - name: "recurring", - tabName: "recurring", - icon: Icon.FiRepeat, - info: `recurring_event_tab_description`, - }, - { - name: "apps", - tabName: "apps", - icon: Icon.FiGrid, - info: `${enabledAppsNumber} ${t("active")}`, - }, - { - name: "workflows", - tabName: "workflows", - icon: Icon.FiZap, - info: `${enabledWorkflowsNumber} ${t("active")}`, - }, - ]; - + const navigation = getNavigation({ t, eventType, enabledAppsNumber, enabledWorkflowsNumber }); // If there is a team put this navigation item within the tabs if (team) navigation.splice(2, 0, { name: "scheduling_type", - tabName: "team", + href: `team`, icon: Icon.FiUsers, info: eventType.schedulingType === "COLLECTIVE" ? "collective" : "round_robin", }); return navigation; - }, [eventType, enabledAppsNumber, team]); - - useEffect(() => { - // Default to the first in the list - if (!router.query.tabName) { - router.push({ - query: { - ...router.query, - tabName: EventTypeTabs[0].tabName, - }, - }); - } - }, [EventTypeTabs, router]); + }, [t, eventType, enabledAppsNumber, enabledWorkflowsNumber, team]); const permalink = `${CAL_URL}/${team ? `team/${team.slug}` : eventType.users[0].username}/${ eventType.slug @@ -265,10 +259,15 @@ function EventTypeSingleLayout({ }>
- +
- +
- {t("delete_event_type_description") as string} + {t("delete_event_type_description")} diff --git a/apps/web/pages/event-types/[type].tsx b/apps/web/pages/event-types/[type].tsx index 649daf63ab..716940aee9 100644 --- a/apps/web/pages/event-types/[type].tsx +++ b/apps/web/pages/event-types/[type].tsx @@ -16,10 +16,10 @@ import { v5 as uuidv5 } from "uuid"; import { z } from "zod"; import { SelectGifInput } from "@calcom/app-store/giphy/components"; -import { getEventLocationType, EventLocationType } from "@calcom/app-store/locations"; +import { EventLocationType, getEventLocationType } from "@calcom/app-store/locations"; import { StripeData } from "@calcom/app-store/stripepayment/lib/server"; import getApps, { getLocationOptions } from "@calcom/app-store/utils"; -import { LocationObject, LocationType } from "@calcom/core/location"; +import { LocationObject } from "@calcom/core/location"; import { parseRecurringEvent } from "@calcom/lib"; import { CAL_URL, WEBAPP_URL } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; diff --git a/packages/ui/v2/core/layouts/BookingLayout.tsx b/packages/ui/v2/core/layouts/BookingLayout.tsx index 7f89fe6a83..50c01a4414 100644 --- a/packages/ui/v2/core/layouts/BookingLayout.tsx +++ b/packages/ui/v2/core/layouts/BookingLayout.tsx @@ -45,10 +45,10 @@ export default function BookingLayout({
- +
- +
{children}
diff --git a/packages/ui/v2/core/layouts/InstalledAppsLayout.tsx b/packages/ui/v2/core/layouts/InstalledAppsLayout.tsx index 08c4a0f0df..6c31609f36 100644 --- a/packages/ui/v2/core/layouts/InstalledAppsLayout.tsx +++ b/packages/ui/v2/core/layouts/InstalledAppsLayout.tsx @@ -49,10 +49,10 @@ export default function InstalledAppsLayout({
- +
- +
{children}
diff --git a/packages/ui/v2/core/navigation/tabs/HorizontalTabItem.tsx b/packages/ui/v2/core/navigation/tabs/HorizontalTabItem.tsx index 85aacedb72..271dbbed99 100644 --- a/packages/ui/v2/core/navigation/tabs/HorizontalTabItem.tsx +++ b/packages/ui/v2/core/navigation/tabs/HorizontalTabItem.tsx @@ -1,65 +1,28 @@ -import noop from "lodash/noop"; import Link from "next/link"; import { useRouter } from "next/router"; -import { MouseEventHandler } from "react"; +import { ComponentProps } from "react"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { SkeletonText } from "../../skeleton"; -export type HorizontalTabItemProps = { +export type HorizontalTabItemProps = { name: string; disabled?: boolean; className?: string; -} & ( - | { - href: string; - } - | ({ - href?: never; - } & Partial>) -); + href: string; + linkProps?: Omit, "href">; +}; -const HorizontalTabItem = function ({ - name, - href, - tabNameKey, - ...props -}: HorizontalTabItemProps & { - tabNameKey?: T; -}) { - const router = useRouter(); +const HorizontalTabItem = function ({ name, href, linkProps, ...props }: HorizontalTabItemProps) { const { t, isLocaleReady } = useLocale(); - let newHref = ""; - let isCurrent; - const _tabNameKey = tabNameKey || "tabName"; - const tabName = props[tabNameKey as keyof typeof props]; - - if (href) { - newHref = href; - isCurrent = router.asPath.startsWith(href); - } else if (tabName) { - newHref = ""; - isCurrent = router.query[_tabNameKey] === tabName; - } - - const onClick: MouseEventHandler = tabName - ? (e) => { - e.preventDefault(); - router.push({ - query: { - ...router.query, - [_tabNameKey]: tabName, - }, - }); - } - : noop; + const { asPath } = useRouter(); + const isCurrent = asPath.startsWith(href); return ( - + { - tabs: HorizontalTabItemProps[]; - tabNameKey?: T; +export interface NavTabProps { + tabs: HorizontalTabItemProps[]; + linkProps?: HorizontalTabItemProps["linkProps"]; } -const HorizontalTabs = function ({ tabs, tabNameKey, ...props }: NavTabProps) { - const _tabNameKey = tabNameKey || "tabName"; +const HorizontalTabs = function ({ tabs, linkProps, ...props }: NavTabProps) { return (
diff --git a/packages/ui/v2/core/navigation/tabs/VerticalTabItem.tsx b/packages/ui/v2/core/navigation/tabs/VerticalTabItem.tsx index 3793726c8e..cf6c7708fe 100644 --- a/packages/ui/v2/core/navigation/tabs/VerticalTabItem.tsx +++ b/packages/ui/v2/core/navigation/tabs/VerticalTabItem.tsx @@ -1,80 +1,46 @@ -import noop from "lodash/noop"; import Link from "next/link"; import { useRouter } from "next/router"; -import { Fragment, MouseEventHandler } from "react"; +import { ComponentProps, Fragment } from "react"; -// import { ChevronRight } from "react-feather"; import classNames from "@calcom/lib/classNames"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { SVGComponent } from "@calcom/types/SVGComponent"; import { Icon } from "@calcom/ui/Icon"; -export type VerticalTabItemProps = { +export type VerticalTabItemProps = { name: string; info?: string; icon?: SVGComponent; disabled?: boolean; - children?: VerticalTabItemProps[]; + children?: VerticalTabItemProps[]; textClassNames?: string; className?: string; isChild?: boolean; hidden?: boolean; disableChevron?: boolean; -} & ( - | { - /** If you want to change query param tabName as per current tab */ - href: string; - tabName?: never; - } - | ({ - href?: never; - } & Partial>) -); + href: string; + linkProps?: Omit, "href">; +}; -const VerticalTabItem = function ({ +const VerticalTabItem = function ({ name, href, - tabNameKey, info, isChild, disableChevron, + linkProps, ...props -}: VerticalTabItemProps & { - tabNameKey?: T; -}) { - const router = useRouter(); +}: VerticalTabItemProps) { const { t } = useLocale(); - let newHref = ""; - let isCurrent; - const tabName = props[tabNameKey as keyof typeof props] as string; - const _tabNameKey = tabNameKey || "tabName"; - if (href) { - newHref = href; - isCurrent = router.asPath.startsWith(href); - } else if (tabName) { - newHref = ""; - isCurrent = router.query[_tabNameKey] === tabName; - } - - const onClick: MouseEventHandler = tabName - ? (e) => { - e.preventDefault(); - router.push({ - query: { - ...router.query, - [_tabNameKey]: tabName, - }, - }); - } - : noop; + const { asPath } = useRouter(); + const isCurrent = asPath.startsWith(href); return ( {!props.hidden && ( <> - +
({ data-testid={`vertical-tab-${name}`} aria-current={isCurrent ? "page" : undefined}> {props.icon && ( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - //@ts-ignore )}
@@ -106,7 +70,7 @@ const VerticalTabItem = function ({ {props.children?.map((child) => ( - + ))} )} diff --git a/packages/ui/v2/core/navigation/tabs/VerticalTabs.tsx b/packages/ui/v2/core/navigation/tabs/VerticalTabs.tsx index 84791bcc17..81775c0515 100644 --- a/packages/ui/v2/core/navigation/tabs/VerticalTabs.tsx +++ b/packages/ui/v2/core/navigation/tabs/VerticalTabs.tsx @@ -4,23 +4,15 @@ import VerticalTabItem, { VerticalTabItemProps } from "./VerticalTabItem"; export { VerticalTabItem }; -export interface NavTabProps { - tabs: VerticalTabItemProps[]; +export interface NavTabProps { + tabs: VerticalTabItemProps[]; children?: React.ReactNode; className?: string; sticky?: boolean; - tabNameKey?: T; + linkProps?: VerticalTabItemProps["linkProps"]; } -const NavTabs = function ({ - tabs, - tabNameKey, - className = "", - sticky, - ...props -}: NavTabProps) { - const _tabNameKey = tabNameKey || "tabName"; - +const NavTabs = function ({ tabs, className = "", sticky, linkProps, ...props }: NavTabProps) { return ( );