import type { FC, HTMLAttributes } from "react"; import { useCallback, useEffect, useRef } from "react"; import type { Placement } from "@react-types/overlays"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faUser, faGear, faArrowRightFromBracket, faPhoneVolume, faSort } from "@fortawesome/pro-duotone-svg-icons"; const IconUser: FC<{ className?: string }> = ({ className }) => ; const IconSettings: FC<{ className?: string }> = ({ className }) => ; const IconLogout: FC<{ className?: string }> = ({ className }) => ; const IconForceReady: FC<{ className?: string }> = ({ className }) => ; import { useFocusManager } from "react-aria"; import type { DialogProps as AriaDialogProps } from "react-aria-components"; import { Button as AriaButton, Dialog as AriaDialog, DialogTrigger as AriaDialogTrigger, Popover as AriaPopover } from "react-aria-components"; import { AvatarLabelGroup } from "@/components/base/avatar/avatar-label-group"; import { useBreakpoint } from "@/hooks/use-breakpoint"; import { cx } from "@/utils/cx"; type NavAccountType = { /** Unique identifier for the nav item. */ id: string; /** Name of the account holder. */ name: string; /** Email address of the account holder. */ email: string; /** Avatar image URL. */ avatar: string; /** Online status of the account holder. This is used to display the online status indicator. */ status: "online" | "offline"; }; export const NavAccountMenu = ({ className, onSignOut, onForceReady, ...dialogProps }: AriaDialogProps & { className?: string; accounts?: NavAccountType[]; selectedAccountId?: string; onSignOut?: () => void; onForceReady?: () => void }) => { const focusManager = useFocusManager(); const dialogRef = useRef(null); const onKeyDown = useCallback( (e: KeyboardEvent) => { switch (e.key) { case "ArrowDown": focusManager?.focusNext({ tabbable: true, wrap: true }); break; case "ArrowUp": focusManager?.focusPrevious({ tabbable: true, wrap: true }); break; } }, [focusManager], ); useEffect(() => { const element = dialogRef.current; if (element) { element.addEventListener("keydown", onKeyDown); } return () => { if (element) { element.removeEventListener("keydown", onKeyDown); } }; }, [onKeyDown]); return ( {({ close }) => ( <>
{ close(); onForceReady?.(); }} />
{ close(); onSignOut?.(); }} />
)}
); }; const NavAccountCardMenuItem = ({ icon: Icon, label, shortcut, ...buttonProps }: { icon?: FC<{ className?: string }>; label: string; shortcut?: string; } & HTMLAttributes) => { return ( ); }; export const NavAccountCard = ({ popoverPlacement, selectedAccountId, items = [], onSignOut, onForceReady, }: { popoverPlacement?: Placement; selectedAccountId?: string; items?: NavAccountType[]; onSignOut?: () => void; onForceReady?: () => void; }) => { const triggerRef = useRef(null); const isDesktop = useBreakpoint("lg"); const selectedAccount = items.find((account) => account.id === selectedAccountId); if (!selectedAccount) { console.warn(`Account with ID ${selectedAccountId} not found in `); return null; } return (
cx( "origin-(--trigger-anchor-point) will-change-transform", isEntering && "duration-150 ease-out animate-in fade-in placement-right:slide-in-from-left-0.5 placement-top:slide-in-from-bottom-0.5 placement-bottom:slide-in-from-top-0.5", isExiting && "duration-100 ease-in animate-out fade-out placement-right:slide-out-to-left-0.5 placement-top:slide-out-to-bottom-0.5 placement-bottom:slide-out-to-top-0.5", ) } >
); };