lovart3/components/lovart/pricing-action-button.tsx
Your Name 7432cfc890
Some checks failed
Lint / build (20) (push) Has been cancelled
Playwright Tests / test (push) Has been cancelled
feat: wire lovart pricing checkout and stripe webhook sync
2026-02-12 12:43:27 +08:00

94 lines
2.3 KiB
TypeScript

"use client";
import { Loader2 } from "lucide-react";
import { useRouter } from "next/navigation";
import { useSession } from "next-auth/react";
import { useState } from "react";
import { cn } from "@/lib/utils";
export function PricingActionButton({
planId,
planName,
checkoutEnabled,
highlight,
}: {
planId: string;
planName: string;
checkoutEnabled: boolean;
highlight?: boolean;
}) {
const { data: session, status } = useSession();
const router = useRouter();
const [isPending, setIsPending] = useState(false);
async function handleCheckout() {
if (isPending) {
return;
}
if (status === "loading") {
return;
}
if (!checkoutEnabled) {
window.alert("支付尚未配置,请先在环境变量中配置 Stripe Price ID。");
return;
}
if (!session?.user || session.user.type === "guest") {
router.push("/login?callbackUrl=/lovart/pricing");
return;
}
setIsPending(true);
try {
const response = await fetch("/api/billing/checkout", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ planId }),
});
const data = (await response.json()) as { error?: string; url?: string };
if (!response.ok || !data.url) {
window.alert(data.error || "创建支付会话失败,请稍后再试。");
return;
}
window.location.assign(data.url);
} catch (error) {
console.error("[PricingActionButton] checkout error", error);
window.alert("创建支付会话失败,请稍后再试。");
} finally {
setIsPending(false);
}
}
return (
<button
className={cn(
"mt-6 inline-flex w-full items-center justify-center rounded-xl px-4 py-2 text-sm font-semibold",
highlight
? "bg-white text-zinc-900 hover:bg-zinc-200"
: "border border-white/20 text-zinc-100 hover:border-white/40",
isPending && "cursor-not-allowed opacity-75"
)}
disabled={isPending}
onClick={handleCheckout}
type="button"
>
{isPending ? (
<span className="inline-flex items-center gap-2">
<Loader2 className="h-4 w-4 animate-spin" />
跳转支付中...
</span>
) : (
`订阅 ${planName}`
)}
</button>
);
}