refactor(HomeNavbar): Phase 3 - 提取用户菜单组件
**背景** 继 Phase 1 (静态组件) 和 Phase 2 (Redux订阅) 后,进一步优化 HomeNavbar **重构内容** 1. **新增组件目录** `src/components/Navbars/components/UserMenu/` - UserAvatar.js (101行) - 头像 + 皇冠图标 + 订阅边框 - DesktopUserMenu.js (93行) - 桌面版 Tooltip + 订阅弹窗 - TabletUserMenu.js (166行) - 平板版下拉菜单 (含所有功能) - index.js - 统一导出 2. **HomeNavbar.js 优化** - 删除 ~150 行用户菜单 JSX 代码 - 移除未使用的 Tooltip 导入 - 替换为 DesktopUserMenu / TabletUserMenu 组件调用 - 1533 → 1394 行 (-139行, -9%) **技术亮点** - React.memo 优化渲染性能 - 复用 Redux subscriptionSlice (Phase 2) - 响应式设计 (isDesktop vs isTablet) - 组件内聚,降低父组件耦合 **累计成果** (Phase 1-3) - 原始: 1623 行 - 当前: 1394 行 - 减少: 229 行 (-14%) - 提取: 7 个组件 (4 静态 + 3 用户菜单) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -31,7 +31,6 @@ import {
|
||||
useColorMode,
|
||||
useColorModeValue,
|
||||
useToast,
|
||||
Tooltip,
|
||||
Modal,
|
||||
ModalOverlay,
|
||||
ModalContent,
|
||||
@@ -48,8 +47,6 @@ import { useAuthModal } from '../../hooks/useAuthModal';
|
||||
import { logger } from '../../utils/logger';
|
||||
import { getApiBase } from '../../utils/apiConfig';
|
||||
import SubscriptionButton from '../Subscription/SubscriptionButton';
|
||||
import SubscriptionModal from '../Subscription/SubscriptionModal';
|
||||
import { CrownIcon, TooltipContent } from '../Subscription/CrownTooltip';
|
||||
import { useNavigationEvents } from '../../hooks/useNavigationEvents';
|
||||
|
||||
// Phase 1 优化: 提取的子组件
|
||||
@@ -60,6 +57,9 @@ import CalendarButton from './components/CalendarButton';
|
||||
// Phase 2 优化: 使用 Redux 管理订阅数据
|
||||
import { useSubscription } from '../../hooks/useSubscription';
|
||||
|
||||
// Phase 3 优化: 提取的用户菜单组件
|
||||
import { DesktopUserMenu, TabletUserMenu } from './components/UserMenu';
|
||||
|
||||
/** 二级导航栏组件 - 显示当前一级菜单下的所有二级菜单项 */
|
||||
const SecondaryNav = ({ showCompletenessAlert }) => {
|
||||
const navigate = useNavigate();
|
||||
@@ -1069,156 +1069,16 @@ export default function HomeNavbar() {
|
||||
</Menu>
|
||||
)}
|
||||
|
||||
{/* 头像区域 - 响应式 */}
|
||||
{/* 头像区域 - 响应式 (Phase 3 优化) */}
|
||||
{isDesktop ? (
|
||||
// 大屏:头像点击打开订阅弹窗
|
||||
<>
|
||||
<Tooltip
|
||||
label={<TooltipContent subscriptionInfo={subscriptionInfo} />}
|
||||
placement="bottom"
|
||||
hasArrow
|
||||
bg={useColorModeValue('white', 'gray.800')}
|
||||
borderRadius="lg"
|
||||
border="1px solid"
|
||||
borderColor={useColorModeValue('gray.200', 'gray.600')}
|
||||
boxShadow="lg"
|
||||
p={3}
|
||||
>
|
||||
<Box
|
||||
position="relative"
|
||||
cursor="pointer"
|
||||
onClick={openSubscriptionModal}
|
||||
>
|
||||
<CrownIcon subscriptionInfo={subscriptionInfo} />
|
||||
<Avatar
|
||||
size="sm"
|
||||
name={getDisplayName()}
|
||||
src={user.avatar_url}
|
||||
bg="blue.500"
|
||||
border={subscriptionInfo.type !== 'free' ? '2.5px solid' : 'none'}
|
||||
borderColor={
|
||||
subscriptionInfo.type === 'max' ? '#667eea' :
|
||||
subscriptionInfo.type === 'pro' ? '#667eea' : 'transparent'
|
||||
}
|
||||
_hover={{
|
||||
transform: 'scale(1.05)',
|
||||
boxShadow: subscriptionInfo.type !== 'free'
|
||||
? '0 4px 12px rgba(102, 126, 234, 0.4)'
|
||||
: 'md',
|
||||
}}
|
||||
transition="all 0.2s"
|
||||
/>
|
||||
</Box>
|
||||
</Tooltip>
|
||||
{isSubscriptionModalOpen && (
|
||||
<SubscriptionModal
|
||||
isOpen={isSubscriptionModalOpen}
|
||||
onClose={closeSubscriptionModal}
|
||||
subscriptionInfo={subscriptionInfo}
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
<DesktopUserMenu user={user} />
|
||||
) : (
|
||||
// 中屏:头像作为下拉菜单,包含所有功能
|
||||
<Menu>
|
||||
<MenuButton>
|
||||
<Box position="relative">
|
||||
<CrownIcon subscriptionInfo={subscriptionInfo} />
|
||||
<Avatar
|
||||
size="sm"
|
||||
name={getDisplayName()}
|
||||
src={user.avatar_url}
|
||||
bg="blue.500"
|
||||
border={subscriptionInfo.type !== 'free' ? '2.5px solid' : 'none'}
|
||||
borderColor={
|
||||
subscriptionInfo.type === 'max' ? '#667eea' :
|
||||
subscriptionInfo.type === 'pro' ? '#667eea' : 'transparent'
|
||||
}
|
||||
_hover={{ transform: 'scale(1.05)' }}
|
||||
transition="all 0.2s"
|
||||
/>
|
||||
</Box>
|
||||
</MenuButton>
|
||||
<MenuList minW="320px">
|
||||
{/* 用户信息区 */}
|
||||
<Box px={3} py={2} borderBottom="1px" borderColor={useColorModeValue('gray.200', 'gray.600')}>
|
||||
<Text fontSize="sm" fontWeight="bold">{getDisplayName()}</Text>
|
||||
<Text fontSize="xs" color="gray.500">{user.email}</Text>
|
||||
{user.phone && (
|
||||
<Text fontSize="xs" color="gray.500">{user.phone}</Text>
|
||||
)}
|
||||
{user.has_wechat && (
|
||||
<Badge size="sm" colorScheme="green" mt={1}>微信已绑定</Badge>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{/* 订阅管理 */}
|
||||
<MenuItem icon={<FaCrown />} onClick={openSubscriptionModal}>
|
||||
<Flex justify="space-between" align="center" w="100%">
|
||||
<Text>订阅管理</Text>
|
||||
<Badge colorScheme={subscriptionInfo.type === 'free' ? 'gray' : 'purple'}>
|
||||
{subscriptionInfo.type === 'max' ? 'MAX' :
|
||||
subscriptionInfo.type === 'pro' ? 'PRO' : '免费版'}
|
||||
</Badge>
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
|
||||
{isSubscriptionModalOpen && (
|
||||
<SubscriptionModal
|
||||
isOpen={isSubscriptionModalOpen}
|
||||
onClose={closeSubscriptionModal}
|
||||
subscriptionInfo={subscriptionInfo}
|
||||
/>
|
||||
)}
|
||||
|
||||
<MenuDivider />
|
||||
|
||||
{/* 投资日历 */}
|
||||
<MenuItem icon={<FiCalendar />} onClick={() => navigate('/community')}>
|
||||
<Text>投资日历</Text>
|
||||
</MenuItem>
|
||||
|
||||
{/* 自选股 */}
|
||||
<MenuItem icon={<FiStar />} onClick={() => navigate('/home/center')}>
|
||||
<Flex justify="space-between" align="center" w="100%">
|
||||
<Text>我的自选股</Text>
|
||||
{watchlistQuotes && watchlistQuotes.length > 0 && (
|
||||
<Badge>{watchlistQuotes.length}</Badge>
|
||||
)}
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
|
||||
{/* 自选事件 */}
|
||||
<MenuItem icon={<FiCalendar />} onClick={() => navigate('/home/center')}>
|
||||
<Flex justify="space-between" align="center" w="100%">
|
||||
<Text>我的自选事件</Text>
|
||||
{followingEvents && followingEvents.length > 0 && (
|
||||
<Badge>{followingEvents.length}</Badge>
|
||||
)}
|
||||
</Flex>
|
||||
</MenuItem>
|
||||
|
||||
<MenuDivider />
|
||||
|
||||
{/* 个人中心 */}
|
||||
<MenuItem icon={<FiHome />} onClick={() => navigate('/home/center')}>
|
||||
个人中心
|
||||
</MenuItem>
|
||||
<MenuItem icon={<FiUser />} onClick={() => navigate('/home/profile')}>
|
||||
个人资料
|
||||
</MenuItem>
|
||||
<MenuItem icon={<FiSettings />} onClick={() => navigate('/home/settings')}>
|
||||
账户设置
|
||||
</MenuItem>
|
||||
|
||||
<MenuDivider />
|
||||
|
||||
{/* 退出登录 */}
|
||||
<MenuItem icon={<FiLogOut />} onClick={handleLogout} color="red.500">
|
||||
退出登录
|
||||
</MenuItem>
|
||||
</MenuList>
|
||||
</Menu>
|
||||
<TabletUserMenu
|
||||
user={user}
|
||||
handleLogout={handleLogout}
|
||||
watchlistQuotes={watchlistQuotes}
|
||||
followingEvents={followingEvents}
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 个人中心下拉菜单 - 仅大屏显示 */}
|
||||
|
||||
Reference in New Issue
Block a user