diff --git a/apps/web/components/ui/AdminRequired.tsx b/apps/web/components/ui/AdminRequired.tsx index 18e52752d0..97b33f4e40 100644 --- a/apps/web/components/ui/AdminRequired.tsx +++ b/apps/web/components/ui/AdminRequired.tsx @@ -6,6 +6,7 @@ type AdminRequiredProps = { children?: React.ReactNode; }; +/** @deprecated use PermssionContainer instead. Will delete once V2 goes live */ export const AdminRequired: FC = ({ children, as, ...rest }) => { const session = useSession(); diff --git a/apps/web/pages/v2/settings/admin/impersonation.tsx b/apps/web/pages/v2/settings/admin/impersonation.tsx index 2ea50f175b..e9263ffc8d 100644 --- a/apps/web/pages/v2/settings/admin/impersonation.tsx +++ b/apps/web/pages/v2/settings/admin/impersonation.tsx @@ -2,8 +2,7 @@ import { signIn } from "next-auth/react"; import { useRef } from "react"; import { useLocale } from "@calcom/lib/hooks/useLocale"; -import Button from "@calcom/ui/Button"; -import { TextField } from "@calcom/ui/form/fields"; +import { TextField, Button } from "@calcom/ui/v2"; import Meta from "@calcom/ui/v2/core/Meta"; import { getLayout } from "@calcom/ui/v2/core/layouts/AdminLayout"; @@ -13,7 +12,7 @@ function AdminView() { return ( <> - +
{ @@ -23,20 +22,15 @@ function AdminView() { console.log(res); }); }}> - - {process.env.NEXT_PUBLIC_WEBSITE_URL}/ - - } - ref={usernameRef} - defaultValue={undefined} - /> -

- {t("impersonate_user_tip")} -

-
+
+ {process.env.NEXT_PUBLIC_WEBSITE_URL}/} + ref={usernameRef} + hint={t("impersonate_user_tip")} + defaultValue={undefined} + />
diff --git a/packages/features/auth/PermissionContainer.tsx b/packages/features/auth/PermissionContainer.tsx new file mode 100644 index 0000000000..e5865aec43 --- /dev/null +++ b/packages/features/auth/PermissionContainer.tsx @@ -0,0 +1,25 @@ +import { useSession } from "next-auth/react"; +import { FC, Fragment } from "react"; + +import { UserPermissionRole } from ".prisma/client"; + +type AdminRequiredProps = { + as?: keyof JSX.IntrinsicElements; + children?: React.ReactNode; + /**Not needed right now but will be useful if we ever expand our permission roles */ + roleRequired?: UserPermissionRole; +}; + +export const PermissionContainer: FC = ({ + children, + as, + roleRequired = "ADMIN", + ...rest +}) => { + const session = useSession(); + + // Admin can do everything + if (session.data?.user.role !== roleRequired || !UserPermissionRole.ADMIN) return null; + const Component = as ?? Fragment; + return {children}; +}; diff --git a/packages/ui/v2/core/layouts/AdminLayout.tsx b/packages/ui/v2/core/layouts/AdminLayout.tsx index 48b233546e..8c408c61fc 100644 --- a/packages/ui/v2/core/layouts/AdminLayout.tsx +++ b/packages/ui/v2/core/layouts/AdminLayout.tsx @@ -1,12 +1,25 @@ -import React, { ComponentProps } from "react"; +import { useSession } from "next-auth/react"; +import { useRouter } from "next/router"; +import React, { ComponentProps, useEffect } from "react"; import Shell from "../Shell"; import SettingsLayout from "./SettingsLayout"; +import { UserPermissionRole } from ".prisma/client"; export default function AdminLayout({ children, ...rest }: { children: React.ReactNode } & ComponentProps) { + const session = useSession(); + const router = useRouter(); + + // Force redirect on component level + useEffect(() => { + if (session.data?.user.role !== UserPermissionRole.ADMIN) { + router.replace("/settings"); + } + }, [session, router]); + return (
diff --git a/packages/ui/v2/core/layouts/SettingsLayout.tsx b/packages/ui/v2/core/layouts/SettingsLayout.tsx index 917b94e620..13e8c23232 100644 --- a/packages/ui/v2/core/layouts/SettingsLayout.tsx +++ b/packages/ui/v2/core/layouts/SettingsLayout.tsx @@ -1,3 +1,4 @@ +import { useSession } from "next-auth/react"; import React, { ComponentProps, useState } from "react"; import { classNames } from "@calcom/lib"; @@ -7,9 +8,10 @@ import Button from "@calcom/ui/v2/core/Button"; import { Icon } from "../../../Icon"; import { useMeta } from "../Meta"; import Shell from "../Shell"; +import { VerticalTabItemProps } from "../navigation/tabs/VerticalTabItem"; import VerticalTabs, { VerticalTabItem } from "../navigation/tabs/VerticalTabs"; -const tabs = [ +const tabs: VerticalTabItemProps[] = [ { name: "my_account", href: "/settings/my-account", @@ -64,7 +66,6 @@ const tabs = [ name: "admin", href: "/settings/admin", icon: Icon.FiLock, - adminRequired: true, children: [ // { name: "impersonation", href: "/settings/admin/impersonation" }, @@ -74,9 +75,23 @@ const tabs = [ }, ]; +// The following keys are assigned to admin only +const adminRequiredKeys = ["admin"]; + +const useTabs = () => { + const session = useSession(); + const isAdmin = session.data?.user.role === "ADMIN"; + // check if name is in adminRequiredKeys + return tabs.filter((tab) => { + if (isAdmin) return true; + return !adminRequiredKeys.includes(tab.name); + }); +}; + const SettingsSidebarContainer = ({ className = "" }) => { + const tabsWithPermissions = useTabs(); return ( - +