"use client"; import "../pages/style/top-bar.css"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogTitle, } from "@/components/ui/dialog"; import { GradientText } from "@/components/ui/gradient-text"; import { useTheme } from "next-themes"; import { Sun, Moon, User, Sparkles, LogOut, PanelsLeftBottom, Bell, Info, CalendarDays, } from "lucide-react"; import { motion } from "framer-motion"; import { createPortal } from "react-dom"; import { useRouter, usePathname } from "next/navigation"; import React, { useRef, useEffect, useLayoutEffect, useState } from "react"; import { logoutUser } from "@/lib/auth"; import { createPortalSession, redirectToPortal, getUserSubscriptionInfo, buyTokens, } from "@/lib/stripe"; import UserCard from "@/components/common/userCard"; import { showInsufficientPointsNotification } from "@/utils/notifications"; import SigninBox from "./signin-box"; interface User { id: string; name: string; email: string; avatar: string; username: string; plan_name?: string; } export function TopBar({ collapsed, isDesktop=true }: { collapsed: boolean, isDesktop?: boolean }) { const router = useRouter(); const [isOpen, setIsOpen] = React.useState(false); const menuRef = useRef(null); const buttonRef = useRef(null); const [currentUser, setCurrentUser] = useState( JSON.parse(localStorage.getItem("currentUser") || "{}") ); const pathname = usePathname(); const [mounted, setMounted] = React.useState(false); const [isLogin, setIsLogin] = useState(false); const [isManagingSubscription, setIsManagingSubscription] = useState(false); const [subscriptionStatus, setSubscriptionStatus] = useState(""); const [credits, setCredits] = useState(0); const [isLoadingSubscription, setIsLoadingSubscription] = useState(false); const [isBuyingTokens, setIsBuyingTokens] = useState(false); const [customAmount, setCustomAmount] = useState(""); const [isSigninModalOpen, setIsSigninModalOpen] = useState(false); // 获取用户订阅信息 const fetchSubscriptionInfo = async () => { if (!currentUser?.id) return; setIsLoadingSubscription(true); try { const response = await getUserSubscriptionInfo(String(currentUser.id)); if (response.successful && response.data) { const status = response.data.subscription_status; setSubscriptionStatus(status); setCredits(response.data.credits); // 更新 currentUser 的 plan_name setCurrentUser((prev) => ({ ...prev, plan_name: response.data.plan_name, // HACK })); } } catch (error) { console.error("获取订阅信息失败:", error); } finally { setIsLoadingSubscription(false); } }; // 处理Token购买(同域新页 + postMessage 方式重定向) const handleBuyTokens = async (tokenAmount: number) => { if (!currentUser?.id) { console.error("用户未登录"); return; } if (tokenAmount <= 0) { console.error("Token数量必须大于0"); return; } // 先同步打开同域新页面,避免被拦截 const redirectWindow = window.open("/pay-redirect", "_blank"); if (!redirectWindow) { console.error("无法打开支付重定向页面,可能被浏览器拦截"); return; } setIsBuyingTokens(true); try { const response = await buyTokens({ token_amount: tokenAmount, package_type: "basic" }); if (response.successful && response.data?.checkout_url) { // 通知当前窗口等待支付,标识为Token购买 window.postMessage({ type: "waiting-payment", paymentType: "token" }, "*"); sessionStorage.setItem('session_id', response.data.session_id); // 通过 postMessage 通知新页面进行重定向 redirectWindow.postMessage({ type: "redirect-to-payment", url: response.data.checkout_url }, window.location.origin); } else { console.error("创建Token购买失败:", response.message); // 通知新页显示错误 redirectWindow.postMessage({ type: "redirect-error", message: response.message || "创建支付失败" }, window.location.origin); } } catch (error: unknown) { console.error("Token购买失败:", error); try { redirectWindow.postMessage({ type: "redirect-error", message: "网络或服务异常,请关闭此页重试" }, window.location.origin); } catch {} } finally { setIsBuyingTokens(false); } }; // 处理自定义金额购买 const handleCustomAmountBuy = async () => { const amount = parseInt(customAmount); if (isNaN(amount) || amount <= 0) { console.error("请输入有效的Token数量"); return; } await handleBuyTokens(amount); setCustomAmount(""); // 清空输入框 }; useEffect(() => { const token = localStorage.getItem("token"); if (token) { setIsLogin(true); } else { setIsLogin(false); } }); useLayoutEffect(() => { console.log("Setting mounted state"); setMounted(true); return () => console.log("Cleanup mounted effect"); }, []); // 处理订阅管理 const handleManageSubscription = async () => { if (!currentUser?.id) { console.error("用户未登录"); return; } setIsManagingSubscription(true); try { const response = await createPortalSession({ user_id: String(currentUser.id), return_url: window.location.origin + "/dashboard", }); if (response.successful && response.data?.portal_url) { redirectToPortal(response.data.portal_url); } else { console.log("cannot open the manage subscription"); return; } } catch (error) { console.log("cannot open the manage subscription"); return; } finally { setIsManagingSubscription(false); } }; // 处理点击事件 useEffect(() => { if (!isOpen) return; let isClickStartedInside = false; const handleMouseDown = (event: MouseEvent) => { const target = event.target as Node; isClickStartedInside = !!( menuRef.current?.contains(target) || buttonRef.current?.contains(target) ); }; const handleMouseUp = (event: MouseEvent) => { const target = event.target as Node; const isClickEndedInside = !!( menuRef.current?.contains(target) || buttonRef.current?.contains(target) ); // 只有当点击开始和结束都在外部时才关闭 if (!isClickStartedInside && !isClickEndedInside) { setIsOpen(false); } isClickStartedInside = false; }; // 在冒泡阶段处理事件 document.addEventListener("mousedown", handleMouseDown); document.addEventListener("mouseup", handleMouseUp); return () => { document.removeEventListener("mousedown", handleMouseDown); document.removeEventListener("mouseup", handleMouseUp); }; }, [isOpen]); const handleAnimationEnd = (event: React.AnimationEvent) => { const element = event.currentTarget; element.classList.remove("on"); }; const handleMouseEnter = (event: React.MouseEvent) => { const element = event.currentTarget; element.classList.add("on"); }; /** * 处理签到功能,打开签到modal */ const handleSignin = () => { setIsSigninModalOpen(true); }; return (
router.push("/")} onMouseEnter={handleMouseEnter} onAnimationEnd={handleAnimationEnd} >

{/* beta标签 */}
Beta
{isLogin ? (
{/* Pricing Link */} {pathname === "/" ? (
router.push("/movies")} > Go Started
) : ( )} {/* Notifications */} {/* */} {/* Theme Toggle */} {/* */} {/* User Menu */}
{mounted && isOpen ? ((createPortal as any)( e.stopPropagation()} >
{/* 顶部用户信息 */}
{currentUser.username ? currentUser.username.charAt(0) : "MF"}

{currentUser.name || currentUser.username}

{currentUser.email}

{/* Sign-in entry */}
{/* AI 积分 */}
{isLoadingSubscription ? "Loading..." : `${credits} credits`}
{/* Purchase Credits 按钮 */}
{/* 自定义金额输入 */}
setCustomAmount(e.target.value)} placeholder="Custom amount" className="flex-1 px-2 py-1 text-xs bg-white/10 text-white placeholder-white/60 border border-white/20 rounded focus:outline-none focus:border-blue-400" min="1" disabled={isBuyingTokens} />
{/* 操作按钮区域 */}
{currentUser.plan_name !== "none" && subscriptionStatus !== 'INACTIVE' && ( )}
, document.body ) as unknown as React.ReactNode) : null}
) : (
router.push("/signup")} > Sign Up
router.push("/movies")} > Go Started
)}
{/* Sign-in Modal */}
); }