forked from 77media/video-flow
修复很多问题
This commit is contained in:
parent
5b268abe5e
commit
a259d66f7c
@ -26,7 +26,6 @@ export default function RootLayout({
|
||||
}) {
|
||||
const [showCallbackModal, setShowCallbackModal] = useState(false)
|
||||
const openCallback = async function (ev: MessageEvent<any>) {
|
||||
console.log(ev)
|
||||
if (ev.data.type === 'waiting-payment') {
|
||||
setShowCallbackModal(true)
|
||||
}
|
||||
|
||||
@ -15,8 +15,39 @@ import { fetchSubscriptionPlans, SubscriptionPlan } from "@/lib/stripe";
|
||||
|
||||
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 (
|
||||
<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 */}
|
||||
<HomeModule5 />
|
||||
</div>
|
||||
@ -66,7 +97,7 @@ function HomeModule5() {
|
||||
}, [plans, billingType]);
|
||||
|
||||
const handleSubscribe = async (planName: string) => {
|
||||
if (planName === "hobby") {
|
||||
if (planName === "Kickoff") {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -103,14 +134,14 @@ function HomeModule5() {
|
||||
return (
|
||||
<div
|
||||
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
|
||||
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]">
|
||||
Start Creating
|
||||
Pick a plan and make it yours
|
||||
</h2>
|
||||
|
||||
{/* 计费切换 */}
|
||||
@ -133,7 +164,7 @@ function HomeModule5() {
|
||||
: "text-white hover:text-gray-300"
|
||||
}`}
|
||||
>
|
||||
Yearly - <span className="text-[#FFCC6D]">10%</span>
|
||||
Yearly - <span className="text-[#FFCC6D]">20%</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@ -143,7 +174,7 @@ function HomeModule5() {
|
||||
{pricingPlans.map((plan, index) => (
|
||||
<div
|
||||
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]">
|
||||
{plan.title}
|
||||
|
||||
@ -714,7 +714,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
|
||||
{!isExpanded && (
|
||||
<div className="absolute top-2 right-2 z-10 flex items-center">
|
||||
{/* 使用 Dropdown 替代手动控制显示/隐藏 */}
|
||||
<Dropdown
|
||||
{/* <Dropdown
|
||||
open={showConfigOptions}
|
||||
onOpenChange={setShowConfigOptions}
|
||||
popupRender={() => (
|
||||
@ -730,7 +730,6 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
|
||||
placement={"left" as any}
|
||||
trigger={["click"]}
|
||||
>
|
||||
{/* 配置项显示控制按钮 - 齿轮图标 */}
|
||||
<Tooltip title="config" placement="top">
|
||||
<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" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</Dropdown>
|
||||
</Dropdown> */}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -771,7 +770,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
|
||||
<div className="flex items-center justify-between">
|
||||
{/* 左侧功能按钮区域 */}
|
||||
<div className="flex items-center gap-2">
|
||||
{/* 获取创意按钮 */}
|
||||
{/* 获取创意按钮
|
||||
<Tooltip
|
||||
title="Get creative ideas for your story"
|
||||
placement="top"
|
||||
@ -787,10 +786,10 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
|
||||
<Lightbulb className="w-4 h-4" />
|
||||
)}
|
||||
</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">
|
||||
@ -830,6 +829,7 @@ export function ChatInputBox({ noData }: { noData: boolean }) {
|
||||
isCreating={isCreating}
|
||||
handleCreateVideo={handleCreateVideo}
|
||||
icon={<Clapperboard className="w-5 h-5" />}
|
||||
className="mr-1 mb-1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -12,14 +12,17 @@ import {
|
||||
LogOut,
|
||||
PanelsLeftBottom,
|
||||
Bell,
|
||||
} from 'lucide-react';
|
||||
import { motion } from 'framer-motion';
|
||||
import ReactDOM 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 } from '@/lib/stripe';
|
||||
|
||||
} from "lucide-react";
|
||||
import { motion } from "framer-motion";
|
||||
import ReactDOM 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,
|
||||
} from "@/lib/stripe";
|
||||
|
||||
interface User {
|
||||
id: string;
|
||||
@ -27,6 +30,7 @@ interface User {
|
||||
email: string;
|
||||
avatar: string;
|
||||
username: string;
|
||||
plan_name?: string;
|
||||
}
|
||||
|
||||
export function TopBar({
|
||||
@ -40,14 +44,14 @@ export function TopBar({
|
||||
const [isOpen, setIsOpen] = React.useState(false);
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
const buttonRef = useRef<HTMLButtonElement>(null);
|
||||
const currentUser: User = JSON.parse(
|
||||
localStorage.getItem("currentUser") || "{}"
|
||||
const [currentUser, setCurrentUser] = useState<User>(
|
||||
JSON.parse(localStorage.getItem("currentUser") || "{}")
|
||||
);
|
||||
const pathname = usePathname()
|
||||
const pathname = usePathname();
|
||||
const [mounted, setMounted] = React.useState(false);
|
||||
const [isLogin, setIsLogin] = useState(false);
|
||||
const [isManagingSubscription, setIsManagingSubscription] = useState(false);
|
||||
const [subscriptionStatus, setSubscriptionStatus] = useState<string>('');
|
||||
const [subscriptionStatus, setSubscriptionStatus] = useState<string>("");
|
||||
const [credits, setCredits] = useState<number>(100);
|
||||
const [isLoadingSubscription, setIsLoadingSubscription] = useState(false);
|
||||
|
||||
@ -59,11 +63,18 @@ export function TopBar({
|
||||
try {
|
||||
const response = await getUserSubscriptionInfo(String(currentUser.id));
|
||||
if (response.successful && response.data) {
|
||||
setSubscriptionStatus(response.data.subscription_status);
|
||||
const status = response.data.subscription_status;
|
||||
setSubscriptionStatus(status);
|
||||
setCredits(response.data.credits);
|
||||
|
||||
// 更新 currentUser 的 plan_name
|
||||
setCurrentUser((prev) => ({
|
||||
...prev,
|
||||
plan_name: response.data.plan_name,
|
||||
}));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('获取订阅信息失败:', error);
|
||||
console.error("获取订阅信息失败:", error);
|
||||
} finally {
|
||||
setIsLoadingSubscription(false);
|
||||
}
|
||||
@ -86,7 +97,7 @@ export function TopBar({
|
||||
// 处理订阅管理
|
||||
const handleManageSubscription = async () => {
|
||||
if (!currentUser?.id) {
|
||||
console.error('用户未登录');
|
||||
console.error("用户未登录");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -94,7 +105,7 @@ export function TopBar({
|
||||
try {
|
||||
const response = await createPortalSession({
|
||||
user_id: String(currentUser.id),
|
||||
return_url: window.location.origin + '/dashboard'
|
||||
return_url: window.location.origin + "/dashboard",
|
||||
});
|
||||
|
||||
if (response.successful && response.data?.portal_url) {
|
||||
@ -199,20 +210,31 @@ export function TopBar({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
isLogin ?(<div className="flex items-center space-x-4">
|
||||
{isLogin ? (
|
||||
<div className="flex items-center space-x-4">
|
||||
{/* Pricing Link */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => {
|
||||
localStorage.setItem("callBackUrl", pathname);
|
||||
window.open("/pricing", "_blank");
|
||||
}}
|
||||
className="text-gray-300 hover:text-white"
|
||||
>
|
||||
Pricing
|
||||
</Button>
|
||||
{pathname === "/" ? (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => router.push("/create")}
|
||||
className="bg-white text-black rounded-full hover:bg-gray-100"
|
||||
>
|
||||
Go Start
|
||||
</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 */}
|
||||
{/* <Button variant="ghost" size="sm" onClick={() => showQueueNotification(3, 10)}>
|
||||
@ -274,9 +296,27 @@ export function TopBar({
|
||||
MF
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<p className="text-sm font-medium">
|
||||
{currentUser.name || currentUser.username}
|
||||
</p>
|
||||
<div className="flex items-center gap-2">
|
||||
<p className="text-sm font-medium">
|
||||
{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">
|
||||
{currentUser.email}
|
||||
</p>
|
||||
@ -298,7 +338,9 @@ export function TopBar({
|
||||
<div className="flex items-center space-x-2">
|
||||
<Sparkles className="h-4 w-4" />
|
||||
<span className="text-white underline text-sm">
|
||||
{isLoadingSubscription ? '...' : `${credits} credits`}
|
||||
{isLoadingSubscription
|
||||
? "..."
|
||||
: `${credits} credits`}
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
@ -311,7 +353,7 @@ export function TopBar({
|
||||
>
|
||||
Upgrade
|
||||
</Button>
|
||||
{subscriptionStatus === 'ACTIVE' && (
|
||||
{subscriptionStatus === "ACTIVE" && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@ -323,62 +365,34 @@ export function TopBar({
|
||||
</Button>
|
||||
)}
|
||||
</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>,
|
||||
document.body
|
||||
)
|
||||
: null}
|
||||
</div>
|
||||
</div>):(
|
||||
<div className="flex items-center space-x-4">
|
||||
<button
|
||||
data-alt="login-button"
|
||||
className="w-[8.5rem] h-[3rem] text-base text-gray-300 hover:text-white transition-colors"
|
||||
onClick={() => router.push("/login")}
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
<button
|
||||
data-alt="signup-button"
|
||||
className="w-[8.5rem] h-[3rem] text-base bg-gray-200 text-gray-800 rounded-full hover:bg-white transition-colors"
|
||||
onClick={() => router.push("/signup")}
|
||||
>
|
||||
Sign Up
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center space-x-4">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => router.push("/login")}
|
||||
className="text-gray-300 hover:text-white"
|
||||
data-alt="login-button"
|
||||
>
|
||||
Login
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => router.push("/signup")}
|
||||
className="bg-gray-200 text-gray-800 rounded-full hover:bg-white"
|
||||
data-alt="signup-button"
|
||||
>
|
||||
Sign Up
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -622,7 +622,7 @@ function HomeModule5() {
|
||||
>
|
||||
<div
|
||||
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]">
|
||||
Pick a plan and make it yours
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user