Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: expose returnURL parameter for handleNextAction #1104

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

### New features

- Add `returnURL` as an optional parameter to `handleNextAction`. Use this so the Stripe SDK can redirect back to your app after authentication. [#1104](https://github.com/stripe/stripe-react-native/pull/1104)

## Fixes

- Fixed an issue where some promises on Android would never resolve when using React Native 0.65.x or under. [#1089](https://github.com/stripe/stripe-react-native/pull/1089).
Expand Down
2 changes: 2 additions & 0 deletions example/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,7 @@ app.post(
},
use_stripe_sdk: useStripeSdk,
customer: customers.data[0].id,
return_url: 'stripe-example://stripe-redirect',
};
const intent = await stripe.paymentIntents.create(params);
return res.send(generateResponse(intent));
Expand All @@ -308,6 +309,7 @@ app.post(
// If a mobile client passes `useStripeSdk`, set `use_stripe_sdk=true`
// to take advantage of new authentication features in mobile SDKs.
use_stripe_sdk: useStripeSdk,
return_url: 'stripe-example://stripe-redirect',
};
const intent = await stripe.paymentIntents.create(params);
// After create, if the PaymentIntent's status is succeeded, fulfill the order.
Expand Down
3 changes: 2 additions & 1 deletion example/src/screens/NoWebhookPaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ export default function NoWebhookPaymentScreen() {
if (clientSecret && requiresAction) {
// 4. if payment requires action calling handleNextAction
const { error: nextActionError, paymentIntent } = await handleNextAction(
clientSecret
clientSecret,
'stripe-example://stripe-redirect'
);

if (nextActionError) {
Expand Down
1 change: 1 addition & 0 deletions ios/StripeSdk.m
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ @interface RCT_EXTERN_MODULE(StripeSdk, RCTEventEmitter)

RCT_EXTERN_METHOD(
handleNextAction:(NSString *)paymentIntentClientSecret
returnURL:(NSString *)returnURL
resolver: (RCTPromiseResolveBlock)resolve
rejecter: (RCTPromiseRejectBlock)reject
)
Expand Down
5 changes: 3 additions & 2 deletions ios/StripeSdk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -684,14 +684,15 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
}
}

@objc(handleNextAction:resolver:rejecter:)
@objc(handleNextAction:returnURL:resolver:rejecter:)
func handleNextAction(
paymentIntentClientSecret: String,
returnURL: String?,
resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock
){
let paymentHandler = STPPaymentHandler.shared()
paymentHandler.handleNextAction(forPayment: paymentIntentClientSecret, with: self, returnURL: nil) { status, paymentIntent, handleActionError in
paymentHandler.handleNextAction(forPayment: paymentIntentClientSecret, with: self, returnURL: returnURL) { status, paymentIntent, handleActionError in
switch (status) {
case .failed:
resolve(Errors.createError(ErrorType.Failed, handleActionError))
Expand Down
3 changes: 2 additions & 1 deletion src/NativeStripeSdk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ type NativeStripeSdkType = {
options: PaymentMethod.CreateOptions
): Promise<CreatePaymentMethodResult>;
handleNextAction(
paymentIntentClientSecret: string
paymentIntentClientSecret: string,
returnURL?: string | null
): Promise<HandleNextActionResult>;
confirmPayment(
paymentIntentClientSecret: string,
Expand Down
30 changes: 21 additions & 9 deletions src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
CanAddCardToWalletResult,
FinancialConnections,
} from './types';
import { Platform } from 'react-native';

const APPLE_PAY_NOT_SUPPORTED_MESSAGE =
'Apple pay is not supported on this device';
Expand Down Expand Up @@ -142,9 +143,9 @@ export const retrieveSetupIntent = async (
/**
* Confirm and, if necessary, authenticate a PaymentIntent.
*
* @param paymentIntentClientSecret The client_secret of the associated [PaymentIntent](https://stripe.com/docs/api/payment_intents).
* @param params An optional object that contains data related to the payment method used to confirm this payment. If no object is provided (undefined), then it is assumed that the payment method has already been [attached to the Payment Intent](https://stripe.com/docs/api/payment_intents/create#create_payment_intent-payment_method).
* @param options An optional object that contains options for this payment method.
* @param {string} paymentIntentClientSecret The client_secret of the associated [PaymentIntent](https://stripe.com/docs/api/payment_intents).
* @param {object=} params An optional object that contains data related to the payment method used to confirm this payment. If no object is provided (undefined), then it is assumed that the payment method has already been [attached to the Payment Intent](https://stripe.com/docs/api/payment_intents/create#create_payment_intent-payment_method).
* @param {object=} options An optional object that contains options for this payment method.
* @returns A promise that resolves to an object containing either a `paymentIntent` field, or an `error` field.
*/
export const confirmPayment = async (
Expand Down Expand Up @@ -257,13 +258,24 @@ export const confirmApplePayPayment = async (
}
};

/** Handles any nextAction required to authenticate the PaymentIntent.
* Call this method if you are using manual confirmation. See https://stripe.com/docs/payments/accept-a-payment?platform=react-native&ui=custom
*
* @param {string} paymentIntentClientSecret The client secret associated with the PaymentIntent.
* @param {string=} returnURL An optional return URL so the Stripe SDK can redirect back to your app after authentication. This should match the `return_url` you specified during PaymentIntent confirmation.
* */
export const handleNextAction = async (
paymentIntentClientSecret: string
paymentIntentClientSecret: string,
returnURL?: string
): Promise<HandleNextActionResult> => {
try {
const { paymentIntent, error } = await NativeStripeSdk.handleNextAction(
paymentIntentClientSecret
);
const { paymentIntent, error } =
Platform.OS === 'ios'
? await NativeStripeSdk.handleNextAction(
paymentIntentClientSecret,
returnURL ?? null
)
: await NativeStripeSdk.handleNextAction(paymentIntentClientSecret);
if (error) {
return {
error,
Expand Down Expand Up @@ -579,7 +591,7 @@ export const collectBankAccountForSetup = async (
/**
* Use collectBankAccountToken in the [Add a Financial Connections Account to a US Custom Connect](https://stripe.com/docs/financial-connections/connect-payouts) account flow.
* When called, it will load the Authentication Flow, an on-page modal UI which allows your user to securely link their external financial account for payouts.
* @param clientSecret The client_secret of the [Financial Connections Session](https://stripe.com/docs/api/financial_connections/session).
* @param {string} clientSecret The client_secret of the [Financial Connections Session](https://stripe.com/docs/api/financial_connections/session).
* @returns A promise that resolves to an object containing either `session` and `token` fields, or an error field.
*/
export const collectBankAccountToken = async (
Expand Down Expand Up @@ -608,7 +620,7 @@ export const collectBankAccountToken = async (
/**
* Use collectFinancialConnectionsAccounts in the [Collect an account to build data-powered products](https://stripe.com/docs/financial-connections/other-data-powered-products) flow.
* When called, it will load the Authentication Flow, an on-page modal UI which allows your user to securely link their external financial account.
* @param clientSecret The client_secret of the [Financial Connections Session](https://stripe.com/docs/api/financial_connections/session).
* @param {string} clientSecret The client_secret of the [Financial Connections Session](https://stripe.com/docs/api/financial_connections/session).
* @returns A promise that resolves to an object containing either a `session` field, or an error field.
*/
export const collectFinancialConnectionsAccounts = async (
Expand Down
5 changes: 3 additions & 2 deletions src/hooks/useStripe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,10 @@ export function useStripe() {

const _handleNextAction = useCallback(
async (
paymentIntentClientSecret: string
paymentIntentClientSecret: string,
returnURL?: string
): Promise<HandleNextActionResult> => {
return handleNextAction(paymentIntentClientSecret);
return handleNextAction(paymentIntentClientSecret, returnURL);
},
[]
);
Expand Down