"use client"; import { Check, ChevronUp, Download, ExternalLink, Info, Languages, LogOut, Megaphone, Monitor, Moon, Sun, UserCog, } from "lucide-react"; import Image from "next/image"; import { useTranslations } from "next-intl"; import { useState } from "react"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuSeparator, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "@/components/ui/dropdown-menu"; import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/spinner"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; import { useLocaleContext } from "@/contexts/LocaleContext"; import { useMediaQuery } from "@/hooks/use-media-query"; import { usePlatform } from "@/hooks/use-platform"; import { GITHUB_RELEASES_URL, usePrimaryDownload } from "@/lib/desktop-download-utils"; import { APP_VERSION } from "@/lib/env-config"; import { trackDesktopDownloadClicked } from "@/lib/posthog/events"; import { cn } from "@/lib/utils"; import type { User } from "../../types/layout.types"; // Supported languages configuration const LANGUAGES = [ { code: "en" as const, name: "English", flag: "🇺🇸" }, { code: "es" as const, name: "Español", flag: "🇪🇸" }, { code: "pt" as const, name: "Português", flag: "🇧🇷" }, { code: "hi" as const, name: "हिन्दी", flag: "🇮🇳" }, { code: "zh" as const, name: "简体中文", flag: "🇨🇳" }, ]; // Supported themes configuration const THEMES = [ { value: "light" as const, name: "Light", icon: Sun }, { value: "dark" as const, name: "Dark", icon: Moon }, { value: "system" as const, name: "System", icon: Monitor }, ]; const LEARN_MORE_LINKS = [ { key: "documentation" as const, href: "https://surfsense.com/docs" }, { key: "github" as const, href: "https://github.com/MODSetter/SurfSense" }, ]; interface SidebarUserProfileProps { user: User; onUserSettings?: () => void; onAnnouncements?: () => void; announcementUnreadCount?: number; onLogout?: () => void; isCollapsed?: boolean; theme?: string; setTheme?: (theme: "light" | "dark" | "system") => void; } function formatAnnouncementCount(count: number): string { if (count <= 999) { return count.toString(); } const thousands = Math.floor(count / 1000); return `${thousands}k+`; } /** * Generates a consistent color based on email */ function stringToColor(str: string): string { let hash = 0; for (let i = 0; i < str.length; i++) { hash = str.charCodeAt(i) + ((hash << 5) - hash); } const colors = [ "#6366f1", "#8b5cf6", "#a855f7", "#d946ef", "#ec4899", "#f43f5e", "#ef4444", "#f97316", "#eab308", "#84cc16", "#22c55e", "#14b8a6", "#06b6d4", "#0ea5e9", "#3b82f6", ]; return colors[Math.abs(hash) % colors.length]; } /** * Gets initials from email */ function getInitials(email: string): string { const name = email.split("@")[0]; const parts = name.split(/[._-]/); if (parts.length >= 2) { return (parts[0][0] + parts[1][0]).toUpperCase(); } return name.slice(0, 2).toUpperCase(); } /** * User avatar component - shows image if available, otherwise falls back to initials */ function UserAvatar({ avatarUrl, initials, bgColor, size = "sm", }: { avatarUrl?: string; initials: string; bgColor: string; size?: "sm" | "md"; }) { const sizeClass = size === "md" ? "h-10 w-10" : "h-8 w-8"; if (avatarUrl) { return ( User avatar ); } return (
{initials}
); } export function SidebarUserProfile({ user, onUserSettings, onAnnouncements, announcementUnreadCount = 0, onLogout, isCollapsed = false, theme, setTheme, }: SidebarUserProfileProps) { const t = useTranslations("sidebar"); const { locale, setLocale } = useLocaleContext(); const { isDesktop } = usePlatform(); const isDesktopViewport = useMediaQuery("(min-width: 768px)"); const { os, primary } = usePrimaryDownload(); const [isLoggingOut, setIsLoggingOut] = useState(false); const bgColor = stringToColor(user.email); const initials = getInitials(user.email); const displayName = user.name || user.email.split("@")[0]; const downloadUrl = primary?.url ?? GITHUB_RELEASES_URL; const downloadLabel = t("download_for_os", { os }); const showDownloadCta = !isDesktop && isDesktopViewport; const handleLanguageChange = (newLocale: "en" | "es" | "pt" | "hi" | "zh") => { setLocale(newLocale); }; const handleThemeChange = (newTheme: "light" | "dark" | "system") => { setTheme?.(newTheme); }; const handleLogout = async () => { if (isLoggingOut || !onLogout) return; setIsLoggingOut(true); try { await onLogout(); } finally { setIsLoggingOut(false); } }; // Collapsed view - just show avatar with dropdown if (isCollapsed) { return (
{showDownloadCta && ( {downloadLabel} )}

{displayName}

{user.email}

{t("user_settings")} {onAnnouncements && ( What's New {announcementUnreadCount > 0 && ( {formatAnnouncementCount(announcementUnreadCount)} )} )} {setTheme && ( {t("theme")} {THEMES.map((themeOption) => { const Icon = themeOption.icon; const isSelected = theme === themeOption.value; return ( handleThemeChange(themeOption.value)} className={cn( "mb-1 last:mb-0 transition-all", "hover:bg-accent hover:text-accent-foreground", isSelected && "text-primary" )} > {t(themeOption.value)} {isSelected && } ); })} )} {t("language")} {LANGUAGES.map((language) => { const isSelected = locale === language.code; return ( handleLanguageChange(language.code)} className={cn( "mb-1 last:mb-0 transition-all", "hover:bg-accent hover:text-accent-foreground", isSelected && "text-primary" )} > {language.flag} {language.name} {isSelected && } ); })} {t("learn_more")} {LEARN_MORE_LINKS.map((link) => ( {t(link.key)} ))}

v{APP_VERSION}

{!isDesktop && ( {downloadLabel} )} {isLoggingOut ? ( ) : ( )} {isLoggingOut ? t("loggingOut") : t("logout")}
); } // Expanded view return (
{showDownloadCta && ( )}

{displayName}

{user.email}

{t("user_settings")} {onAnnouncements && ( What's New {announcementUnreadCount > 0 && ( {formatAnnouncementCount(announcementUnreadCount)} )} )} {setTheme && ( {t("theme")} {THEMES.map((themeOption) => { const Icon = themeOption.icon; const isSelected = theme === themeOption.value; return ( handleThemeChange(themeOption.value)} className={cn( "mb-1 last:mb-0 transition-all", "hover:bg-accent hover:text-accent-foreground", isSelected && "text-primary" )} > {t(themeOption.value)} {isSelected && } ); })} )} {t("language")} {LANGUAGES.map((language) => { const isSelected = locale === language.code; return ( handleLanguageChange(language.code)} className={cn( "mb-1 last:mb-0 transition-all", "hover:bg-accent hover:text-accent-foreground", isSelected && "text-primary" )} > {language.flag} {language.name} {isSelected && } ); })} {t("learn_more")} {LEARN_MORE_LINKS.map((link) => ( {t(link.key)} ))}

v{APP_VERSION}

{!isDesktop && ( {downloadLabel} )} {isLoggingOut ? : } {isLoggingOut ? t("loggingOut") : t("logout")}
); }