From 7d39e3d0658206b34b3f1dc85a3457783c9f09ea Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Wed, 7 Feb 2024 21:32:44 +1100 Subject: [PATCH] feat: add team feature flag (#915) ## Description Add the ability to feature flag the teams feature via UI. Also added minor UI changes ## Checklist - [X] I have tested these changes locally and they work as expected. - [X] I have added/updated tests that prove the effectiveness of these changes. - [X] I have followed the project's coding style guidelines. --- .../components/(dashboard)/layout/header.tsx | 38 +++- .../(dashboard)/layout/mobile-navigation.tsx | 2 +- .../(dashboard)/layout/profile-dropdown.tsx | 169 ++++++++++++++++++ .../settings/layout/desktop-nav.tsx | 27 +-- .../settings/layout/mobile-nav.tsx | 27 +-- .../dialogs/create-team-checkout-dialog.tsx | 3 +- .../forms/2fa/authenticator-app.tsx | 2 - packages/lib/constants/feature-flags.ts | 1 + packages/ui/primitives/sheet.tsx | 9 +- 9 files changed, 244 insertions(+), 34 deletions(-) create mode 100644 apps/web/src/components/(dashboard)/layout/profile-dropdown.tsx diff --git a/apps/web/src/components/(dashboard)/layout/header.tsx b/apps/web/src/components/(dashboard)/layout/header.tsx index 753f5fb11..65bb63230 100644 --- a/apps/web/src/components/(dashboard)/layout/header.tsx +++ b/apps/web/src/components/(dashboard)/layout/header.tsx @@ -7,6 +7,7 @@ import { useParams } from 'next/navigation'; import { MenuIcon, SearchIcon } from 'lucide-react'; +import { useFeatureFlags } from '@documenso/lib/client-only/providers/feature-flag'; import type { GetTeamsResponse } from '@documenso/lib/server-only/team/get-teams'; import { getRootHref } from '@documenso/lib/utils/params'; import type { User } from '@documenso/prisma/client'; @@ -18,6 +19,7 @@ import { CommandMenu } from '../common/command-menu'; import { DesktopNav } from './desktop-nav'; import { MenuSwitcher } from './menu-switcher'; import { MobileNavigation } from './mobile-navigation'; +import { ProfileDropdown } from './profile-dropdown'; export type HeaderProps = HTMLAttributes & { user: User; @@ -27,6 +29,10 @@ export type HeaderProps = HTMLAttributes & { export const Header = ({ className, user, teams, ...props }: HeaderProps) => { const params = useParams(); + const { getFlag } = useFeatureFlags(); + + const isTeamsEnabled = getFlag('app_teams'); + const [isCommandMenuOpen, setIsCommandMenuOpen] = useState(false); const [isHamburgerMenuOpen, setIsHamburgerMenuOpen] = useState(false); const [scrollY, setScrollY] = useState(0); @@ -41,6 +47,34 @@ export const Header = ({ className, user, teams, ...props }: HeaderProps) => { return () => window.removeEventListener('scroll', onScroll); }, []); + if (!isTeamsEnabled) { + return ( +
5 && 'border-b-border', + className, + )} + {...props} + > +
+ + + + + + +
+ +
+
+
+ ); + } + return (
{
diff --git a/apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx b/apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx index 7142de5dc..a77300d9e 100644 --- a/apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx +++ b/apps/web/src/components/(dashboard)/layout/mobile-navigation.tsx @@ -47,7 +47,7 @@ export const MobileNavigation = ({ isMenuOpen, onMenuOpenChange }: MobileNavigat return ( - + Documenso Logo { + const { getFlag } = useFeatureFlags(); + const { theme, setTheme } = useTheme(); + const isUserAdmin = isAdmin(user); + + const isBillingEnabled = getFlag('app_billing'); + + const avatarFallback = user.name + ? extractInitials(user.name) + : user.email.slice(0, 1).toUpperCase(); + + return ( + + + + + + + Account + + {isUserAdmin && ( + <> + + + + Admin + + + + + + )} + + + + + Profile + + + + + + + Security + + + + {isBillingEnabled && ( + + + + Billing + + + )} + + + + + + Templates + + + + + + + + Themes + + + + + + Light + + + + Dark + + + + System + + + + + + + + + + Star on Github + + + + + + + void signOut({ + callbackUrl: '/', + }) + } + > + + Sign Out + + + + ); +}; diff --git a/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx b/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx index c7ab61d8a..572c91c76 100644 --- a/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx +++ b/apps/web/src/components/(dashboard)/settings/layout/desktop-nav.tsx @@ -19,6 +19,7 @@ export const DesktopNav = ({ className, ...props }: DesktopNavProps) => { const { getFlag } = useFeatureFlags(); const isBillingEnabled = getFlag('app_billing'); + const isTeamsEnabled = getFlag('app_teams'); return (
@@ -35,18 +36,20 @@ export const DesktopNav = ({ className, ...props }: DesktopNavProps) => { - - - + {isTeamsEnabled && ( + + + + )} - - - + {isTeamsEnabled && ( + + + + )}
diff --git a/apps/web/src/components/forms/2fa/authenticator-app.tsx b/apps/web/src/components/forms/2fa/authenticator-app.tsx index 316272e34..3aa0e123e 100644 --- a/apps/web/src/components/forms/2fa/authenticator-app.tsx +++ b/apps/web/src/components/forms/2fa/authenticator-app.tsx @@ -30,13 +30,11 @@ export const AuthenticatorApp = ({ isTwoFactorEnabled }: AuthenticatorAppProps)
!open && setModalState(null)} /> !open && setModalState(null)} /> diff --git a/packages/lib/constants/feature-flags.ts b/packages/lib/constants/feature-flags.ts index e972b47c2..947409be1 100644 --- a/packages/lib/constants/feature-flags.ts +++ b/packages/lib/constants/feature-flags.ts @@ -17,6 +17,7 @@ export const FEATURE_FLAG_POLL_INTERVAL = 30000; */ export const LOCAL_FEATURE_FLAGS: Record = { app_billing: process.env.NEXT_PUBLIC_FEATURE_BILLING_ENABLED === 'true', + app_teams: true, marketing_header_single_player_mode: false, } as const; diff --git a/packages/ui/primitives/sheet.tsx b/packages/ui/primitives/sheet.tsx index e9f1b4401..a6326de0f 100644 --- a/packages/ui/primitives/sheet.tsx +++ b/packages/ui/primitives/sheet.tsx @@ -3,7 +3,8 @@ import * as React from 'react'; import * as SheetPrimitive from '@radix-ui/react-dialog'; -import { VariantProps, cva } from 'class-variance-authority'; +import type { VariantProps } from 'class-variance-authority'; +import { cva } from 'class-variance-authority'; import { X } from 'lucide-react'; import { cn } from '../lib/utils'; @@ -12,7 +13,7 @@ const Sheet = SheetPrimitive.Root; const SheetTrigger = SheetPrimitive.Trigger; -const portalVariants = cva('fixed inset-0 z-50 flex', { +const portalVariants = cva('fixed inset-0 z-[61] flex', { variants: { position: { top: 'items-start', @@ -42,7 +43,7 @@ const SheetOverlay = React.forwardRef< >(({ className, children: _children, ...props }, ref) => (