import { ROADMAP } from "@calcom/lib/constants"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { useUserAgentData } from "@calcom/lib/hooks/useUserAgentData"; import useMeQuery from "@calcom/trpc/react/hooks/useMeQuery"; import classNames from "@calcom/ui/classNames"; import { Avatar } from "@calcom/ui/components/avatar"; import { BlocksIcon, ChevronDownIcon, ChevronUpIcon, CircleHelpIcon, DownloadIcon, LogOutIcon, MapIcon, MoonIcon, SettingsIcon, UserIcon, } from "@coss/ui/icons"; import { useGetUserAttributes } from "@calcom/web/components/settings/platform/hooks/useGetUserAttributes"; import FreshChatProvider from "@calcom/web/modules/ee/support/lib/freshchat/FreshChatProvider"; import { Menu, MenuItem, MenuPopup, MenuSeparator, MenuSub, MenuSubPopup, MenuSubTrigger, MenuTrigger, } from "@coss/ui/components/menu"; import Link from "next/link"; import { usePathname } from "next/navigation"; import { signOut } from "next-auth/react"; import type { MouseEvent } from "react"; import { useEffect, useState } from "react"; import { AppleIcon, ChromeIcon, EdgeIcon, FirefoxIcon, LinuxIcon, PlayStoreIcon, SafariIcon, WindowsIcon, } from "./DownloadIcons"; declare global { interface Window { Support?: { open: () => void; shouldShowTriggerButton: (showTrigger: boolean) => void; }; Beacon?: BeaconFunction; } } type BeaconFunction = { (command: "session-data", data: Record): void; // Catch-all for other methods - add explicit types above if using new commands (...args: unknown[]): void; }; interface UserDropdownProps { small?: boolean; } const DOWNLOAD_LINKS = { ios: "https://go.cal.com/iOS", android: "https://go.cal.com/android", chrome: "https://go.cal.com/chrome", safari: "https://go.cal.com/safari", firefox: "https://go.cal.com/firefox", edge: "https://go.cal.com/edge", macos: "https://cal.com/download", windows: "https://cal.com/download", linux: "https://cal.com/download", } as const; export function UserDropdown({ small }: UserDropdownProps) { const { isPlatformUser } = useGetUserAttributes(); const { t } = useLocale(); const { data: user, isPending } = useMeQuery(); const pathname = usePathname(); const isPlatformPages = pathname?.startsWith("/settings/platform"); const { os, browser, isMobile } = useUserAgentData(); useEffect(() => { if (typeof window === "undefined") return; const sendSessionData = () => { const Beacon = window.Beacon; if (Beacon) { Beacon("session-data", { username: user?.username || "Unknown", screenResolution: `${screen.width}x${screen.height}`, }); return true; } return false; }; // Try immediately, then poll if Beacon isn't loaded yet if (!sendSessionData()) { const intervalId = setInterval(() => { if (sendSessionData()) { clearInterval(intervalId); } }, 1000); return () => clearInterval(intervalId); } }, [user?.username]); const [menuOpen, setMenuOpen] = useState(false); const [openSupportAfterClose, setOpenSupportAfterClose] = useState(false); const handleHelpClick = (e?: MouseEvent) => { e?.preventDefault(); e?.stopPropagation(); setOpenSupportAfterClose(true); setMenuOpen(false); }; useEffect(() => { if (typeof window === "undefined") return; if (!menuOpen && openSupportAfterClose) { setTimeout(() => { window.Support?.open(); }, 0); setOpenSupportAfterClose(false); } }, [menuOpen, openSupportAfterClose]); // Prevent rendering dropdown if user isn't available. // We don't want to show nameless user. if (!user && !isPending) { return null; } return ( }> {!small && ( {isPending ? "Loading..." : (user?.name ?? "Nameless User")} {menuOpen ? ( )} {!isPlatformPages && ( <> }> {t("my_profile")} }> {t("my_settings")} }> {t("out_of_office")} )} }> {t("visit_roadmap")} {t("help")} {!isPlatformPages && isMobile && os === "ios" && ( }> {t("download_app")} )} {!isPlatformPages && isMobile && os === "android" && ( }> {t("download_app")} )} {!isPlatformPages && !isMobile && ( {t("download_app")} {os === "macos" && ( }> {t("download_for_macos")} )} {os === "windows" && ( }> {t("download_for_windows")} )} {os === "linux" && ( }> {t("download_for_linux")} )} {browser === "chrome" && ( }> {t("download_chrome_extension")} )} {browser === "safari" && ( }> {t("download_safari_extension")} )} {browser === "firefox" && ( }> {t("download_firefox_extension")} )} {browser === "edge" && ( }> {t("download_edge_extension")} )} }> {t("download_for_ios")} }> {t("download_for_android")} )} {!isPlatformPages && isPlatformUser && ( } className="todesktop:hidden hidden lg:flex"> {t("platform")} )} { signOut({ callbackUrl: "/auth/logout" }); }}> {t("sign_out")} ); }