From f9e104ee2152249300d9be5ebd2127ac45260db7 Mon Sep 17 00:00:00 2001 From: v0l Date: Tue, 14 Jul 2026 18:39:55 +0100 Subject: [PATCH] feat: save Revolut card for off-session automatic renewals When a subscription has auto_renewal_enabled, pass savePaymentMethodFor=merchant to the Revolut card widget so the card is saved for merchant-initiated (off-session) automatic renewals. The subscription payment flow loads the subscription to determine whether to save the card. Companion to LNVPS/api #160. --- src/components/revolut.tsx | 7 +++++++ src/components/subscription-payment-flow.tsx | 12 ++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/components/revolut.tsx b/src/components/revolut.tsx index 319a4da..dcbbf40 100644 --- a/src/components/revolut.tsx +++ b/src/components/revolut.tsx @@ -16,6 +16,8 @@ interface RevolutProps { onPaid: () => void; onCancel?: () => void; mode?: Mode; + /** Save the card for merchant-initiated (off-session) automatic renewals */ + saveCard?: boolean; } export function RevolutPayWidget({ @@ -24,6 +26,7 @@ export function RevolutPayWidget({ onPaid, onCancel, mode, + saveCard, }: RevolutProps) { const login = useLogin(); const { formatMessage } = useIntl(); @@ -163,6 +166,10 @@ export function RevolutPayWidget({ streetLine1: streetLine1 || undefined, streetLine2: streetLine2 || undefined, }, + // Save the payment method for merchant-initiated (off-session) automatic + // renewals. The backend then captures the saved customer/payment-method + // ids on webhook completion. + ...(saveCard ? { savePaymentMethodFor: "merchant" as const } : {}), }); } diff --git a/src/components/subscription-payment-flow.tsx b/src/components/subscription-payment-flow.tsx index 0910c7c..864932d 100644 --- a/src/components/subscription-payment-flow.tsx +++ b/src/components/subscription-payment-flow.tsx @@ -52,6 +52,7 @@ export default function SubscriptionPaymentFlow({ const [loading, setLoading] = useState(false); const [error, setError] = useState(); const [account, setAccount] = useState(); + const [autoRenewalEnabled, setAutoRenewalEnabled] = useState(false); useEffect(() => { if (!login?.api) return; @@ -61,6 +62,16 @@ export default function SubscriptionPaymentFlow({ .catch((e) => console.error("Failed to load account info:", e)); }, [login?.api]); + // Load the subscription so we know whether to save the card for off-session + // automatic renewals during a Revolut checkout. + useEffect(() => { + if (!login?.api) return; + login.api + .getSubscription(subscriptionId) + .then((s) => setAutoRenewalEnabled(s.auto_renewal_enabled)) + .catch((e) => console.error("Failed to load subscription:", e)); + }, [login?.api, subscriptionId]); + const handlePaymentComplete = useCallback(() => { setPayment(undefined); onPaymentComplete(); @@ -225,6 +236,7 @@ export default function SubscriptionPaymentFlow({ payment={toVmPayment(payment)} account={account} onPaid={handlePaymentComplete} + saveCard={autoRenewalEnabled} /> ) : (