Skip to content

Commit

Permalink
feat: Add support for Link (#1176)
Browse files Browse the repository at this point in the history
  • Loading branch information
charliecruzan-stripe authored Nov 1, 2022
1 parent 26322f6 commit f4d9ab0
Show file tree
Hide file tree
Showing 20 changed files with 93 additions and 13 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@

### New features

- Added [Link](https://stripe.com/docs/payments/link) support in Payment Sheet. [#1176](https://github.com/stripe/stripe-react-native/pull/1176)
- Added the `resetPaymentSheetCustomer` method to clear persisted authentication state in the PaymentSheet. [#1176](https://github.com/stripe/stripe-react-native/pull/1176)
- Added `preferredNetwork` and `availableNetworks` fields to the `CardResult` payment method. [#1176](https://github.com/stripe/stripe-react-native/pull/1176)
- Added support for custom fonts to `CardForm` and `CardView` on Android. [#1150](https://github.com/stripe/stripe-react-native/pull/1150)

## Fixes

- Fixed an issue on iOS where `confirmSetupIntent` would throw an error if the `Card` payment method was provided with the `paymentMethodId` parameter. [#1151](https://github.com/stripe/stripe-react-native/pull/1151)
- Upgraded `stripe-android` to 20.15.+. [#1176](https://github.com/stripe/stripe-react-native/pull/1176)
- Fixed `FinancialConnections.Subcategory` and `FinancialConnections.Permission` types to be camel-case instead of snake case. [#1176](https://github.com/stripe/stripe-react-native/pull/1176)
- Fixed an issue with Financial Connections on iOS where the app wouldn't properly redirect back after authentication. [#1178](https://github.com/stripe/stripe-react-native/pull/1178)
- Fixed `borderWidth` and `borderRadius` for `<CardField />` and `CardForm />` was inconsistent across iOS and Android. [#1182](https://github.com/stripe/stripe-react-native/pull/1182)

Expand Down
2 changes: 1 addition & 1 deletion android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
StripeSdk_kotlinVersion=1.6.21
StripeSdk_stripeVersion=20.12.+
StripeSdk_stripeVersion=20.15.+
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ class FinancialConnectionsSheetFragment : Fragment() {
FinancialConnectionsAccount.Permissions.BALANCES -> "balances"
FinancialConnectionsAccount.Permissions.OWNERSHIP -> "ownership"
FinancialConnectionsAccount.Permissions.TRANSACTIONS -> "transactions"
FinancialConnectionsAccount.Permissions.ACCOUNT_NUMBERS -> "accountNumbers"
FinancialConnectionsAccount.Permissions.UNKNOWN -> "unparsable"
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ class PaymentLauncherFragment(
StripeIntent.NextActionType.AlipayRedirect,
StripeIntent.NextActionType.BlikAuthorize,
StripeIntent.NextActionType.WeChatPayRedirect,
StripeIntent.NextActionType.UpiAwaitNotification,
null -> false
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import com.stripe.android.core.ApiVersion
import com.stripe.android.core.AppInfo
import com.stripe.android.model.*
import com.stripe.android.payments.bankaccount.CollectBankAccountConfiguration
import com.stripe.android.paymentsheet.PaymentSheet
import com.stripe.android.view.AddPaymentMethodActivityStarter
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -160,6 +161,12 @@ class StripeSdkModule(reactContext: ReactApplicationContext) : ReactContextBaseJ
paymentSheetFragment?.confirmPayment(promise)
}

@ReactMethod
fun resetPaymentSheetCustomer(promise: Promise) {
PaymentSheet.resetCustomer(context = reactApplicationContext)
promise.resolve(null)
}

private fun payWithFpx() {
getCurrentActivityOrResolveWithError(confirmPromise)?.let {
AddPaymentMethodActivityStarter(it)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,8 @@ internal fun mapFromPaymentMethod(paymentMethod: PaymentMethod): WritableMap {
card.putString("funding", paymentMethod.card?.funding)
card.putString("last4", paymentMethod.card?.last4)
card.putString("fingerprint", paymentMethod.card?.fingerprint)
card.putString("preferredNetwork", paymentMethod.card?.networks?.preferred)
card.putArray("availableNetworks", paymentMethod.card?.networks?.available?.toList() as? ReadableArray)

sepaDebit.putString("bankCode", paymentMethod.sepaDebit?.bankCode)
sepaDebit.putString("country", paymentMethod.sepaDebit?.country)
Expand Down
10 changes: 5 additions & 5 deletions example/ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,12 @@ PODS:
- StripeUICore (= 22.8.4)
- stripe-react-native (0.19.0):
- React-Core
- Stripe (~> 22.8.3)
- StripeFinancialConnections (~> 22.8.3)
- Stripe (~> 22.8.4)
- StripeFinancialConnections (~> 22.8.4)
- stripe-react-native/Tests (0.19.0):
- React-Core
- Stripe (~> 22.8.3)
- StripeFinancialConnections (~> 22.8.3)
- Stripe (~> 22.8.4)
- StripeFinancialConnections (~> 22.8.4)
- Stripe/Stripe3DS2 (22.8.4):
- StripeApplePay (= 22.8.4)
- StripeCore (= 22.8.4)
Expand Down Expand Up @@ -615,7 +615,7 @@ SPEC CHECKSUMS:
RNScreens: 4a1af06327774490d97342c00aee0c2bafb497b7
SocketRocket: fccef3f9c5cedea1353a9ef6ada904fde10d6608
Stripe: 59f6659e8ea413def19c97c57e23f5ec6ea48cf8
stripe-react-native: 7135ed308ee04234d665da5e79e4d2737e549be3
stripe-react-native: 48ad0866973ed214c3a4424de85b00ed006cf116
StripeApplePay: 6e9aebd3d248464836e9fbdaef6e5fb1817d56a6
StripeCore: 193f27552fb98108ebfe0df11651fe5f38948305
StripeFinancialConnections: 955c345ada7d0dff1a9bd15c4ebc97eacce4ac75
Expand Down
1 change: 1 addition & 0 deletions example/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,7 @@ app.post('/payment-sheet', async (_, res) => {
// Note: some payment methods have different requirements: https://stripe.com/docs/payments/payment-methods/integration-options
payment_method_types: [
'card',
'link',
// 'ideal',
// 'sepa_debit',
// 'sofort',
Expand Down
11 changes: 10 additions & 1 deletion example/src/screens/PaymentsUICompleteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import { API_URL } from '../Config';
import appearance from './PaymentSheetAppearance';

export default function PaymentsUICompleteScreen() {
const { initPaymentSheet, presentPaymentSheet } = useStripe();
const { initPaymentSheet, presentPaymentSheet, resetPaymentSheetCustomer } =
useStripe();
const [paymentSheetEnabled, setPaymentSheetEnabled] = useState(false);
const [loading, setLoading] = useState(false);
const [clientSecret, setClientSecret] = useState<string>();
Expand Down Expand Up @@ -119,6 +120,14 @@ export default function PaymentsUICompleteScreen() {
title="Checkout"
onPress={openPaymentSheet}
/>

<Button
title="Reset customer"
onPress={async () => {
// Link will still be presented for the customer if you pass in the customer ID and ephemeral key to payment sheet
await resetPaymentSheetCustomer();
}}
/>
</PaymentScreen>
);
}
5 changes: 4 additions & 1 deletion ios/Mappers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -594,8 +594,11 @@ class Mappers {
"expMonth": paymentMethod.card?.expMonth ?? NSNull(),
"fingerprint": paymentMethod.card?.fingerprint ?? NSNull(),
"funding": paymentMethod.card?.funding ?? NSNull(),
"last4": paymentMethod.card?.last4 ?? NSNull()
"last4": paymentMethod.card?.last4 ?? NSNull(),
"preferredNetwork": paymentMethod.card?.networks?.preferred ?? NSNull(),
"availableNetworks": paymentMethod.card?.networks?.available ?? NSNull(),
]

let sepaDebit: NSDictionary = [
"bankCode": paymentMethod.sepaDebit?.bankCode ?? NSNull(),
"country": paymentMethod.sepaDebit?.country ?? NSNull(),
Expand Down
5 changes: 5 additions & 0 deletions ios/StripeSdk.m
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ @interface RCT_EXTERN_MODULE(StripeSdk, RCTEventEmitter)
rejecter: (RCTPromiseRejectBlock)reject
)

RCT_EXTERN_METHOD(
resetPaymentSheetCustomer:(RCTPromiseResolveBlock)resolve
rejecter: (RCTPromiseRejectBlock)reject
)

RCT_EXTERN_METHOD(
confirmPayment:(NSString *)paymentIntentClientSecret
data:(NSDictionary *)data
Expand Down
8 changes: 8 additions & 0 deletions ios/StripeSdk.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
self.urlScheme = urlScheme

STPAPIClient.shared.publishableKey = publishableKey
StripeAPI.defaultPublishableKey = publishableKey
STPAPIClient.shared.stripeAccount = stripeAccountId

let name = RCTConvert.nsString(appInfo["name"]) ?? ""
Expand Down Expand Up @@ -218,6 +219,13 @@ class StripeSdk: RCTEventEmitter, STPApplePayContextDelegate, STPBankSelectionVi
}
}
}

@objc(resetPaymentSheetCustomer:rejecter:)
func resetPaymentSheetCustomer(resolver resolve: @escaping RCTPromiseResolveBlock,
rejecter reject: @escaping RCTPromiseRejectBlock) -> Void {
PaymentSheet.resetCustomer()
resolve(nil)
}

@objc(presentPaymentSheet:rejecter:)
func presentPaymentSheet(resolver resolve: @escaping RCTPromiseResolveBlock,
Expand Down
1 change: 1 addition & 0 deletions jest/mock.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const mockFunctions = {
confirmPaymentSheetPayment: jest.fn(async () => ({
error: null,
})),
resetPaymentSheetCustomer: jest.fn(async () => null),
initGooglePay: jest.fn(async () => ({
error: null,
})),
Expand Down
1 change: 1 addition & 0 deletions src/NativeStripeSdk.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ type NativeStripeSdkType = {
collectFinancialConnectionsAccounts(
clientSecret: string
): Promise<FinancialConnections.SessionResult>;
resetPaymentSheetCustomer(): Promise<null>;
};

const { StripeSdk } = NativeModules;
Expand Down
9 changes: 9 additions & 0 deletions src/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,6 +455,15 @@ export const confirmPaymentSheetPayment =
}
};

/**
* You must call this method when the user logs out from your app. This will ensure that
* any persisted authentication state in the PaymentSheet, such as authentication cookies,
* is also cleared during logout.
*/
export const resetPaymentSheetCustomer = async (): Promise<null> => {
return await NativeStripeSdk.resetPaymentSheetCustomer();
};

export const isGooglePaySupported = async (
params?: GooglePay.IsSupportedParams
): Promise<boolean> => {
Expand Down
14 changes: 14 additions & 0 deletions src/hooks/usePaymentSheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export function usePaymentSheet() {
initPaymentSheet: initPaymentSheetNative,
presentPaymentSheet: presentPaymentSheetNative,
confirmPaymentSheetPayment: confirmPaymentSheetPaymentNative,
resetPaymentSheetCustomer: resetPaymentSheetCustomerNative,
} = useStripe();
const [loading, setLoading] = useState(false);

Expand All @@ -34,10 +35,23 @@ export function usePaymentSheet() {
return result;
};

const resetPaymentSheetCustomer = async () => {
setLoading(true);
const result = await resetPaymentSheetCustomerNative();
setLoading(false);
return result;
};

return {
loading,
initPaymentSheet,
presentPaymentSheet,
confirmPaymentSheetPayment,
/**
* You must call this method when the user logs out from your app. This will ensure that
* any persisted authentication state in the PaymentSheet, such as authentication cookies,
* is also cleared during logout.
*/
resetPaymentSheetCustomer,
};
}
11 changes: 11 additions & 0 deletions src/hooks/useStripe.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ import {
canAddCardToWallet,
collectBankAccountToken,
collectFinancialConnectionsAccounts,
resetPaymentSheetCustomer,
} from '../functions';

/**
Expand Down Expand Up @@ -311,6 +312,10 @@ export function useStripe() {
[]
);

const _resetPaymentSheetCustomer = useCallback(async (): Promise<null> => {
return resetPaymentSheetCustomer();
}, []);

return {
retrievePaymentIntent: _retrievePaymentIntent,
retrieveSetupIntent: _retrieveSetupIntent,
Expand Down Expand Up @@ -340,5 +345,11 @@ export function useStripe() {
canAddCardToWallet: _canAddCardToWallet,
collectBankAccountToken: _collectBankAccountToken,
collectFinancialConnectionsAccounts: _collectFinancialConnectionsAccounts,
/**
* You must call this method when the user logs out from your app. This will ensure that
* any persisted authentication state in the PaymentSheet, such as authentication cookies,
* is also cleared during logout.
*/
resetPaymentSheetCustomer: _resetPaymentSheetCustomer,
};
}
8 changes: 4 additions & 4 deletions src/types/FinancialConnections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,18 +84,18 @@ export type PaymentMethodType = 'us_bank_account' | 'link';

export type Subcategory =
| 'checking'
| 'credit_card'
| 'line_of_credit'
| 'creditCard'
| 'lineOfCredit'
| 'mortgage'
| 'other'
| 'savings';

export type Permission =
| 'balances'
| 'ownership'
| 'payment_method'
| 'paymentMethod'
| 'transactions'
| 'account_numbers';
| 'accountNumbers';

export type Balance = {
/** The UNIX timestamp (in milliseconds) of time that the external institution calculated this balance. */
Expand Down
2 changes: 2 additions & 0 deletions src/types/PaymentMethod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,8 @@ export interface CardResult {
fingerprint?: string;
funding?: string;
last4?: string;
preferredNetwork?: string;
availableNetworks?: Array<string>;
}

export interface FpxResult {
Expand Down
2 changes: 1 addition & 1 deletion stripe-react-native.podspec
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'json'

package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
stripe_version = '~> 22.8.3'
stripe_version = '~> 22.8.4'

Pod::Spec.new do |s|
s.name = 'stripe-react-native'
Expand Down

0 comments on commit f4d9ab0

Please sign in to comment.