'use client'; import { useMutation, useQuery } from '@tanstack/react-query'; import { useEffect, useRef, useState } from 'react'; import { useRouter } from 'next/navigation'; import { useAuth } from '@/components/providers/auth-provider'; import { ThemeToggle } from '@/components/ui/theme-toggle'; import { getPublicStatus } from '@/features/auth/api/public'; import { getLatestRelease, upgradeServer } from '@/features/update/api/update'; import { VersionUpgradeModal } from '@/features/update/components/version-upgrade-modal'; import { publicEnv } from '@/lib/env/public-env'; import { useAppShellStore } from '@/store/app-shell'; export function DashboardTopbar() { const router = useRouter(); const { logout, user } = useAuth(); const toggleSidebar = useAppShellStore((state) => state.toggleSidebar); const isMobileSidebarOpen = useAppShellStore( (state) => state.isMobileSidebarOpen, ); const setMobileSidebarOpen = useAppShellStore( (state) => state.setMobileSidebarOpen, ); const [isLoggingOut, setIsLoggingOut] = useState(false); const [isUserMenuOpen, setIsUserMenuOpen] = useState(false); const [isVersionModalOpen, setIsVersionModalOpen] = useState(false); const [versionFeedback, setVersionFeedback] = useState(null); const menuRef = useRef(null); const isRoot = (user?.role ?? 0) >= 100; const publicStatusQuery = useQuery({ queryKey: ['public-status'], queryFn: getPublicStatus, }); const latestReleaseQuery = useQuery({ queryKey: ['update', 'latest-release'], queryFn: getLatestRelease, enabled: isRoot, refetchInterval: 60 * 60 * 1000, }); const upgradeMutation = useMutation({ mutationFn: upgradeServer, onSuccess: (release) => { setVersionFeedback( `服务升级任务已启动,目标版本 ${release.tag_name}。页面可能短暂不可用。`, ); void latestReleaseQuery.refetch(); }, onError: (error) => { setVersionFeedback( error instanceof Error ? error.message : '升级失败,请稍后重试。', ); }, }); useEffect(() => { if (!isUserMenuOpen) { return; } const handlePointerDown = (event: MouseEvent) => { if (!menuRef.current?.contains(event.target as Node)) { setIsUserMenuOpen(false); } }; const handleEscape = (event: KeyboardEvent) => { if (event.key === 'Escape') { setIsUserMenuOpen(false); } }; window.addEventListener('mousedown', handlePointerDown); window.addEventListener('keydown', handleEscape); return () => { window.removeEventListener('mousedown', handlePointerDown); window.removeEventListener('keydown', handleEscape); }; }, [isUserMenuOpen]); const handleLogout = async () => { setIsLoggingOut(true); setIsUserMenuOpen(false); await logout(); router.replace('/login'); }; const handleSidebarToggle = () => { if (window.innerWidth < 1000) { setMobileSidebarOpen(!isMobileSidebarOpen); return; } toggleSidebar(); }; const handleOpenVersionModal = () => { setVersionFeedback(null); setIsVersionModalOpen(true); if (isRoot) { void latestReleaseQuery.refetch(); } }; const handleUpgrade = () => { setVersionFeedback(null); upgradeMutation.mutate(); }; const release = latestReleaseQuery.data; const hasUpdate = Boolean(isRoot && release?.has_update); const currentVersion = publicStatusQuery.data?.version || 'unknown'; const versionLabel = hasUpdate ? `版本 ${publicEnv.appVersion} · 可升级` : `版本 ${publicEnv.appVersion}`; const versionButtonClassName = hasUpdate ? 'border-[var(--status-warning-border)] bg-[var(--status-warning-soft)] text-[var(--status-warning-foreground)]' : 'border-[var(--border-default)]'; const versionErrorMessage = versionFeedback || (latestReleaseQuery.isError ? latestReleaseQuery.error instanceof Error ? latestReleaseQuery.error.message : '版本检查失败,请稍后重试。' : undefined); return ( <>
{isUserMenuOpen ? (

{user?.display_name || user?.username || '用户'}

{user?.username ? (

@{user.username}

) : null}
) : null}
setIsVersionModalOpen(false)} currentVersion={currentVersion} frontendVersion={publicEnv.appVersion} startTime={publicStatusQuery.data?.start_time} release={release} isLoading={latestReleaseQuery.isLoading && !release && isRoot} errorMessage={versionErrorMessage} canUpgrade={isRoot} isChecking={latestReleaseQuery.isFetching} isUpgrading={upgradeMutation.isPending} onRefresh={() => { setVersionFeedback(null); if (isRoot) { void latestReleaseQuery.refetch(); } }} onUpgrade={handleUpgrade} /> ); }