Files
vf_react/src/components/Navbars/HomeNavbar.js
2025-11-21 14:07:04 +08:00

205 lines
7.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import React, { useCallback, useState } from 'react';
import {
Box,
Flex,
Text,
Button,
Container,
useDisclosure,
HStack,
Icon,
Menu,
MenuButton,
MenuList,
MenuItem,
Badge,
Grid,
IconButton,
useBreakpointValue,
Spinner,
useColorMode,
useColorModeValue,
useToast,
} from '@chakra-ui/react';
import { ChevronDownIcon, HamburgerIcon, SunIcon, MoonIcon } from '@chakra-ui/icons';
import { FiStar, FiCalendar, FiUser, FiSettings, FiHome, FiLogOut } from 'react-icons/fi';
import { FaCrown } from 'react-icons/fa';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '../../contexts/AuthContext';
import { useAuthModal } from '../../hooks/useAuthModal';
import { logger } from '../../utils/logger';
import { getApiBase } from '../../utils/apiConfig';
import SubscriptionButton from '../Subscription/SubscriptionButton';
import { useNavigationEvents } from '../../hooks/useNavigationEvents';
// Phase 1 优化: 提取的子组件
import BrandLogo from './components/BrandLogo';
import LoginButton from './components/LoginButton';
import CalendarButton from './components/CalendarButton';
// Phase 2 优化: 使用 Redux 管理订阅数据
import { useSubscription } from '../../hooks/useSubscription';
// Phase 3 优化: 提取的用户菜单组件
import { DesktopUserMenu, TabletUserMenu } from './components/UserMenu';
// Phase 4 优化: 提取的导航菜单组件
import { DesktopNav, PersonalCenterMenu } from './components/Navigation';
// Phase 5 优化: 提取的移动端抽屉菜单组件
import { MobileDrawer } from './components/MobileDrawer';
// Phase 6 优化: 提取的功能菜单组件和自定义 Hooks
import { WatchlistMenu, FollowingEventsMenu } from './components/FeatureMenus';
import { useWatchlist } from '../../hooks/useWatchlist';
import { useFollowingEvents } from '../../hooks/useFollowingEvents';
// Phase 7 优化: 提取的二级导航、资料完整性、右侧功能区组件
import SecondaryNav from './components/SecondaryNav';
import ProfileCompletenessAlert from './components/ProfileCompletenessAlert';
import { useProfileCompleteness } from '../../hooks/useProfileCompleteness';
import NavbarActions from './components/NavbarActions';
// Phase 7: SecondaryNav 组件已提取到 ./components/SecondaryNav/index.js
// Phase 4: MoreNavMenu 和 NavItems 组件已提取到 Navigation 目录
export default function HomeNavbar() {
const { isOpen, onOpen, onClose } = useDisclosure();
const navigate = useNavigate();
const isMobile = useBreakpointValue({ base: true, md: false });
const isDesktop = useBreakpointValue({ base: false, md: false, lg: true });
const { user, isAuthenticated, logout, isLoading } = useAuth();
const { openAuthModal } = useAuthModal();
const { colorMode, toggleColorMode } = useColorMode();
const navbarBg = useColorModeValue('white', 'gray.800');
const navbarBorder = useColorModeValue('gray.200', 'gray.700');
const brandText = useColorModeValue('gray.800', 'white');
const brandHover = useColorModeValue('blue.600', 'blue.300');
const toast = useToast();
// 🎯 初始化导航埋点Hook
const navEvents = useNavigationEvents({ component: 'main_navbar' });
// ⚡ 提取 userId 为独立变量,避免 user 对象引用变化导致无限循环
const userId = user?.id;
const prevUserIdRef = React.useRef(userId);
const prevIsAuthenticatedRef = React.useRef(isAuthenticated);
// 添加调试信息 - 暂时注释以减少日志噪音
// logger.debug('HomeNavbar', '组件渲染状态', {
// hasUser: !!user,
// isAuthenticated,
// isLoading,
// userId: user?.id
// });
// 获取显示名称的函数
const getDisplayName = () => {
if (!user) return '';
return user.nickname || user.username || user.name || user.email || '用户';
};
// Phase 6: 自选股和关注事件逻辑已提取到自定义 Hooks
const { watchlistQuotes, followingEvents } = useWatchlist();
const { followingEvents: events } = useFollowingEvents();
// 注意:这里只需要数据用于 TabletUserMenu实际的菜单组件会自己管理状态
// Phase 7: 资料完整性逻辑已提取到 useProfileCompleteness Hook
const {
profileCompleteness,
showAlert: showCompletenessAlert,
setShowAlert: setShowCompletenessAlert,
resetCompleteness
} = useProfileCompleteness({ isAuthenticated, user });
// 处理登出
const handleLogout = async () => {
try {
await logout();
// Phase 7: 使用 resetCompleteness 重置资料完整性状态
resetCompleteness();
// logout函数已经包含了跳转逻辑这里不需要额外处理
} catch (error) {
logger.error('HomeNavbar', 'handleLogout', error, {
userId: user?.id
});
}
};
// Phase 2: 使用 Redux 订阅数据
const {
subscriptionInfo,
isSubscriptionModalOpen,
openSubscriptionModal,
closeSubscriptionModal
} = useSubscription();
// Phase 6: loadWatchlistQuotes, loadFollowingEvents, handleRemoveFromWatchlist,
// handleUnfollowEvent 已移至自定义 Hooks 中,由各自组件内部管理
// Phase 2: 加载订阅信息逻辑已移至 useSubscriptionData Hook
return (
<>
{/* 资料完整性提醒横幅 (Phase 7 优化) */}
{showCompletenessAlert && (
<ProfileCompletenessAlert
profileCompleteness={profileCompleteness}
onClose={() => setShowCompletenessAlert(false)}
onNavigateToSettings={() => navigate('/home/settings')}
/>
)}
<Box
position="sticky"
top={showCompletenessAlert ? "60px" : 0}
zIndex={1000}
bg={navbarBg}
backdropFilter="blur(10px)"
borderBottom="1px"
borderColor={navbarBorder}
py={{ base: 2, md: 3 }}
>
<Container maxW="container.xl" px={{ base: 3, md: 4 }}>
<Flex justify="space-between" align="center">
{/* Logo - 价小前投研 */}
<BrandLogo />
{/* 中间导航区域 - 响应式 (Phase 4 优化) */}
{isDesktop && (
// 桌面端:完整导航菜单(移动端和平板端的汉堡菜单已移至右侧)
<DesktopNav isAuthenticated={isAuthenticated} user={user} />
)}
{/* 右侧功能区 (Phase 7 优化) */}
<NavbarActions
isLoading={isLoading}
isAuthenticated={isAuthenticated}
user={user}
isDesktop={isDesktop}
onMenuOpen={onOpen}
handleLogout={handleLogout}
watchlistQuotes={watchlistQuotes}
followingEvents={followingEvents}
/>
</Flex>
</Container>
{/* 移动端抽屉菜单 (Phase 5 优化) */}
<MobileDrawer
isOpen={isOpen}
onClose={onClose}
isAuthenticated={isAuthenticated}
user={user}
handleLogout={handleLogout}
openAuthModal={openAuthModal}
/>
</Box>
{/* 二级导航栏 - 显示当前页面所属的二级菜单 */}
{!isMobile && <SecondaryNav showCompletenessAlert={showCompletenessAlert} />}
{/* 投资日历 Modal - 已移至 CalendarButton 组件内部 */}
</>
);
}