feat(billing): brand checkout + auto-prefill user details
#1 Checkout branding (within Razorpay's hosted-UI limits): - image: /icons/192.png — Tia logo in the checkout header - theme color #fb7185 (Tia rose, matches app theme-color) — was terracotta - Note: Razorpay Checkout is their hosted UI; logo + brand color + name are the only customisable bits. Fonts/layout cannot be changed (platform limit). #2 Auto-prefill name/email/phone: - UpgradeButton now fetches /api/auth/profile on mount and passes prefill {name, email, contact} to Razorpay. User can still edit in checkout. - Saves manual entry; uses the phone we now collect. (#3 "seller doesn't support recurring payments" is a Razorpay ACCOUNT setting, not code — needs subscriptions enabled on the account. Handled separately.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
082956adea
commit
b5f1e5540b
1 changed files with 26 additions and 5 deletions
|
|
@ -8,8 +8,10 @@ interface RazorpayOptions {
|
||||||
subscription_id: string;
|
subscription_id: string;
|
||||||
name: string;
|
name: string;
|
||||||
description: string;
|
description: string;
|
||||||
|
image?: string; // brand logo shown in the checkout header
|
||||||
handler: (resp: RazorpayResponse) => void;
|
handler: (resp: RazorpayResponse) => void;
|
||||||
prefill?: { email?: string; contact?: string };
|
prefill?: { name?: string; email?: string; contact?: string };
|
||||||
|
notes?: Record<string, string>;
|
||||||
theme?: { color?: string };
|
theme?: { color?: string };
|
||||||
modal?: { ondismiss?: () => void };
|
modal?: { ondismiss?: () => void };
|
||||||
}
|
}
|
||||||
|
|
@ -73,9 +75,19 @@ export function UpgradeButton({
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
const [done, setDone] = useState(false);
|
const [done, setDone] = useState(false);
|
||||||
|
// Auto-prefill from the signed-in user's profile (editable in checkout).
|
||||||
|
const [profile, setProfile] = useState<{ name?: string; email?: string; phone?: string }>({});
|
||||||
|
|
||||||
// Warm the checkout script so the first click is instant.
|
// Warm the checkout script + load profile so the first click is instant.
|
||||||
useEffect(() => { loadCheckout(); }, []);
|
useEffect(() => {
|
||||||
|
loadCheckout();
|
||||||
|
fetch("/api/auth/profile", { credentials: "include" })
|
||||||
|
.then((r) => r.json())
|
||||||
|
.then((d) => {
|
||||||
|
if (d.user) setProfile({ name: d.user.name, email: d.user.email, phone: d.user.phone || undefined });
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}, []);
|
||||||
|
|
||||||
const handleUpgrade = async () => {
|
const handleUpgrade = async () => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
@ -91,14 +103,23 @@ export function UpgradeButton({
|
||||||
|
|
||||||
const { subscriptionId, keyId } = createData as { subscriptionId: string; keyId: string };
|
const { subscriptionId, keyId } = createData as { subscriptionId: string; keyId: string };
|
||||||
|
|
||||||
|
// Build prefill from the explicit prop (if any) + the loaded profile.
|
||||||
|
// Razorpay shows these pre-filled but the user can still edit them.
|
||||||
|
const prefill: { name?: string; email?: string; contact?: string } = {};
|
||||||
|
const prefillEmail = email || profile.email;
|
||||||
|
if (profile.name) prefill.name = profile.name;
|
||||||
|
if (prefillEmail) prefill.email = prefillEmail;
|
||||||
|
if (profile.phone) prefill.contact = profile.phone;
|
||||||
|
|
||||||
// 2. Open Razorpay Checkout for the mandate.
|
// 2. Open Razorpay Checkout for the mandate.
|
||||||
const rzp = new window.Razorpay({
|
const rzp = new window.Razorpay({
|
||||||
key: keyId, // id only — never the secret
|
key: keyId, // id only — never the secret
|
||||||
subscription_id: subscriptionId,
|
subscription_id: subscriptionId,
|
||||||
name: "Tia",
|
name: "Tia",
|
||||||
description: "Tia Premium — ₹199/month",
|
description: "Tia Premium — ₹199/month",
|
||||||
prefill: email ? { email } : undefined,
|
image: `${window.location.origin}/icons/192.png`, // brand logo in checkout header
|
||||||
theme: { color: "#C26B4E" }, // heirloom terracotta
|
prefill: Object.keys(prefill).length ? prefill : undefined,
|
||||||
|
theme: { color: "#fb7185" }, // Tia rose (matches app theme-color)
|
||||||
handler: async (resp) => {
|
handler: async (resp) => {
|
||||||
// 3. Verify for UX feedback only — entitlement comes via webhook.
|
// 3. Verify for UX feedback only — entitlement comes via webhook.
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue