2025-08-28 18:40:17 +08:00

225 lines
7.7 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"use client";
import { useState, useEffect, useMemo } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import { Check, ArrowLeft } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { fetchSubscriptionPlans, SubscriptionPlan } from "@/lib/stripe";
export default function PricingPage() {
return (
<div className="w-full h-full overflow-y-auto bg-black text-white pb-[10rem]">
{/* Main Content */}
<HomeModule5 />
</div>
);
}
/**价格方案 */
function HomeModule5() {
const [billingType, setBillingType] = useState<"month" | "year">("month");
const [plans, setPlans] = useState<SubscriptionPlan[]>([]);
// 从后端获取订阅计划数据
useEffect(() => {
const loadPlans = async () => {
try {
const plansData = await fetchSubscriptionPlans();
setPlans(plansData);
} catch (err) {
console.error("加载订阅计划失败:", err);
}
};
loadPlans();
}, []);
const pricingPlans = useMemo<
{
title: string;
price: number;
credits: string;
buttonText: string;
features: string[];
}[]
>(() => {
return plans.map((plan) => {
return {
title: plan.display_name || plan.name,
price:
billingType === "month"
? plan.price_month / 100
: plan.price_year / 100,
credits: plan.description,
buttonText: plan.is_free ? "Try For Free" : "Subscribe Now",
features: plan.features || [],
};
});
}, [plans, billingType]);
const handleSubscribe = async (planName: string) => {
if (planName === "hobby") {
return;
}
try {
// 使用新的Checkout Session方案更简单
const { createCheckoutSession, redirectToCheckout } = await import(
"@/lib/stripe"
);
// 从localStorage获取当前用户信息
const User = JSON.parse(localStorage.getItem("currentUser") || "{}");
if (!User.id) {
throw new Error("无法获取用户ID请重新登录");
}
// 1. 创建Checkout Session
const result = await createCheckoutSession({
user_id: String(User.id),
plan_name: planName,
billing_cycle: billingType,
});
if (!result.successful || !result.data) {
throw new Error("create checkout session failed");
}
window.opener?.postMessage({ type: "waiting-payment" }, "*");
// 2. 直接跳转到Stripe托管页面就这么简单
window.location.href = result.data.checkout_url;
} catch (error) {
throw new Error("create checkout session failed, please try again later");
}
};
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"
>
<div
data-alt="core-value-content"
className="center z-10 flex flex-col items-center mb-[8rem]"
>
<h2 className="text-white text-[3.375rem] leading-[100%] font-normal mb-[1.5rem]">
Start Creating
</h2>
{/* 计费切换 */}
<div className="h-[3.375rem] flex bg-black rounded-full p-[0.0625rem] mt-[1.5rem] border border-white/20">
<button
onClick={() => setBillingType("month")}
className={`box-border flex justify-center items-center w-[6rem] text-base rounded-full transition-all duration-300 ${
billingType === "month"
? "bg-white text-black"
: "text-white hover:text-gray-300"
}`}
>
Monthly
</button>
<button
onClick={() => setBillingType("year")}
className={`box-border flex justify-center items-center w-[7.125rem] text-base rounded-full transition-all duration-300 ${
billingType === "year"
? "bg-white text-black"
: "text-white hover:text-gray-300"
}`}
>
Yearly - <span className="text-[#FFCC6D]">10%</span>
</button>
</div>
</div>
{/* 主要价格卡片 */}
<div className="flex justify-between w-[90%] px-[12rem] mb-[2rem]">
{pricingPlans.map((plan, index) => (
<div
key={index}
className=" w-[26rem] 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}
</h3>
<div className="mb-[1rem]">
<span className="text-white text-[3.375rem] font-bold">
${plan.price}
</span>
<span className="text-white text-xs ml-[0.5rem]">/month</span>
</div>
<p className="text-white text-[0.875rem] mb-[1rem]">
{plan.credits}
</p>
<button
onClick={() => handleSubscribe(plan.title)}
className="w-full bg-white text-black py-[0.75rem] rounded-full mb-[1rem] hover:bg-black hover:text-white transition-colors border border-white/20"
>
{plan.buttonText}
</button>
<p className="w-full text-center text-white/60 text-[0.75rem] mb-[2rem]">
* Billed monthly until cancelled
</p>
<ul className="space-y-[1rem]">
{plan.features.map((feature, featureIndex) => (
<li
key={featureIndex}
className="flex items-center text-white text-[0.875rem]"
>
<span className="text-[#C73BFF] mr-[0.5rem]"></span>
{feature}
</li>
))}
</ul>
</div>
))}
</div>
{/* 额外价格卡片 */}
<div className="flex gap-[1.5rem] w-[90%] px-[12rem]">
<div className="flex-1 bg-black rounded-lg p-[1.5rem] border border-white/20">
<h3 className="text-white text-[1.5rem] font-bold mb-[0.5rem]">
Free
</h3>
<div className="mb-[1rem]">
<span className="text-white text-[2.5rem] font-bold">$0</span>
</div>
<p className="text-white text-[0.875rem] mb-[1.5rem] leading-relaxed">
10 Video mins and 1 AI credit per week, 1 Express avatar, 4 Exports
per week with invideo watermark.
</p>
<p className="text-white text-[0.875rem] mb-[1.5rem] leading-relaxed">
No access to generative features.
</p>
<button className="w-[9rem] bg-[#262626] text-white py-[0.75rem] rounded-full hover:bg-white hover:text-black transition-colors border border-white/20">
Try For Free
</button>
</div>
<div className="flex-1 bg-black rounded-lg p-[1.5rem] border border-white/20">
<h3 className="text-white text-[1.5rem] font-bold mb-[0.5rem]">
Enterprise
</h3>
<p className="text-white text-[2.5rem] mb-[1rem]">Custom</p>
<p className="text-white text-[0.875rem] mb-[1.5rem] leading-relaxed">
Custom solutions for large organizations. Advanced security and
flexible pricing based on your needs.
</p>
<p className="text-white text-[0.875rem] mb-[1.5rem] leading-relaxed">
on your needs.
</p>
<button className="w-[9rem] bg-[#262626] text-white py-[0.75rem] rounded-full hover:bg-white hover:text-black transition-colors border border-white/20">
Contact Us
</button>
</div>
</div>
</div>
);
}