From d69b8ccca87117be9619a1217f53489e49963226 Mon Sep 17 00:00:00 2001 From: gedy182 Date: Thu, 15 Oct 2026 13:11:05 +0800 Subject: [PATCH] feat: add checkoutButton title to PaymentSheetConfiguration The native SDKs already support a custom checkout button title (iOS AWXUIContext.Configuration.checkoutButton.title, Android PaymentElementConfiguration.CheckoutButton), but the React Native wrapper only passed `layout`. presentEntirePaymentFlow now accepts `checkoutButton: { title }` and forwards it on both platforms. Co-Authored-By: Claude Opus 5.5 --- README.md | 9 ++++++++- .../util/PaymentSheetConfigurationConverter.kt | 5 ++++- example/src/App.tsx | 17 +++++++++++++++++ ios/AWXUIContextConfiguration+Extensions.swift | 4 ++++ src/__tests__/index.test.tsx | 12 ++++++++++++ src/types/PaymentSheetConfiguration.ts | 13 +++++++++++++ 6 files changed, 58 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1eccbb3..7ff7a6c 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,14 @@ presentEntirePaymentFlow(session) | `payWithCardDetails(session, card, saveCard)` | Your own card UI (PCI-DSS required) | | `payWithConsent(session, consent)` | Charge a previously saved payment consent | -Session `type` can be `'OneOff'`, `'Recurring'` (save a method without charging), or `'RecurringWithIntent'` (charge now and save). Optionally pass `{ layout: 'tab' | 'accordion' }` as the second argument to `presentEntirePaymentFlow`. +Session `type` can be `'OneOff'`, `'Recurring'` (save a method without charging), or `'RecurringWithIntent'` (charge now and save). Optionally pass a configuration as the second argument to `presentEntirePaymentFlow`: + +```ts +presentEntirePaymentFlow(session, { + layout: 'tab', // or 'accordion' + checkoutButton: { title: 'Pay HKD 50.00' }, // optional, defaults to "Pay" / "Confirm" +}); +``` A runnable integration lives in [`example/`](./example). diff --git a/android/src/main/java/com/airwallexpaymentreactnative/util/PaymentSheetConfigurationConverter.kt b/android/src/main/java/com/airwallexpaymentreactnative/util/PaymentSheetConfigurationConverter.kt index b89e628..aa62c7a 100644 --- a/android/src/main/java/com/airwallexpaymentreactnative/util/PaymentSheetConfigurationConverter.kt +++ b/android/src/main/java/com/airwallexpaymentreactnative/util/PaymentSheetConfigurationConverter.kt @@ -10,6 +10,9 @@ object PaymentSheetConfigurationConverter { "accordion" -> PaymentMethodsLayoutType.ACCORDION else -> PaymentMethodsLayoutType.TAB } - return PaymentElementConfiguration.PaymentSheet(layout = layout) + val checkoutButtonTitle = map?.getMapOrNull("checkoutButton")?.getStringOrNull("title") + val checkoutButton = checkoutButtonTitle?.let { PaymentElementConfiguration.CheckoutButton(it) } + ?: PaymentElementConfiguration.CheckoutButton() + return PaymentElementConfiguration.PaymentSheet(layout = layout, checkoutButton = checkoutButton) } } diff --git a/example/src/App.tsx b/example/src/App.tsx index df2f221..a8705a7 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -335,6 +335,23 @@ function Main() { PresentEntirePaymentFlow (accordion) + { + handlePaymentFlowPress((session) => + presentEntirePaymentFlow(session, { + layout: 'tab', + checkoutButton: { + title: `Pay ${session.currency} ${session.amount.toFixed(2)}`, + }, + }) + ); + }} + > + + PresentEntirePaymentFlow (custom button) + + { diff --git a/ios/AWXUIContextConfiguration+Extensions.swift b/ios/AWXUIContextConfiguration+Extensions.swift index a7bb345..15e9a4e 100644 --- a/ios/AWXUIContextConfiguration+Extensions.swift +++ b/ios/AWXUIContextConfiguration+Extensions.swift @@ -13,5 +13,9 @@ extension AWXUIContext.Configuration { } else { layout = .tab } + if let checkoutButton = params?["checkoutButton"] as? NSDictionary, + let title = checkoutButton["title"] as? String { + self.checkoutButton.title = title + } } } diff --git a/src/__tests__/index.test.tsx b/src/__tests__/index.test.tsx index ebf24e4..85fe822 100644 --- a/src/__tests__/index.test.tsx +++ b/src/__tests__/index.test.tsx @@ -1,4 +1,5 @@ import type { OneOffSession } from '../types/PaymentSession'; +import type { PaymentSheetConfiguration } from '../types/PaymentSheetConfiguration'; describe('PaymentSession', () => { it('includes lang when provided', () => { @@ -15,3 +16,14 @@ describe('PaymentSession', () => { expect(session.lang).toBe('zh-Hans'); }); }); + +describe('PaymentSheetConfiguration', () => { + it('accepts a custom checkout button title', () => { + const configuration: PaymentSheetConfiguration = { + layout: 'tab', + checkoutButton: { title: 'Pay HKD 50.00' }, + }; + + expect(configuration.checkoutButton?.title).toBe('Pay HKD 50.00'); + }); +}); diff --git a/src/types/PaymentSheetConfiguration.ts b/src/types/PaymentSheetConfiguration.ts index 85ccfe2..97994ba 100644 --- a/src/types/PaymentSheetConfiguration.ts +++ b/src/types/PaymentSheetConfiguration.ts @@ -11,4 +11,17 @@ export type PaymentLayout = 'tab' | 'accordion'; */ export interface PaymentSheetConfiguration { layout: PaymentLayout; + /** Customizes the checkout button at the bottom of the payment sheet. */ + checkoutButton?: CheckoutButtonConfiguration; +} + +/** + * Checkout button options for the payment sheet. + */ +export interface CheckoutButtonConfiguration { + /** + * Custom button title, e.g. `'Pay HKD 50.00'`. When omitted, the SDK uses its default: + * "Pay" for one-off payments and "Confirm" for recurring ones. + */ + title?: string; }