From 8d7c41bac45c8323e85d9c31925bebea2739618c Mon Sep 17 00:00:00 2001 From: Rainnny7 Date: Thu, 19 Sep 2024 02:06:19 -0400 Subject: [PATCH] user menu on the sidebar --- bun.lockb | Bin 197482 -> 201016 bytes package.json | 1 + src/app/types/user/user.ts | 5 + src/components/branding.tsx | 5 +- src/components/dashboard/sidebar/links.tsx | 9 +- .../sidebar/organization-selector.tsx | 27 +-- src/components/dashboard/sidebar/sidebar.tsx | 15 +- .../dashboard/sidebar/user-menu.tsx | 84 +++++++ src/components/org/organization-logo.tsx | 70 ++++++ src/components/ui/dropdown-menu.tsx | 208 ++++++++++++++++++ src/components/user/user-avatar.tsx | 70 ++++++ 11 files changed, 472 insertions(+), 22 deletions(-) create mode 100644 src/components/dashboard/sidebar/user-menu.tsx create mode 100644 src/components/org/organization-logo.tsx create mode 100644 src/components/ui/dropdown-menu.tsx create mode 100644 src/components/user/user-avatar.tsx diff --git a/bun.lockb b/bun.lockb index d6784b2fe7b8ed5212d3a4bd77a2954bfa2ce271..dfdd62b386936fcf3994425dd7464114d6e62f6b 100644 GIT binary patch delta 36341 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 P)KYuwta?~$-TnUn7|EqB diff --git a/package.json b/package.json index 86ee8d7..c3618b6 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@heroicons/react": "^2.1.5", "@hookform/resolvers": "^3.9.0", "@radix-ui/react-dialog": "^1.1.1", + "@radix-ui/react-dropdown-menu": "^2.1.1", "@radix-ui/react-icons": "^1.3.0", "@radix-ui/react-popover": "^1.1.1", "@radix-ui/react-separator": "^1.1.0", diff --git a/src/app/types/user/user.ts b/src/app/types/user/user.ts index 4e14f7e..ce5cb85 100644 --- a/src/app/types/user/user.ts +++ b/src/app/types/user/user.ts @@ -14,6 +14,11 @@ export type User = { */ username: string; + /** + * The hash to the avatar of this user, if any. + */ + avatar: string | undefined; + /** * The tier of this user. */ diff --git a/src/components/branding.tsx b/src/components/branding.tsx index 8681e49..af11234 100644 --- a/src/components/branding.tsx +++ b/src/components/branding.tsx @@ -3,6 +3,9 @@ import Image from "next/image"; import { cva } from "class-variance-authority"; import { cn } from "@/lib/utils"; +/** + * The variants of the branding. + */ const brandingVariants = cva( "relative group-hover:opacity-75 hover:opacity-75 select-none transition-all transform-gpu", { @@ -45,7 +48,7 @@ const Branding = ({ href, size, className }: BrandingProps) => ( className={cn(brandingVariants({ size, className }))} href={href ?? "/"} > - PulseApp Logo + Pulse App Logo ); export default Branding; diff --git a/src/components/dashboard/sidebar/links.tsx b/src/components/dashboard/sidebar/links.tsx index e1c62f3..97a213f 100644 --- a/src/components/dashboard/sidebar/links.tsx +++ b/src/components/dashboard/sidebar/links.tsx @@ -14,6 +14,7 @@ import { } from "@heroicons/react/24/outline"; import { useOrganizationContext } from "@/app/provider/organization-provider"; import { OrganizationState } from "@/app/store/organization-store"; +import { usePathname } from "next/navigation"; const links: SidebarLink[] = [ { @@ -53,10 +54,12 @@ const Links = (): ReactElement => { const selectedOrganization: string | undefined = useOrganizationContext( (state: OrganizationState) => state.selected ); + const path: string = usePathname(); return ( -
+
{links.map((link: SidebarLink, index: number) => { - const active: boolean = index === 0; + const href: string = `/dashboard/org/${selectedOrganization}${link.href}`; + const active: boolean = path.startsWith(href); return ( { "px-3 py-2 flex gap-2 items-center text-sm rounded-lg hover:bg-zinc-800 transition-all transform-gpu", active && "font-medium bg-zinc-800" )} - href={`/dashboard/org/${selectedOrganization}${link.href}`} + href={href} >
{link.icon}
{link.name} diff --git a/src/components/dashboard/sidebar/organization-selector.tsx b/src/components/dashboard/sidebar/organization-selector.tsx index 5b2b641..adb9c86 100644 --- a/src/components/dashboard/sidebar/organization-selector.tsx +++ b/src/components/dashboard/sidebar/organization-selector.tsx @@ -4,7 +4,6 @@ import * as React from "react"; import { ReactElement, useEffect, useState } from "react"; import { ChevronsUpDownIcon } from "lucide-react"; import { Button } from "@/components/ui/button"; -import InitialsAvatar from "react-initials-avatar"; import { Command, CommandEmpty, @@ -22,7 +21,7 @@ import { useOrganizationContext } from "@/app/provider/organization-provider"; import { OrganizationState } from "@/app/store/organization-store"; import { Organization } from "@/app/types/org/organization"; import { CheckIcon } from "@heroicons/react/24/outline"; -import Image from "next/image"; +import OrganizationLogo from "@/components/org/organization-logo"; /** * The organization selector. @@ -84,18 +83,10 @@ const OrganizationSelector = (): ReactElement => { > {selected ? (
-
- {selected.logo ? ( - {`${selected.name}'s - ) : ( - - )} -
+ {selected.name}
) : ( @@ -114,7 +105,7 @@ const OrganizationSelector = (): ReactElement => { (organization: Organization, index: number) => ( selectOrganization( @@ -126,10 +117,14 @@ const OrganizationSelector = (): ReactElement => { ) } > + {organization.name} {organization.snowflake === selectedOrganization && ( - + )} ) diff --git a/src/components/dashboard/sidebar/sidebar.tsx b/src/components/dashboard/sidebar/sidebar.tsx index d8326b7..1e32e90 100644 --- a/src/components/dashboard/sidebar/sidebar.tsx +++ b/src/components/dashboard/sidebar/sidebar.tsx @@ -11,7 +11,13 @@ import { useUserContext } from "@/app/provider/user-provider"; import { UserState } from "@/app/store/user-store"; import { hasFlag } from "@/lib/user"; import { UserFlag } from "@/app/types/user/user-flag"; +import UserMenu from "@/components/dashboard/sidebar/user-menu"; +/** + * The sidebar to display on the dashboard. + * + * @return the sidebar jsx + */ const Sidebar = (): ReactElement => { const user: User | undefined = useUserContext( (state: UserState) => state.user @@ -19,7 +25,10 @@ const Sidebar = (): ReactElement => { return hasFlag(user as User, UserFlag.COMPLETED_ONBOARDING) ? ( ) : (
diff --git a/src/components/dashboard/sidebar/user-menu.tsx b/src/components/dashboard/sidebar/user-menu.tsx new file mode 100644 index 0000000..a1d5f05 --- /dev/null +++ b/src/components/dashboard/sidebar/user-menu.tsx @@ -0,0 +1,84 @@ +"use client"; + +import { ReactElement } from "react"; +import { useUserContext } from "@/app/provider/user-provider"; +import { UserState } from "@/app/store/user-store"; +import { User } from "@/app/types/user/user"; +import UserAvatar from "@/components/user/user-avatar"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { + ArrowLeftEndOnRectangleIcon, + Cog6ToothIcon, + CreditCardIcon, + UserIcon, +} from "@heroicons/react/24/outline"; +import Link from "next/link"; + +const UserMenu = (): ReactElement => { + const user: User | undefined = useUserContext( + (state: UserState) => state.user + ); + return ( + + +
+ @ + {user?.username} +
+
+ + {/* Content */} + + + {/* Logout */} + + + + Logout + + +
+ ); +}; + +/** + * The my account section. + * + * @return the section jsx + */ +const MyAccount = (): ReactElement => ( + + + My Account + + + + + + Profile + + + + + + Billing + + + + + + Settings + + + +); + +export default UserMenu; diff --git a/src/components/org/organization-logo.tsx b/src/components/org/organization-logo.tsx new file mode 100644 index 0000000..4f62896 --- /dev/null +++ b/src/components/org/organization-logo.tsx @@ -0,0 +1,70 @@ +import * as React from "react"; +import { ReactElement } from "react"; +import { cva } from "class-variance-authority"; +import Image from "next/image"; +import InitialsAvatar from "react-initials-avatar"; +import { cn } from "@/lib/utils"; +import { Organization } from "@/app/types/org/organization"; + +/** + * The variants of the logo. + */ +const logoVariants = cva("relative rounded-full", { + variants: { + size: { + sm: "w-5 h-5", + default: "w-10 h-10", + }, + }, + defaultVariants: { + size: "default", + }, +}); + +/** + * The props for this component. + */ +type OrganizationLogoProps = { + /** + * The organization to show the logo for. + */ + organization: Organization; + + /** + * The size of the logo. + */ + size?: "sm" | "default"; + + /** + * The optional class name to apply to the logo. + */ + className?: string; +}; + +/** + * A logo for an organization. + * + * @param organization the organization + * @param size the size + * @param className additional class names + * @return the organization jsx + */ +const OrganizationLogo = ({ + organization, + size, + className, +}: OrganizationLogoProps): ReactElement => ( +
+ {organization.logo ? ( + {`${organization.name}'s + ) : ( + + )} +
+); +export default OrganizationLogo; diff --git a/src/components/ui/dropdown-menu.tsx b/src/components/ui/dropdown-menu.tsx new file mode 100644 index 0000000..a838229 --- /dev/null +++ b/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,208 @@ +"use client"; + +import * as React from "react"; +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { + CheckIcon, + ChevronRightIcon, + DotFilledIcon, +} from "@radix-ui/react-icons"; + +import { cn } from "@/lib/utils"; + +const DropdownMenu = DropdownMenuPrimitive.Root; + +const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger; + +const DropdownMenuGroup = DropdownMenuPrimitive.Group; + +const DropdownMenuPortal = DropdownMenuPrimitive.Portal; + +const DropdownMenuSub = DropdownMenuPrimitive.Sub; + +const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup; + +const DropdownMenuSubTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, children, ...props }, ref) => ( + + {children} + + +)); +DropdownMenuSubTrigger.displayName = + DropdownMenuPrimitive.SubTrigger.displayName; + +const DropdownMenuSubContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSubContent.displayName = + DropdownMenuPrimitive.SubContent.displayName; + +const DropdownMenuContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, sideOffset = 4, ...props }, ref) => ( + + + +)); +DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName; + +const DropdownMenuItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName; + +const DropdownMenuCheckboxItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, checked, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuCheckboxItem.displayName = + DropdownMenuPrimitive.CheckboxItem.displayName; + +const DropdownMenuRadioItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + + + + {children} + +)); +DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName; + +const DropdownMenuLabel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef & { + inset?: boolean; + } +>(({ className, inset, ...props }, ref) => ( + +)); +DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName; + +const DropdownMenuSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName; + +const DropdownMenuShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +DropdownMenuShortcut.displayName = "DropdownMenuShortcut"; + +export { + DropdownMenu, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuGroup, + DropdownMenuPortal, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, + DropdownMenuRadioGroup, +}; diff --git a/src/components/user/user-avatar.tsx b/src/components/user/user-avatar.tsx new file mode 100644 index 0000000..08baa9e --- /dev/null +++ b/src/components/user/user-avatar.tsx @@ -0,0 +1,70 @@ +import * as React from "react"; +import { ReactElement } from "react"; +import { cva } from "class-variance-authority"; +import Image from "next/image"; +import InitialsAvatar from "react-initials-avatar"; +import { cn } from "@/lib/utils"; +import { User } from "@/app/types/user/user"; + +/** + * The variants of the avatar. + */ +const avatarVariants = cva("relative rounded-full", { + variants: { + size: { + sm: "w-6 h-6", + default: "w-10 h-10", + }, + }, + defaultVariants: { + size: "default", + }, +}); + +/** + * The props for this component. + */ +type UserAvatarProps = { + /** + * The user to show the avatar for. + */ + user: User; + + /** + * The size of the avatar. + */ + size?: "sm" | "default"; + + /** + * The optional class name to apply to the logo. + */ + className?: string; +}; + +/** + * An avatar for a user. + * + * @param user the user + * @param size the size + * @param className additional class names + * @return the avatar jsx + */ +const UserAvatar = ({ + user, + size, + className, +}: UserAvatarProps): ReactElement => ( +
+ {user.avatar ? ( + {`${user.username}'s + ) : ( + + )} +
+); +export default UserAvatar;