Spaces:
Sleeping
Sleeping
| "use client"; | |
| import { useState } from "react"; | |
| import { CreditCard, Loader2 } from "lucide-react"; | |
| // Razorpay checkout script loader | |
| function loadRazorpayScript(): Promise<boolean> { | |
| return new Promise((resolve) => { | |
| if (typeof window !== "undefined" && (window as any).Razorpay) { | |
| resolve(true); | |
| return; | |
| } | |
| const script = document.createElement("script"); | |
| script.src = "https://checkout.razorpay.com/v1/checkout.js"; | |
| script.onload = () => resolve(true); | |
| script.onerror = () => resolve(false); | |
| document.body.appendChild(script); | |
| }); | |
| } | |
| interface Props { | |
| plan: "pro" | "team"; | |
| label?: string; | |
| className?: string; | |
| userName?: string; | |
| userEmail?: string; | |
| } | |
| export function CheckoutButton({ plan, label, className, userName, userEmail }: Props) { | |
| const [loading, setLoading] = useState(false); | |
| async function handleCheckout() { | |
| setLoading(true); | |
| try { | |
| // Load Razorpay script | |
| const loaded = await loadRazorpayScript(); | |
| if (!loaded) throw new Error("Failed to load Razorpay"); | |
| // Create subscription server-side | |
| const res = await fetch("/api/subscribe/create", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify({ plan }), | |
| }); | |
| if (!res.ok) { | |
| const err = await res.json(); | |
| throw new Error(err.error || "Subscription failed"); | |
| } | |
| const { subscription_id } = await res.json(); | |
| // Open Razorpay checkout | |
| const rzp = new (window as any).Razorpay({ | |
| key: process.env.NEXT_PUBLIC_RAZORPAY_KEY_ID, | |
| subscription_id, | |
| name: "ClauseGuard", | |
| description: plan === "pro" ? "Pro — ₹999/mo" : "Team — ₹3,999/mo", | |
| handler: async (response: any) => { | |
| // Verify payment server-side | |
| const verifyRes = await fetch("/api/subscribe/verify", { | |
| method: "POST", | |
| headers: { "Content-Type": "application/json" }, | |
| body: JSON.stringify(response), | |
| }); | |
| if (verifyRes.ok) { | |
| window.location.href = "/dashboard-pages/dashboard?subscribed=true"; | |
| } | |
| }, | |
| prefill: { | |
| name: userName || "", | |
| email: userEmail || "", | |
| }, | |
| theme: { color: "#18181b" }, | |
| modal: { | |
| ondismiss: () => setLoading(false), | |
| }, | |
| }); | |
| rzp.on("payment.failed", () => setLoading(false)); | |
| rzp.open(); | |
| } catch (error) { | |
| console.error("Checkout error:", error); | |
| setLoading(false); | |
| } | |
| } | |
| return ( | |
| <button | |
| onClick={handleCheckout} | |
| disabled={loading} | |
| className={className || "w-full flex items-center justify-center gap-2 bg-zinc-900 text-white py-2.5 rounded-lg text-sm font-medium hover:bg-zinc-800 disabled:opacity-40 transition-colors"} | |
| > | |
| {loading ? ( | |
| <><Loader2 className="w-4 h-4 animate-spin" /> Processing...</> | |
| ) : ( | |
| <><CreditCard className="w-4 h-4" /> {label || `Subscribe to ${plan}`}</> | |
| )} | |
| </button> | |
| ); | |
| } | |