Created
December 19, 2019 16:30
-
-
Save IjzerenHein/587c4841284465f5d6d25655014766d5 to your computer and use it in GitHub Desktop.
iOS/JS code for showing the Stripe PaymentOptions ViewController in react-native
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// StripeEx.h | |
// VickyParking | |
// | |
// Created by Hein Rutjes on 06/12/2019. | |
// Copyright © 2019 Facebook. All rights reserved. | |
// | |
#ifndef StripeEx_h | |
#define StripeEx_h | |
#import <Foundation/Foundation.h> | |
#import <PassKit/PassKit.h> | |
#import <Stripe/Stripe.h> | |
#import <React/RCTBridgeModule.h> | |
#import <React/RCTEventEmitter.h> | |
@interface StripeExModule : RCTEventEmitter <RCTBridgeModule, STPCustomerEphemeralKeyProvider, STPPaymentOptionsViewControllerDelegate> | |
//<STPCustomerEphemeralKeyProvider> | |
- (void)createCustomerKeyWithAPIVersion:(nonnull NSString *)apiVersion | |
completion:(nonnull STPJSONResponseCompletionBlock) | |
completion; | |
//</STPCustomerEphemeralKeyProvider> | |
@end | |
#endif /* StripeEx_h */ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// @flow | |
import { NativeModules, NativeEventEmitter } from 'react-native'; | |
const { StripeExModule } = NativeModules; | |
if (!StripeExModule) console.warn('StripeEx was not found'); | |
export const stripeEx = StripeExModule; | |
export type StripeExPaymentOptionType = 'applePay' | 'paymentMethod' | 'paymentMethodParams'; | |
export type StripeExPaymentMethodType = 'card' | 'ideal' | 'fpx' | 'unknown'; | |
export type StripeExCreateCustomerKeyCallbackEvent = { apiVersion: string }; | |
export type StripeExCreateCustomerKeyCallback = ( | |
event: StripeExCreateCustomerKeyCallbackEvent | |
) => Promise<any>; | |
export type StripeExSelectPaymentOptionCallbackEvent = { | |
label: string, | |
type: StripeExPaymentOptionType, | |
paymentMethod?: { | |
id: string, | |
type: StripeExPaymentMethodType, | |
}, | |
}; | |
export type StripeExSelectPaymentOptionCallback = ( | |
event: StripeExSelectPaymentOptionCallbackEvent | |
) => void; | |
const stripeExEventEmitter = new NativeEventEmitter(StripeExModule); | |
let globalCreateCustomerKeyCallback: ?StripeExCreateCustomerKeyCallback; | |
let globalSelectPaymentOptionCallback: ?StripeExSelectPaymentOptionCallback; | |
stripeExEventEmitter.addListener( | |
'CreateCustomerKey', | |
async (event: StripeExCreateCustomerKeyCallbackEvent) => { | |
try { | |
if (!globalCreateCustomerKeyCallback) throw new Error('No CreateCustomerKey callback'); | |
const key = await globalCreateCustomerKeyCallback(event); | |
stripeEx.onCreatedCustomerKey(key, null); | |
} catch (err) { | |
stripeEx.onCreatedCustomerKey({}, { name: err.name, message: err.message }); | |
} | |
} | |
); | |
stripeExEventEmitter.addListener( | |
'SelectPaymentOption', | |
(event: StripeExSelectPaymentOptionCallbackEvent) => { | |
if (!globalSelectPaymentOptionCallback) throw new Error('No SelectPaymentOption callback'); | |
globalSelectPaymentOptionCallback(event); | |
} | |
); | |
stripeEx.showPaymentOptions = async function( | |
options: any, | |
createCustomerKeyCallback: StripeExCreateCustomerKeyCallback, | |
selectPaymentOptionCallback: StripeExSelectPaymentOptionCallback | |
): Promise<boolean> { | |
if (globalCreateCustomerKeyCallback) { | |
throw new Error('Already in progress'); | |
} | |
try { | |
globalCreateCustomerKeyCallback = createCustomerKeyCallback; | |
globalSelectPaymentOptionCallback = selectPaymentOptionCallback; | |
const res = await stripeEx.paymentOptionsForm(options); | |
globalCreateCustomerKeyCallback = undefined; | |
globalSelectPaymentOptionCallback = undefined; | |
return res; | |
} catch (err) { | |
globalCreateCustomerKeyCallback = undefined; | |
globalSelectPaymentOptionCallback = undefined; | |
throw err; | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// StripeEx.m | |
// VickyParking | |
// | |
// Created by Hein Rutjes on 06/12/2019. | |
// Copyright © 2019 Facebook. All rights reserved. | |
// | |
#import "StripeEx.h" | |
#import "StripeHelpers.h" | |
#import <React/RCTConvert.h> | |
@implementation StripeExModule { | |
NSString *_publishableKey; | |
NSString *_merchantId; | |
RCTPromiseResolveBlock _paymentOptionsFormResolver; | |
RCTPromiseRejectBlock _paymentOptionsFormRejecter; | |
STPJSONResponseCompletionBlock _createCustomerKeyCompletionBlock; | |
} | |
- (instancetype)init { | |
if ((self = [super init])) { | |
} | |
return self; | |
} | |
- (dispatch_queue_t)methodQueue { | |
// This makes sure our code is thread safe by never simultaneously executing | |
// Possibly useful, possibly undesirable for performance. | |
return dispatch_get_main_queue(); | |
} | |
- (NSDictionary *)constantsToExport | |
{ | |
return @{}; | |
} | |
RCT_EXPORT_MODULE(); | |
+ (BOOL)requiresMainQueueSetup | |
{ | |
return YES; | |
} | |
- (NSArray<NSString *> *)supportedEvents | |
{ | |
return @[@"CreateCustomerKey",@"SelectPaymentOption"]; | |
} | |
RCT_EXPORT_METHOD(init:(NSDictionary *)options) { | |
_publishableKey = options[@"publishableKey"]; | |
_merchantId = options[@"merchantId"]; | |
//[Stripe setDefaultPublishableKey:publishableKey]; | |
} | |
RCT_EXPORT_METHOD(onCreatedCustomerKey:(NSDictionary *)json error:(NSDictionary *)error) { | |
if (_createCustomerKeyCompletionBlock == nil) return; | |
_createCustomerKeyCompletionBlock(json, [StripeHelpers errorFromJson:error]); | |
_createCustomerKeyCompletionBlock = nil; | |
} | |
- (void)createCustomerKeyWithAPIVersion:(nonnull NSString *)apiVersion | |
completion:(nonnull STPJSONResponseCompletionBlock) | |
completion | |
{ | |
_createCustomerKeyCompletionBlock = completion; | |
[self sendEventWithName:@"CreateCustomerKey" body:@{@"apiVersion": apiVersion}]; | |
} | |
/*RCT_EXPORT_METHOD(getImage:(NSString *)imageType | |
resolver:(RCTPromiseResolveBlock)resolve | |
rejecter:(RCTPromiseRejectBlock)reject) { | |
UIImage* image = nil; | |
if ([imageType isEqualToString:@"applePay"]) { | |
image = [STPImageLibrary applePayCardImage]; | |
} | |
}*/ | |
RCT_EXPORT_METHOD(paymentOptionsForm:(NSDictionary *)options | |
resolver:(RCTPromiseResolveBlock)resolve | |
rejecter:(RCTPromiseRejectBlock)reject) { | |
if((_createCustomerKeyCompletionBlock != nil) || (_paymentOptionsFormResolver != nil)) { | |
reject(@"AlreadyInProgress", @"AlreadyInProgress", nil); | |
return; | |
} | |
// Store promise completetion handlers | |
_paymentOptionsFormResolver = resolve; | |
_paymentOptionsFormRejecter = reject; | |
// Create customer context | |
STPCustomerContext* customerContext = [[STPCustomerContext alloc]initWithKeyProvider:self]; | |
// Get configuration | |
NSUInteger requiredBillingAddressFields = [StripeHelpers billingType:options[@"requiredBillingAddressFields"]]; | |
NSString *companyName = options[@"companyName"] ? options[@"companyName"] : @""; | |
STPUserInformation *prefilledInformation = [StripeHelpers userInformation:options[@"prefilledInformation"]]; | |
NSString *publishableKey = options[@"publishableKey"] ? options[@"publishableKey"] : _publishableKey; | |
UIModalPresentationStyle formPresentation = [StripeHelpers formPresentation:options[@"presentation"]]; | |
STPTheme *theme = [StripeHelpers formTheme:options[@"theme"]]; | |
STPPaymentConfiguration *configuration = [[STPPaymentConfiguration alloc] init]; | |
[configuration setRequiredBillingAddressFields:requiredBillingAddressFields]; | |
[configuration setCompanyName:companyName]; | |
[configuration setPublishableKey:publishableKey]; | |
// Create view controller | |
STPPaymentOptionsViewController *vc = [[STPPaymentOptionsViewController alloc] initWithConfiguration:configuration theme:theme customerContext:customerContext delegate:self]; | |
// Display view controller | |
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:vc]; | |
[navigationController setModalPresentationStyle:formPresentation]; | |
dispatch_async(dispatch_get_main_queue(), ^{ | |
[RCTPresentedViewController() presentViewController:navigationController animated:YES completion:nil]; | |
}); | |
} | |
- (void)paymentOptionsViewController:(nonnull STPPaymentOptionsViewController *) | |
paymentOptionsViewController | |
didFailToLoadWithError:(nonnull NSError *)error | |
{ | |
[RCTPresentedViewController() dismissViewControllerAnimated:YES completion:nil]; | |
[StripeHelpers rejectPromise:_paymentOptionsFormRejecter error:error]; | |
_paymentOptionsFormResolver = nil; | |
_paymentOptionsFormRejecter = nil; | |
} | |
- (void)paymentOptionsViewControllerDidFinish: | |
(nonnull STPPaymentOptionsViewController *)paymentOptionsViewController | |
{ | |
[RCTPresentedViewController() dismissViewControllerAnimated:YES completion:nil]; | |
_paymentOptionsFormResolver(@YES); | |
_paymentOptionsFormResolver = nil; | |
_paymentOptionsFormRejecter = nil; | |
} | |
- (void)paymentOptionsViewControllerDidCancel: | |
(nonnull STPPaymentOptionsViewController *)paymentOptionsViewController | |
{ | |
[RCTPresentedViewController() dismissViewControllerAnimated:YES completion:nil]; | |
_paymentOptionsFormResolver(@NO); | |
_paymentOptionsFormResolver = nil; | |
_paymentOptionsFormRejecter = nil; | |
} | |
- (void)paymentOptionsViewController:(nonnull STPPaymentOptionsViewController *) | |
paymentOptionsViewController | |
didSelectPaymentOption: | |
(nonnull id<STPPaymentOption>)paymentOption | |
{ | |
NSMutableDictionary* body = [[NSMutableDictionary alloc]init]; | |
[body setValue:paymentOption.label forKey:@"label"]; | |
[body setValue:@"unknown" forKey:@"type"]; | |
if ([paymentOption isKindOfClass:[STPApplePayPaymentOption class]]) { | |
[body setValue:@"applePay" forKey:@"type"]; | |
} else if ([paymentOption isKindOfClass:[STPPaymentMethod class]]) { | |
STPPaymentMethod* paymentMethod = (STPPaymentMethod*) paymentOption; | |
[body setValue:@"paymentMethod" forKey:@"type"]; | |
[body setObject:@{ | |
@"id": paymentMethod.stripeId, | |
@"type": [StripeHelpers string:paymentMethod.type] | |
} forKey:@"paymentMethod"]; | |
} else if ([paymentOption isKindOfClass:[STPPaymentMethodParams class]]) { | |
STPPaymentMethodParams* paymentMethodParams = (STPPaymentMethodParams*) paymentOption; | |
[body setValue:@"paymentMethodParams" forKey:@"type"]; | |
} | |
[self sendEventWithName:@"SelectPaymentOption" body:body]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment