修复很多问题

This commit is contained in:
海龙 2025-08-29 06:45:11 +08:00
parent 5b268abe5e
commit a259d66f7c
5 changed files with 144 additions and 100 deletions

View File

@ -26,7 +26,6 @@ export default function RootLayout({
}) { }) {
const [showCallbackModal, setShowCallbackModal] = useState(false) const [showCallbackModal, setShowCallbackModal] = useState(false)
const openCallback = async function (ev: MessageEvent<any>) { const openCallback = async function (ev: MessageEvent<any>) {
console.log(ev)
if (ev.data.type === 'waiting-payment') { if (ev.data.type === 'waiting-payment') {
setShowCallbackModal(true) setShowCallbackModal(true)
} }

View File

@ -15,8 +15,39 @@ import { fetchSubscriptionPlans, SubscriptionPlan } from "@/lib/stripe";
export default function PricingPage() { export default function PricingPage() {
useEffect(() => {
// 获取当前窗口尺寸
const currentWidth = window.innerWidth;
const currentHeight = window.innerHeight;
// 计算缩放比例 (1920x1080)
const wScale = currentWidth / 1920;
const hScale = currentHeight / 1080;
// 检查app节点是否存在
const pricingPage = document.getElementById("pricing-page");
if (!pricingPage) {
console.error("未找到app节点");
return;
}
// setHPading((hScale || 1) * 10);
// 创建样式元素
const style = document.createElement("style");
// 设置CSS样式
style.textContent = `
#pricing-page {
transform-origin: top left;
transform: scale(${wScale}, ${hScale});
width: 1920px;
height: 1080px;
}
`;
// 将样式添加到head
document.head.appendChild(style);
}, []);
return ( return (
<div className="w-full h-full overflow-y-auto bg-black text-white pb-[10rem]"> <div className="w-full h-full overflow-y-auto bg-black text-white pb-[10rem]" id="pricing-page">
{/* Main Content */} {/* Main Content */}
<HomeModule5 /> <HomeModule5 />
</div> </div>
@ -66,7 +97,7 @@ function HomeModule5() {
}, [plans, billingType]); }, [plans, billingType]);
const handleSubscribe = async (planName: string) => { const handleSubscribe = async (planName: string) => {
if (planName === "hobby") { if (planName === "Kickoff") {
return; return;
} }
@ -103,14 +134,14 @@ function HomeModule5() {
return ( return (
<div <div
data-alt="core-value-section" data-alt="core-value-section"
className="home-module5 h-[1600px] relative flex flex-col items-center justify-center w-full bg-black snap-start" className="home-module5 h-[1300px] relative flex flex-col items-center justify-center w-full bg-black snap-start"
> >
<div <div
data-alt="core-value-content" data-alt="core-value-content"
className="center z-10 flex flex-col items-center mb-[8rem]" className="center z-10 flex flex-col items-center mb-[4rem]"
> >
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[1.5rem]"> <h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[1.5rem]">
Start Creating Pick a plan and make it yours
</h2> </h2>
{/* 计费切换 */} {/* 计费切换 */}
@ -133,7 +164,7 @@ function HomeModule5() {
: "text-white hover:text-gray-300" : "text-white hover:text-gray-300"
}`} }`}
> >
Yearly - <span className="text-[#FFCC6D]">10%</span> Yearly - <span className="text-[#FFCC6D]">20%</span>
</button> </button>
</div> </div>
</div> </div>
@ -143,7 +174,7 @@ function HomeModule5() {
{pricingPlans.map((plan, index) => ( {pricingPlans.map((plan, index) => (
<div <div
key={index} key={index}
className=" w-[26rem] h-[38.125rem] bg-black rounded-lg p-[1.5rem] border border-white/20" className=" w-[24rem] h-[38.125rem] bg-black rounded-lg p-[1.5rem] border border-white/20"
> >
<h3 className="text-white text-2xl font-normal mb-[1rem]"> <h3 className="text-white text-2xl font-normal mb-[1rem]">
{plan.title} {plan.title}

View File

@ -714,7 +714,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
{!isExpanded && ( {!isExpanded && (
<div className="absolute top-2 right-2 z-10 flex items-center"> <div className="absolute top-2 right-2 z-10 flex items-center">
{/* 使用 Dropdown 替代手动控制显示/隐藏 */} {/* 使用 Dropdown 替代手动控制显示/隐藏 */}
<Dropdown {/* <Dropdown
open={showConfigOptions} open={showConfigOptions}
onOpenChange={setShowConfigOptions} onOpenChange={setShowConfigOptions}
popupRender={() => ( popupRender={() => (
@ -730,7 +730,6 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
placement={"left" as any} placement={"left" as any}
trigger={["click"]} trigger={["click"]}
> >
{/* 配置项显示控制按钮 - 齿轮图标 */}
<Tooltip title="config" placement="top"> <Tooltip title="config" placement="top">
<button <button
data-alt="config-toggle-button" data-alt="config-toggle-button"
@ -739,7 +738,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
<Settings className="w-4 h-4 text-white/80" /> <Settings className="w-4 h-4 text-white/80" />
</button> </button>
</Tooltip> </Tooltip>
</Dropdown> </Dropdown> */}
</div> </div>
)} )}
@ -771,7 +770,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
{/* 左侧功能按钮区域 */} {/* 左侧功能按钮区域 */}
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
{/* 获取创意按钮 */} {/*
<Tooltip <Tooltip
title="Get creative ideas for your story" title="Get creative ideas for your story"
placement="top" placement="top"
@ -787,10 +786,10 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
<Lightbulb className="w-4 h-4" /> <Lightbulb className="w-4 h-4" />
)} )}
</button> </button>
</Tooltip> </Tooltip> */}
{/* 分隔线 */} {/* 分隔线 */}
<div className="w-px h-4 bg-white/[0.20]"></div> {/* <div className="w-px h-4 bg-white/[0.20]"></div> */}
{/* 模板故事按钮 */} {/* 模板故事按钮 */}
<Tooltip title="Choose from movie templates" placement="top"> <Tooltip title="Choose from movie templates" placement="top">
@ -830,6 +829,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
isCreating={isCreating} isCreating={isCreating}
handleCreateVideo={handleCreateVideo} handleCreateVideo={handleCreateVideo}
icon={<Clapperboard className="w-5 h-5" />} icon={<Clapperboard className="w-5 h-5" />}
className="mr-1 mb-1"
/> />
</div> </div>
</div> </div>

View File

@ -12,14 +12,17 @@ import {
LogOut, LogOut,
PanelsLeftBottom, PanelsLeftBottom,
Bell, Bell,
} from 'lucide-react'; } from "lucide-react";
import { motion } from 'framer-motion'; import { motion } from "framer-motion";
import ReactDOM from 'react-dom'; import ReactDOM from "react-dom";
import { useRouter, usePathname } from 'next/navigation'; import { useRouter, usePathname } from "next/navigation";
import React, { useRef, useEffect, useLayoutEffect, useState } from 'react'; import React, { useRef, useEffect, useLayoutEffect, useState } from "react";
import { logoutUser } from '@/lib/auth'; import { logoutUser } from "@/lib/auth";
import { createPortalSession, redirectToPortal, getUserSubscriptionInfo } from '@/lib/stripe'; import {
createPortalSession,
redirectToPortal,
getUserSubscriptionInfo,
} from "@/lib/stripe";
interface User { interface User {
id: string; id: string;
@ -27,6 +30,7 @@ interface User {
email: string; email: string;
avatar: string; avatar: string;
username: string; username: string;
plan_name?: string;
} }
export function TopBar({ export function TopBar({
@ -40,14 +44,14 @@ export function TopBar({
const [isOpen, setIsOpen] = React.useState(false); const [isOpen, setIsOpen] = React.useState(false);
const menuRef = useRef<HTMLDivElement>(null); const menuRef = useRef<HTMLDivElement>(null);
const buttonRef = useRef<HTMLButtonElement>(null); const buttonRef = useRef<HTMLButtonElement>(null);
const currentUser: User = JSON.parse( const [currentUser, setCurrentUser] = useState<User>(
localStorage.getItem("currentUser") || "{}" JSON.parse(localStorage.getItem("currentUser") || "{}")
); );
const pathname = usePathname() const pathname = usePathname();
const [mounted, setMounted] = React.useState(false); const [mounted, setMounted] = React.useState(false);
const [isLogin, setIsLogin] = useState(false); const [isLogin, setIsLogin] = useState(false);
const [isManagingSubscription, setIsManagingSubscription] = useState(false); const [isManagingSubscription, setIsManagingSubscription] = useState(false);
const [subscriptionStatus, setSubscriptionStatus] = useState<string>(''); const [subscriptionStatus, setSubscriptionStatus] = useState<string>("");
const [credits, setCredits] = useState<number>(100); const [credits, setCredits] = useState<number>(100);
const [isLoadingSubscription, setIsLoadingSubscription] = useState(false); const [isLoadingSubscription, setIsLoadingSubscription] = useState(false);
@ -59,11 +63,18 @@ export function TopBar({
try { try {
const response = await getUserSubscriptionInfo(String(currentUser.id)); const response = await getUserSubscriptionInfo(String(currentUser.id));
if (response.successful && response.data) { if (response.successful && response.data) {
setSubscriptionStatus(response.data.subscription_status); const status = response.data.subscription_status;
setSubscriptionStatus(status);
setCredits(response.data.credits); setCredits(response.data.credits);
// 更新 currentUser 的 plan_name
setCurrentUser((prev) => ({
...prev,
plan_name: response.data.plan_name,
}));
} }
} catch (error) { } catch (error) {
console.error('获取订阅信息失败:', error); console.error("获取订阅信息失败:", error);
} finally { } finally {
setIsLoadingSubscription(false); setIsLoadingSubscription(false);
} }
@ -86,7 +97,7 @@ export function TopBar({
// 处理订阅管理 // 处理订阅管理
const handleManageSubscription = async () => { const handleManageSubscription = async () => {
if (!currentUser?.id) { if (!currentUser?.id) {
console.error('用户未登录'); console.error("用户未登录");
return; return;
} }
@ -94,7 +105,7 @@ export function TopBar({
try { try {
const response = await createPortalSession({ const response = await createPortalSession({
user_id: String(currentUser.id), user_id: String(currentUser.id),
return_url: window.location.origin + '/dashboard' return_url: window.location.origin + "/dashboard",
}); });
if (response.successful && response.data?.portal_url) { if (response.successful && response.data?.portal_url) {
@ -199,20 +210,31 @@ export function TopBar({
</div> </div>
</div> </div>
{ {isLogin ? (
isLogin ?(<div className="flex items-center space-x-4"> <div className="flex items-center space-x-4">
{/* Pricing Link */} {/* Pricing Link */}
<Button {pathname === "/" ? (
variant="ghost" <Button
size="sm" variant="ghost"
onClick={() => { size="sm"
localStorage.setItem("callBackUrl", pathname); onClick={() => router.push("/create")}
window.open("/pricing", "_blank"); className="bg-white text-black rounded-full hover:bg-gray-100"
}} >
className="text-gray-300 hover:text-white" Go Start
> </Button>
Pricing ) : (
</Button> <Button
variant="ghost"
size="sm"
onClick={() => {
localStorage.setItem("callBackUrl", pathname);
window.open("/pricing", "_blank");
}}
className="text-gray-300 hover:text-white"
>
Pricing
</Button>
)}
{/* Notifications */} {/* Notifications */}
{/* <Button variant="ghost" size="sm" onClick={() => showQueueNotification(3, 10)}> {/* <Button variant="ghost" size="sm" onClick={() => showQueueNotification(3, 10)}>
@ -274,9 +296,27 @@ export function TopBar({
MF MF
</div> </div>
<div className="flex-1"> <div className="flex-1">
<p className="text-sm font-medium"> <div className="flex items-center gap-2">
{currentUser.name || currentUser.username} <p className="text-sm font-medium">
</p> {currentUser.name || currentUser.username}
</p>
{currentUser.plan_name &&
currentUser.plan_name !== "none" && (
<span
className={`inline-flex items-center px-2 py-1 text-xs font-medium rounded-full ${
currentUser.plan_name === "Kickoff"
? "bg-blue-100 text-blue-800"
: currentUser.plan_name === "Pro"
? "bg-purple-100 text-purple-800"
: currentUser.plan_name === "Ultra"
? "bg-orange-100 text-orange-800"
: ""
}`}
>
{currentUser.plan_name}
</span>
)}
</div>
<p className="text-xs text-gray-500"> <p className="text-xs text-gray-500">
{currentUser.email} {currentUser.email}
</p> </p>
@ -298,7 +338,9 @@ export function TopBar({
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
<Sparkles className="h-4 w-4" /> <Sparkles className="h-4 w-4" />
<span className="text-white underline text-sm"> <span className="text-white underline text-sm">
{isLoadingSubscription ? '...' : `${credits} credits`} {isLoadingSubscription
? "..."
: `${credits} credits`}
</span> </span>
</div> </div>
<Button <Button
@ -311,7 +353,7 @@ export function TopBar({
> >
Upgrade Upgrade
</Button> </Button>
{subscriptionStatus === 'ACTIVE' && ( {subscriptionStatus === "ACTIVE" && (
<Button <Button
variant="outline" variant="outline"
size="sm" size="sm"
@ -323,62 +365,34 @@ export function TopBar({
</Button> </Button>
)} )}
</div> </div>
{/* Menu Items */}
<div className="p-2">
{/* <motion.button
whileHover={{ backgroundColor: 'rgba(255,255,255,0.1)' }}
className="w-full flex items-center space-x-2 px-3 py-2 rounded-md text-sm text-white"
onClick={() => router.push('/my-library')}
data-alt="my-library-button"
>
<Library className="h-4 w-4" />
<span>My Library</span>
</motion.button>
<motion.button
whileHover={{ backgroundColor: 'rgba(255,255,255,0.1)' }}
className="w-full flex items-center space-x-2 px-3 py-2 rounded-md text-sm text-white"
onClick={() => {
// 处理退出登录
setIsOpen(false);
}}
data-alt="logout-button"
>
<LogOut className="h-4 w-4" />
<span>Logout</span>
</motion.button> */}
{/* Footer */}
<div className="mt-4 px-3 py-2 text-xs text-gray-400 text-center">
<div>Privacy Policy · Terms of Service</div>
<div>250819215404 | 2025/8/20 06:00:50</div>
</div>
</div>
</motion.div>, </motion.div>,
document.body document.body
) )
: null} : null}
</div> </div>
</div>):( </div>
<div className="flex items-center space-x-4"> ) : (
<button <div className="flex items-center space-x-4">
data-alt="login-button" <Button
className="w-[8.5rem] h-[3rem] text-base text-gray-300 hover:text-white transition-colors" variant="ghost"
onClick={() => router.push("/login")} size="sm"
> onClick={() => router.push("/login")}
Login className="text-gray-300 hover:text-white"
</button> data-alt="login-button"
<button >
data-alt="signup-button" Login
className="w-[8.5rem] h-[3rem] text-base bg-gray-200 text-gray-800 rounded-full hover:bg-white transition-colors" </Button>
onClick={() => router.push("/signup")} <Button
> variant="ghost"
Sign Up size="sm"
</button> onClick={() => router.push("/signup")}
</div> className="bg-gray-200 text-gray-800 rounded-full hover:bg-white"
) data-alt="signup-button"
} >
Sign Up
</Button>
</div>
)}
</div> </div>
</div> </div>
); );

View File

@ -622,7 +622,7 @@ function HomeModule5() {
> >
<div <div
data-alt="core-value-content" data-alt="core-value-content"
className="center z-10 flex flex-col items-center mb-[8rem]" className="center z-10 flex flex-col items-center mb-[4rem]"
> >
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[1.5rem]"> <h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[1.5rem]">
Pick a plan and make it yours Pick a plan and make it yours