ClauseGuard / web /components /checkout-button.tsx
gaurv007's picture
Replace Stripe with Razorpay: subscriptions, webhooks, checkout modal, INR pricing
fbf3514 verified
raw
history blame
3.07 kB
"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>
);
}