'use client'; import React from 'react'; import Link from 'next/link'; import Image from 'next/image'; import { usePathname, useRouter } from 'next/navigation'; import { MessageSquare, Activity, Clock, Puzzle, Blocks, FolderOpen, Store, LogIn, UserPlus, Bot, ServerCog, Mail, LogOut, ChevronDown } from 'lucide-react'; import { logout } from '@/lib/api'; import { LanguageSwitcher } from '@/components/LanguageSwitcher'; import { Avatar, AvatarFallback } from '@/components/ui/avatar'; import { Button } from '@/components/ui/button'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { appConnectionStatusLabel } from '@/lib/i18n/common'; import { pickAppText } from '@/lib/i18n/core'; import { useAppI18n } from '@/lib/i18n/provider'; import { useChatStore } from '@/lib/store'; type NavItem = { key: | 'chat' | 'status' | 'office' | 'skills' | 'plugins' | 'agents' | 'mcp' | 'outlook' | 'marketplace' | 'files'; href: string; icon: React.ComponentType<{ className?: string }>; matchPrefixes?: string[]; }; const NAV_ITEMS: NavItem[] = [ { key: 'chat', href: '/', icon: MessageSquare }, { key: 'status', href: '/status', icon: Activity }, { key: 'office', href: '/office', icon: Clock, matchPrefixes: ['/office', '/cron'] }, { key: 'skills', href: '/skills', icon: Puzzle }, { key: 'plugins', href: '/plugins', icon: Blocks }, { key: 'agents', href: '/agents', icon: Bot }, { key: 'mcp', href: '/mcp', icon: ServerCog }, { key: 'outlook', href: '/outlook', icon: Mail }, { key: 'marketplace', href: '/marketplace', icon: Store }, { key: 'files', href: '/files', icon: FolderOpen }, ]; const AUTH_ITEMS = [ { key: 'login', href: '/login', icon: LogIn }, { key: 'register', href: '/register', icon: UserPlus }, ] as const; function ConnectionDot() { const { locale } = useAppI18n(); const wsStatus = useChatStore((s) => s.wsStatus); const nanobotReady = useChatStore((s) => s.nanobotReady); const isOnline = wsStatus === 'connected' && nanobotReady === true; const isChecking = wsStatus === 'connected' && nanobotReady === null; const isConnecting = wsStatus === 'connecting' || isChecking; const isOffline = wsStatus === 'disconnected' || (wsStatus === 'connected' && nanobotReady === false); const color = isOnline ? 'bg-green-500' : isConnecting ? 'bg-yellow-500' : 'bg-red-500'; const label = appConnectionStatusLabel(wsStatus, nanobotReady, locale); return (
{label}
); } const Header = () => { const { locale } = useAppI18n(); const pathname = usePathname(); const router = useRouter(); const user = useChatStore((s) => s.user); const isAuthLoading = useChatStore((s) => s.isAuthLoading); const setUser = useChatStore((s) => s.setUser); const navLabel = React.useCallback((key: NavItem['key']) => { if (key === 'chat') return pickAppText(locale, '对话', 'Chat'); if (key === 'status') return pickAppText(locale, '状态', 'Status'); if (key === 'office') return pickAppText(locale, '任务管理', 'Tasks'); if (key === 'skills') return pickAppText(locale, '技能', 'Skills'); if (key === 'plugins') return pickAppText(locale, '插件', 'Plugins'); if (key === 'agents') return pickAppText(locale, '智能体', 'Agents'); if (key === 'mcp') return 'MCP'; if (key === 'outlook') return 'Outlook'; if (key === 'marketplace') return pickAppText(locale, '市场', 'Marketplace'); return pickAppText(locale, '文件', 'Files'); }, [locale]); const authLabel = React.useCallback((key: 'login' | 'register') => ( key === 'login' ? pickAppText(locale, '登录', 'Sign In') : pickAppText(locale, '注册', 'Sign Up') ), [locale]); const handleLogout = async () => { await logout(); setUser(null); router.replace('/login'); router.refresh(); }; const userInitial = (user?.username || user?.email || '?').trim().charAt(0).toUpperCase(); return (
Boardware logo Boardware Agent Sandbox
{user ? (

{user.email}

{userInitial}

{pickAppText(locale, `${user.username},你好!`, `Hi, ${user.username}`)}

{pickAppText(locale, '当前已登录到你的工作区实例。', 'You are currently signed in to your workspace instance.')}

) : !isAuthLoading ? ( AUTH_ITEMS.map((item) => { const isActive = pathname.startsWith(item.href); const Icon = item.icon; return ( {authLabel(item.key)} ); }) ) : null}
); }; export default Header;