import { api } from "./api"; declare global { interface Window { Razorpay?: any } } function loadScript(): Promise { return new Promise((resolve) => { if (window.Razorpay) return resolve(true); const s = document.createElement("script"); s.src = "https://checkout.razorpay.com/v1/checkout.js"; s.onload = () => resolve(true); s.onerror = () => resolve(false); document.body.appendChild(s); }); } /** * Start a plan upgrade/downgrade. Creates an order, opens Razorpay checkout * (or auto-confirms in mock mode), then verifies and activates the plan. * Returns true on success. */ export async function purchasePlan( planId: string, coupon?: string, onSuccess?: (invoiceNumber?: string) => void ): Promise { const order = await api("/billing/create-order", { method: "POST", body: JSON.stringify({ plan_id: planId, coupon: coupon || undefined }), }); // Free / fully-discounted plan — activated server-side already. if (order.free) { onSuccess?.(); return; } // Mock mode (no Razorpay keys): skip the modal, verify directly. if (order.mock) { const res = await api("/billing/verify", { method: "POST", body: JSON.stringify({ razorpay_order_id: order.order_id, razorpay_payment_id: `pay_mock_${Date.now()}`, razorpay_signature: "mock", plan_id: order.plan_id, }), }); onSuccess?.(res.invoice_number); return; } // Live mode — open Razorpay checkout. const ok = await loadScript(); if (!ok) throw new Error("Failed to load Razorpay checkout"); await new Promise((resolve, reject) => { const rzp = new window.Razorpay({ key: order.key_id, amount: order.amount * 100, currency: order.currency, name: "VerifyPack", description: `${order.plan_name} plan`, order_id: order.order_id, handler: async (resp: any) => { try { const res = await api("/billing/verify", { method: "POST", body: JSON.stringify({ razorpay_order_id: resp.razorpay_order_id, razorpay_payment_id: resp.razorpay_payment_id, razorpay_signature: resp.razorpay_signature, plan_id: order.plan_id, }), }); onSuccess?.(res.invoice_number); resolve(); } catch (e) { reject(e); } }, modal: { ondismiss: () => reject(new Error("Payment cancelled")) }, theme: { color: "#2563eb" }, }); rzp.open(); }); }