"use client"; import React, { useEffect, useMemo, useState } from 'react'; import { usePathname, useRouter } from 'next/navigation'; import { Menu, Rocket, LogOut, User as UserIcon, X, Info, CalendarDays } from 'lucide-react'; import { Drawer } from 'antd'; import { fetchTabsByCode, HomeTabItem } from '@/api/serversetting'; import { getSigninStatus } from '@/api/signin'; import { getCurrentUser, isAuthenticated, logoutUser } from '@/lib/auth'; import { getUserSubscriptionInfo } from '@/lib/stripe'; import { trackEvent } from '@/utils/analytics'; import { GradientText } from '@/components/ui/gradient-text'; import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog'; import SigninBox from './signin-box'; import { navigationItems } from './type'; import './H5TopBar.css'; interface H5TopBarProps { /** 点击首页 tab 时的回调,用于页面内滚动 */ onSelectHomeTab?: (key: string) => void; } interface CurrentUserMinimal { id?: string; name?: string; email?: string; username?: string; } /** * 移动端顶栏(抽屉式菜单) * - 未登录:左 LOGO → '/',右侧 Signup + 菜单;抽屉显示 homeTabs 与 登录/注册 * - 已登录:左 LOGO → '/home',右侧 升级图标 + 菜单;抽屉显示 用户卡片、快捷充值、入口与登出 */ export default function H5TopBar({ onSelectHomeTab }: H5TopBarProps) { const router = useRouter(); const pathname = usePathname(); const [isLogin, setIsLogin] = useState(false); const [user, setUser] = useState(null); const [credits, setCredits] = useState(0); const [isBuyingTokens, setIsBuyingTokens] = useState(false); const [homeTabs, setHomeTabs] = useState([]); const [drawerOpen, setDrawerOpen] = useState(false); const [customAmount, setCustomAmount] = useState(""); const [isSigninModalOpen, setIsSigninModalOpen] = useState(false); const [isManagingSubscription, setIsManagingSubscription] = useState(false); const [subscriptionStatus, setSubscriptionStatus] = useState(""); const [planName, setPlanName] = useState(""); const [needsSigninBadge, setNeedsSigninBadge] = useState(false); const [isGlassActive, setIsGlassActive] = useState(false); const isHome = useMemo(() => pathname === '/', [pathname]); useEffect(() => { setIsLogin(isAuthenticated()); const u = getCurrentUser(); setUser(u || null); }, []); useEffect(() => { if (!user?.id) return; let ignore = false; const load = async () => { try { const res = await getUserSubscriptionInfo(String(user.id)); if (!ignore && res?.data?.credits !== undefined) { setCredits(res.data.credits); if (typeof res.data.subscription_status === 'string') { setSubscriptionStatus(res.data.subscription_status); } if (typeof res.data.plan_name === 'string') { setPlanName(res.data.plan_name); } } } catch {} }; load(); return () => { ignore = true; }; }, [user?.id]); // 仅首页时加载 homeTabs,用于未登录抽屉导航 useEffect(() => { if (!isHome) return; let mounted = true; const loadTabs = async () => { try { const tabs = await fetchTabsByCode('homeTab'); if (mounted && Array.isArray(tabs)) setHomeTabs(tabs); } catch {} }; loadTabs(); return () => { mounted = false; }; }, [isHome]); // 获取今日签到状态,未签到则显示红点 useEffect(() => { const loadSignin = async () => { if (!isLogin) return; try { const data: any = await getSigninStatus(); const hasSignin = !!data?.data?.has_signin; setNeedsSigninBadge(!hasSignin); } catch {} }; loadSignin(); }, [isLogin]); // 首页滚动 30vh 后开启玻璃质感背景 useEffect(() => { if (!isHome) return; const computeAndSet = (evt?: Event) => { const threshold = Math.max(0, window.innerHeight * 0.3); const winY = window.scrollY || window.pageYOffset || 0; const docElY = (document.documentElement && document.documentElement.scrollTop) || 0; const scrollingElY = (document.scrollingElement as any)?.scrollTop || 0; const bodyY = (document.body && (document.body as any).scrollTop) || 0; let currentY = Math.max(winY, docElY, scrollingElY, bodyY); const target = evt?.target as any; if (target && typeof target.scrollTop === 'number') { currentY = Math.max(currentY, target.scrollTop); } const nextActive = currentY >= threshold; setIsGlassActive(nextActive); }; // 初始计算一次 computeAndSet(); // 监听 window 与 document(捕获阶段,捕获内部滚动容器事件) window.addEventListener('scroll', computeAndSet, { passive: true }); document.addEventListener('scroll', computeAndSet, { passive: true, capture: true }); return () => { window.removeEventListener('scroll', computeAndSet); document.removeEventListener('scroll', computeAndSet, { capture: true } as any); }; }, [isHome]); // 离开首页时,移除玻璃背景 useEffect(() => { if (!isHome) { setIsGlassActive(false); } else { } }, [isHome]); const handleLogoClick = () => { if (isLogin) { router.push('/home'); } else { router.push('/'); } }; const handleUpgrade = () => { router.push('/pricing'); }; const handleBuyTokens = async (amount: number) => { if (!user?.id) return; setIsBuyingTokens(true); try { const url = `/pay-redirect?type=token&amount=${encodeURIComponent(amount)}&pkg=basic`; window.open(url, '_blank'); window.postMessage({ type: 'waiting-payment', paymentType: 'subscription' }, '*'); } finally { setIsBuyingTokens(false); } }; const handleCustomAmountBuy = async () => { const amount = parseInt(customAmount); if (isNaN(amount) || amount < 50) { window.msg.warning("Minimum purchase is 50 credits."); return; } await handleBuyTokens(amount); setCustomAmount(""); }; const handleSignin = () => { setIsSigninModalOpen(true); }; const handleManageSubscription = async () => { if (!user?.id) return; setIsManagingSubscription(true); try { // 获取用户当前订阅信息 const response = await getUserSubscriptionInfo(String(user.id)); if (!response?.successful || !response?.data) { throw new Error('Failed to get subscription info'); } const currentPlan = response.data.plan_name; const billingType = 'month'; // 默认使用月付,用户可以在pricing页面切换 // 跟踪订阅管理按钮点击事件 trackEvent('subscription_manage_click', { event_category: 'subscription', event_label: 'manage_subscription', custom_parameters: { current_plan: currentPlan, billing_type: billingType, }, }); // 复用pricing页面的跳转方案:构建pay-redirect URL const url = `/pay-redirect?type=subscription&plan=${encodeURIComponent(currentPlan)}&billing=${encodeURIComponent(billingType)}`; const win = window.open(url, '_blank'); // 通知当前窗口等待支付(显示loading模态框) window.postMessage({ type: 'waiting-payment', paymentType: 'subscription', }, '*'); if (!win) { throw new Error('Unable to open redirect window, please check popup settings'); } } catch (error) { console.error('Failed to manage subscription:', error); // 如果出错,回退到pricing页面 router.push('/pricing'); } finally { setIsManagingSubscription(false); } }; return ( <>
{/* 左侧 LOGO */}

{/* beta标签 */}
Beta
{/* 右侧操作区 */}
{ !drawerOpen && ( <> {isLogin ? ( ) : ( )} ) } {/* 菜单抽屉(antd Drawer) */} setDrawerOpen(false)} title={null} closable height={undefined} maskClosable // 64px 顶栏高度 + 8px 安全间距 styles={{ content: { position: 'absolute', top: '3.5rem', height: isHome ? 'auto' : 'calc(100dvh - 3.5rem)' }, body: { padding: 0 }, header: { display: 'none' }, mask: { position: 'absolute', top: '3.5rem', height: 'calc(100dvh - 3.5rem)', backgroundColor: 'transparent' }, }} className="[&_.ant-drawer-content]:bg-white [&_.ant-drawer-content]:text-black dark:[&_.ant-drawer-content]:bg-[#0b0b0b] dark:[&_.ant-drawer-content]:text-white dark:[&_.ant-drawer-body]:bg-[#0b0b0b] dark:[&_.ant-drawer-body]:text-white" >
{/* 用户信息/未登录头部 */} {isLogin ? (
{(user?.username || user?.name || 'MF').slice(0, 1)}
{user?.name || user?.username || 'User'}
{user?.email}
) : ( <> )} {/* 内容区 */}
{isLogin ? (
{/* 积分中心 */}
{/* 签到 */} {/* 积分 */}
{credits} credits
{/* 快捷充值 */}
{/* 自定义充值 */}
setCustomAmount(e.target.value)} placeholder="Custom amount" className="w-[120px] h-9 px-2 text-sm bg-white/10 text-black dark:text-white placeholder-black/40 dark:placeholder-white/60 border border-black/20 dark:border-white/20 rounded focus:outline-none mobile-input" min={1} />
{/* 菜单目录 */}
{navigationItems.map((group) => ( group.items.map((nav) => { const isActive = pathname === nav.href; return ( ); }) ))}
{/* 其他功能 */}
{planName !== 'none' && subscriptionStatus !== 'INACTIVE' && ( )}
) : (
{isHome && homeTabs.length > 0 && (
{homeTabs.map((tab) => ( ))}
)}
)}
{/* 底部操作 */} {isLogin && (
)}
{/* Sign-in Modal */} { setIsSigninModalOpen(open); if (!open) { // 刷新积分 if (user?.id) { getUserSubscriptionInfo(String(user.id)).then((res:any)=>{ if(res?.data?.credits!==undefined){ setCredits(res.data.credits) } }).catch(()=>{}); } // 关闭签到弹窗后,重新检查红点 if (isLogin) { getSigninStatus().then((d:any)=> setNeedsSigninBadge(!d?.data?.has_signin)).catch(()=>{}); } } }}> { try { if (user?.id) { const res = await getUserSubscriptionInfo(String(user.id)); if (res?.data?.credits !== undefined) { setCredits(res.data.credits); } } } catch {} // 成功签到后去除红点 setNeedsSigninBadge(false); }} />
); }