@xbenjii/react-native-braintree-dropin-ui 2.5.0 → 2.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,352 +1,352 @@
1
- #import "RNBraintreeDropIn.h"
2
- #import <React/RCTUtils.h>
3
- #import "BTThreeDSecureRequest.h"
4
- #import "BTThreeDSecurePostalAddress.h"
5
- #import "BTThreeDSecureAdditionalInformation.h"
6
-
7
- @implementation RNBraintreeDropIn
8
-
9
- - (dispatch_queue_t)methodQueue
10
- {
11
- return dispatch_get_main_queue();
12
- }
13
- RCT_EXPORT_MODULE(RNBraintreeDropIn)
14
-
15
- RCT_EXPORT_METHOD(show:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
16
- {
17
- BTDropInColorScheme colorScheme;
18
-
19
- if([options[@"darkTheme"] boolValue]){
20
- if (@available(iOS 13.0, *)) {
21
- colorScheme = BTDropInColorSchemeDynamic;
22
- } else {
23
- colorScheme = BTDropInColorSchemeDark;
24
- }
25
- } else {
26
- colorScheme = BTDropInColorSchemeLight;
27
- }
28
-
29
- BTDropInUICustomization *uiCustomization = [[BTDropInUICustomization alloc] initWithColorScheme:colorScheme];
30
-
31
- if(options[@"fontFamily"]){
32
- uiCustomization.fontFamily = options[@"fontFamily"];
33
- }
34
- if(options[@"boldFontFamily"]){
35
- uiCustomization.boldFontFamily = options[@"boldFontFamily"];
36
- }
37
-
38
- self.resolve = resolve;
39
- self.reject = reject;
40
- self.applePayAuthorized = NO;
41
-
42
- NSString* clientToken = options[@"clientToken"];
43
- if (!clientToken) {
44
- reject(@"NO_CLIENT_TOKEN", @"You must provide a client token", nil);
45
- return;
46
- }
47
-
48
- BTDropInRequest *request = [[BTDropInRequest alloc] init];
49
- request.uiCustomization = uiCustomization;
50
-
51
- NSDictionary* threeDSecureOptions = options[@"threeDSecure"];
52
- if (threeDSecureOptions) {
53
- NSNumber* threeDSecureAmount = threeDSecureOptions[@"amount"];
54
- if (!threeDSecureAmount) {
55
- reject(@"NO_3DS_AMOUNT", @"You must provide an amount for 3D Secure", nil);
56
- return;
57
- }
58
-
59
- BTThreeDSecureRequest *threeDSecureRequest = [[BTThreeDSecureRequest alloc] init];
60
- threeDSecureRequest.amount = [NSDecimalNumber decimalNumberWithString:threeDSecureAmount.stringValue];
61
- threeDSecureRequest.versionRequested = BTThreeDSecureVersion2;
62
-
63
- NSString *threeDSecureEmail = threeDSecureOptions[@"email"];
64
- if(threeDSecureEmail) {
65
- threeDSecureRequest.email = threeDSecureEmail;
66
- }
67
-
68
- NSDictionary* threeDSecureBillingAddress = threeDSecureOptions[@"billingAddress"];
69
- if(threeDSecureBillingAddress) {
70
- BTThreeDSecurePostalAddress *billingAddress = [BTThreeDSecurePostalAddress new];
71
-
72
- if(threeDSecureBillingAddress[@"givenName"]) {
73
- billingAddress.givenName = threeDSecureBillingAddress[@"givenName"];
74
- }
75
- if(threeDSecureBillingAddress[@"surname"]) {
76
- billingAddress.surname = threeDSecureBillingAddress[@"surname"];
77
- }
78
- if(threeDSecureBillingAddress[@"streetAddress"]) {
79
- billingAddress.streetAddress = threeDSecureBillingAddress[@"streetAddress"];
80
- }
81
- if(threeDSecureBillingAddress[@"extendedAddress"]) {
82
- billingAddress.extendedAddress = threeDSecureBillingAddress[@"extendedAddress"];
83
- }
84
- if(threeDSecureBillingAddress[@"locality"]) {
85
- billingAddress.locality = threeDSecureBillingAddress[@"locality"];
86
- }
87
- if(threeDSecureBillingAddress[@"region"]) {
88
- billingAddress.region = threeDSecureBillingAddress[@"region"];
89
- }
90
- if(threeDSecureBillingAddress[@"countryCodeAlpha2"]) {
91
- billingAddress.countryCodeAlpha2 = threeDSecureBillingAddress[@"countryCodeAlpha2"];
92
- }
93
- if(threeDSecureBillingAddress[@"postalCode"]) {
94
- billingAddress.postalCode = threeDSecureBillingAddress[@"postalCode"];
95
- }
96
- if(threeDSecureBillingAddress[@"phoneNumber"]) {
97
- billingAddress.phoneNumber = threeDSecureBillingAddress[@"phoneNumber"];
98
- }
99
- threeDSecureRequest.billingAddress = billingAddress;
100
- }
101
-
102
- request.threeDSecureRequest = threeDSecureRequest;
103
-
104
- }
105
-
106
- BTAPIClient *apiClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
107
- self.dataCollector = [[BTDataCollector alloc] initWithAPIClient:apiClient];
108
- [self.dataCollector collectDeviceData:^(NSString * _Nonnull deviceDataCollector) {
109
- // Save deviceData
110
- self.deviceDataCollector = deviceDataCollector;
111
- }];
112
-
113
- if([options[@"vaultManager"] boolValue]){
114
- request.vaultManager = YES;
115
- }
116
-
117
- if([options[@"cardDisabled"] boolValue]){
118
- request.cardDisabled = YES;
119
- }
120
-
121
- if([options[@"applePay"] boolValue]){
122
- NSString* merchantIdentifier = options[@"merchantIdentifier"];
123
- NSString* countryCode = options[@"countryCode"];
124
- NSString* currencyCode = options[@"currencyCode"];
125
- NSString* merchantName = options[@"merchantName"];
126
- NSDecimalNumber* orderTotal = [NSDecimalNumber decimalNumberWithDecimal:[options[@"orderTotal"] decimalValue]];
127
- if(!merchantIdentifier || !countryCode || !currencyCode || !merchantName || !orderTotal){
128
- reject(@"MISSING_OPTIONS", @"Not all required Apple Pay options were provided", nil);
129
- return;
130
- }
131
- self.braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
132
-
133
- self.paymentRequest = [[PKPaymentRequest alloc] init];
134
- self.paymentRequest.merchantIdentifier = merchantIdentifier;
135
- self.paymentRequest.merchantCapabilities = PKMerchantCapability3DS;
136
- self.paymentRequest.countryCode = countryCode;
137
- self.paymentRequest.currencyCode = currencyCode;
138
- self.paymentRequest.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkDiscover, PKPaymentNetworkChinaUnionPay];
139
- self.paymentRequest.paymentSummaryItems =
140
- @[
141
- [PKPaymentSummaryItem summaryItemWithLabel:merchantName amount:orderTotal]
142
- ];
143
- if (@available(iOS 11.0, *)) {
144
- self.paymentRequest.requiredBillingContactFields = [[NSSet<PKContactField> alloc] initWithObjects: PKContactFieldPostalAddress, PKContactFieldEmailAddress, PKContactFieldName, nil];
145
- } else {
146
- reject(@"MISSING_OPTIONS", @"Not all required Apple Pay options were provided", nil);
147
- }
148
- self.viewController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest: self.paymentRequest];
149
- self.viewController.delegate = self;
150
- }else{
151
- request.applePayDisabled = YES;
152
- }
153
-
154
- if(![options[@"payPal"] boolValue]){ //disable paypal
155
- request.paypalDisabled = YES;
156
- }
157
-
158
- BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientToken request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
159
- [self.reactRoot dismissViewControllerAnimated:YES completion:nil];
160
-
161
- //result.paymentOptionType == .ApplePay
162
- //NSLog(@"paymentOptionType = %ld", result.paymentOptionType);
163
-
164
- if (error != nil) {
165
- reject(error.localizedDescription, error.localizedDescription, error);
166
- } else if (result.canceled) {
167
- reject(@"USER_CANCELLATION", @"The user cancelled", nil);
168
- } else {
169
- if (threeDSecureOptions && [result.paymentMethod isKindOfClass:[BTCardNonce class]]) {
170
- BTCardNonce *cardNonce = (BTCardNonce *)result.paymentMethod;
171
- if (!cardNonce.threeDSecureInfo.liabilityShiftPossible && cardNonce.threeDSecureInfo.wasVerified) {
172
- reject(@"3DSECURE_NOT_ABLE_TO_SHIFT_LIABILITY", @"3D Secure liability cannot be shifted", nil);
173
- } else if (!cardNonce.threeDSecureInfo.liabilityShifted && cardNonce.threeDSecureInfo.wasVerified) {
174
- reject(@"3DSECURE_LIABILITY_NOT_SHIFTED", @"3D Secure liability was not shifted", nil);
175
- } else{
176
- [[self class] resolvePayment:result deviceData:self.deviceDataCollector resolver:resolve];
177
- }
178
- } else if(result.paymentMethod == nil && (result.paymentMethodType == 16 || result.paymentMethodType == 17 || result.paymentMethodType == 18)){ //Apple Pay
179
- // UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
180
- // [ctrl presentViewController:self.viewController animated:YES completion:nil];
181
- UIViewController *rootViewController = RCTPresentedViewController();
182
- [rootViewController presentViewController:self.viewController animated:YES completion:nil];
183
- } else{
184
- [[self class] resolvePayment:result deviceData:self.deviceDataCollector resolver:resolve];
185
- }
186
- }
187
- }];
188
-
189
- if (dropIn != nil) {
190
- [self.reactRoot presentViewController:dropIn animated:YES completion:nil];
191
- } else {
192
- reject(@"INVALID_CLIENT_TOKEN", @"The client token seems invalid", nil);
193
- }
194
- }
195
-
196
- RCT_EXPORT_METHOD(getDeviceData:(NSString*)clientToken resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
197
- {
198
- BTAPIClient *braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
199
- BTDataCollector *dataCollector = [[BTDataCollector alloc] initWithAPIClient:braintreeClient];
200
- [dataCollector collectDeviceData:^(NSString * _Nonnull deviceData) {
201
- resolve(deviceData);
202
- }];
203
- }
204
-
205
- RCT_EXPORT_METHOD(fetchMostRecentPaymentMethod:(NSString*)clientToken
206
- resolver:(RCTPromiseResolveBlock)resolve
207
- rejecter:(RCTPromiseRejectBlock)reject)
208
- {
209
- [BTDropInResult mostRecentPaymentMethodForClientToken:clientToken completion:^(BTDropInResult * _Nullable result, NSError * _Nullable error) {
210
- if (error != nil) {
211
- reject(error.localizedDescription, error.localizedDescription, error);
212
- } else if (result.canceled) {
213
- reject(@"USER_CANCELLATION", @"The user cancelled", nil);
214
- } else {
215
- [[self class] resolvePayment:result deviceData:result.deviceData resolver:resolve];
216
- }
217
- }];
218
- }
219
-
220
- RCT_EXPORT_METHOD(tokenizeCard:(NSString*)clientToken
221
- info:(NSDictionary*)cardInfo
222
- resolver:(RCTPromiseResolveBlock)resolve
223
- rejecter:(RCTPromiseRejectBlock)reject)
224
- {
225
- NSString *number = cardInfo[@"number"];
226
- NSString *expirationMonth = cardInfo[@"expirationMonth"];
227
- NSString *expirationYear = cardInfo[@"expirationYear"];
228
- NSString *cvv = cardInfo[@"cvv"];
229
- NSString *postalCode = cardInfo[@"postalCode"];
230
-
231
- if (!number || !expirationMonth || !expirationYear || !cvv || !postalCode) {
232
- reject(@"INVALID_CARD_INFO", @"Invalid card info", nil);
233
- return;
234
- }
235
-
236
- BTAPIClient *braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
237
- BTCardClient *cardClient = [[BTCardClient alloc] initWithAPIClient:braintreeClient];
238
- BTCard *card = [[BTCard alloc] init];
239
- card.number = number;
240
- card.expirationMonth = expirationMonth;
241
- card.expirationYear = expirationYear;
242
- card.cvv = cvv;
243
- card.postalCode = postalCode;
244
-
245
- [cardClient tokenizeCard:card
246
- completion:^(BTCardNonce *tokenizedCard, NSError *error) {
247
- if (error == nil) {
248
- resolve(tokenizedCard.nonce);
249
- } else {
250
- reject(@"TOKENIZE_ERROR", @"Error tokenizing card.", error);
251
- }
252
- }];
253
- }
254
-
255
- - (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
256
- didAuthorizePayment:(PKPayment *)payment
257
- handler:(nonnull void (^)(PKPaymentAuthorizationResult * _Nonnull))completion
258
- {
259
-
260
- // Example: Tokenize the Apple Pay payment
261
- BTApplePayClient *applePayClient = [[BTApplePayClient alloc]
262
- initWithAPIClient:self.braintreeClient];
263
- [applePayClient tokenizeApplePayPayment:payment
264
- completion:^(BTApplePayCardNonce *tokenizedApplePayPayment,
265
- NSError *error) {
266
- if (tokenizedApplePayPayment) {
267
- // On success, send nonce to your server for processing.
268
- // If applicable, address information is accessible in `payment`.
269
- // NSLog(@"description = %@", tokenizedApplePayPayment.localizedDescription);
270
-
271
- completion([[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusSuccess errors:nil]);
272
- self.applePayAuthorized = YES;
273
-
274
-
275
- NSMutableDictionary* result = [NSMutableDictionary new];
276
- [result setObject:tokenizedApplePayPayment.nonce forKey:@"nonce"];
277
- [result setObject:@"Apple Pay" forKey:@"type"];
278
- [result setObject:[NSString stringWithFormat: @"%@ %@", @"", tokenizedApplePayPayment.type] forKey:@"description"];
279
- [result setObject:[NSNumber numberWithBool:false] forKey:@"isDefault"];
280
- [result setObject:self.deviceDataCollector forKey:@"deviceData"];
281
- if(payment.billingContact && payment.billingContact.postalAddress) {
282
- [result setObject:payment.billingContact.name.givenName forKey:@"firstName"];
283
- [result setObject:payment.billingContact.name.familyName forKey:@"lastName"];
284
- if(payment.billingContact.emailAddress) {
285
- [result setObject:payment.billingContact.emailAddress forKey:@"email"];
286
- }
287
- NSString *street = payment.billingContact.postalAddress.street;
288
- NSArray *splitArray = [street componentsSeparatedByString:@"\n"];
289
- [result setObject:splitArray[0] forKey:@"addressLine1"];
290
- if([splitArray count] > 1 && splitArray[1]) {
291
- [result setObject:splitArray[1] forKey:@"addressLine2"];
292
- }
293
- [result setObject:payment.billingContact.postalAddress.city forKey:@"city"];
294
- [result setObject:payment.billingContact.postalAddress.state forKey:@"state"];
295
- [result setObject:payment.billingContact.postalAddress.ISOCountryCode forKey:@"country"];
296
- [result setObject:payment.billingContact.postalAddress.postalCode forKey:@"zip1"];
297
- }
298
- self.resolve(result);
299
-
300
- } else {
301
- // Tokenization failed. Check `error` for the cause of the failure.
302
-
303
- // Indicate failure via the completion callback:
304
- completion([[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusFailure errors:nil]);
305
- }
306
- }];
307
- }
308
-
309
- // Be sure to implement -paymentAuthorizationViewControllerDidFinish:
310
- - (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller{
311
- [self.reactRoot dismissViewControllerAnimated:YES completion:nil];
312
- if(self.applePayAuthorized == NO){
313
- self.reject(@"USER_CANCELLATION", @"The user cancelled", nil);
314
- }
315
- }
316
-
317
- + (void)resolvePayment:(BTDropInResult* _Nullable)result deviceData:(NSString * _Nonnull)deviceDataCollector resolver:(RCTPromiseResolveBlock _Nonnull)resolve {
318
- //NSLog(@"result = %@", result);
319
-
320
- if (!result) {
321
- resolve(nil);
322
- return;
323
- }
324
-
325
- NSMutableDictionary* jsResult = [NSMutableDictionary new];
326
-
327
- //NSLog(@"paymentMethod = %@", result.paymentMethod);
328
- //NSLog(@"paymentIcon = %@", result.paymentIcon);
329
-
330
- [jsResult setObject:result.paymentMethod.nonce forKey:@"nonce"];
331
- [jsResult setObject:result.paymentMethod.type forKey:@"type"];
332
- [jsResult setObject:result.paymentDescription forKey:@"description"];
333
- [jsResult setObject:[NSNumber numberWithBool:result.paymentMethod.isDefault] forKey:@"isDefault"];
334
- [jsResult setObject:deviceDataCollector forKey:@"deviceData"];
335
-
336
- resolve(jsResult);
337
- }
338
-
339
- - (UIViewController*)reactRoot {
340
- UIViewController *root = [UIApplication sharedApplication].keyWindow.rootViewController;
341
- UIViewController *maybeModal = root.presentedViewController;
342
-
343
- UIViewController *modalRoot = root;
344
-
345
- if (maybeModal != nil) {
346
- modalRoot = maybeModal;
347
- }
348
-
349
- return modalRoot;
350
- }
351
-
352
- @end
1
+ #import "RNBraintreeDropIn.h"
2
+ #import <React/RCTUtils.h>
3
+ #import "BTThreeDSecureRequest.h"
4
+ #import "BTThreeDSecurePostalAddress.h"
5
+ #import "BTThreeDSecureAdditionalInformation.h"
6
+
7
+ @implementation RNBraintreeDropIn
8
+
9
+ - (dispatch_queue_t)methodQueue
10
+ {
11
+ return dispatch_get_main_queue();
12
+ }
13
+ RCT_EXPORT_MODULE(RNBraintreeDropIn)
14
+
15
+ RCT_EXPORT_METHOD(show:(NSDictionary*)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
16
+ {
17
+ BTDropInColorScheme colorScheme;
18
+
19
+ if([options[@"darkTheme"] boolValue]){
20
+ if (@available(iOS 13.0, *)) {
21
+ colorScheme = BTDropInColorSchemeDynamic;
22
+ } else {
23
+ colorScheme = BTDropInColorSchemeDark;
24
+ }
25
+ } else {
26
+ colorScheme = BTDropInColorSchemeLight;
27
+ }
28
+
29
+ BTDropInUICustomization *uiCustomization = [[BTDropInUICustomization alloc] initWithColorScheme:colorScheme];
30
+
31
+ if(options[@"fontFamily"]){
32
+ uiCustomization.fontFamily = options[@"fontFamily"];
33
+ }
34
+ if(options[@"boldFontFamily"]){
35
+ uiCustomization.boldFontFamily = options[@"boldFontFamily"];
36
+ }
37
+
38
+ self.resolve = resolve;
39
+ self.reject = reject;
40
+ self.applePayAuthorized = NO;
41
+
42
+ NSString* clientToken = options[@"clientToken"];
43
+ if (!clientToken) {
44
+ reject(@"NO_CLIENT_TOKEN", @"You must provide a client token", nil);
45
+ return;
46
+ }
47
+
48
+ BTDropInRequest *request = [[BTDropInRequest alloc] init];
49
+ request.uiCustomization = uiCustomization;
50
+
51
+ NSDictionary* threeDSecureOptions = options[@"threeDSecure"];
52
+ if (threeDSecureOptions) {
53
+ NSNumber* threeDSecureAmount = threeDSecureOptions[@"amount"];
54
+ if (!threeDSecureAmount) {
55
+ reject(@"NO_3DS_AMOUNT", @"You must provide an amount for 3D Secure", nil);
56
+ return;
57
+ }
58
+
59
+ BTThreeDSecureRequest *threeDSecureRequest = [[BTThreeDSecureRequest alloc] init];
60
+ threeDSecureRequest.amount = [NSDecimalNumber decimalNumberWithString:threeDSecureAmount.stringValue];
61
+ threeDSecureRequest.versionRequested = BTThreeDSecureVersion2;
62
+
63
+ NSString *threeDSecureEmail = threeDSecureOptions[@"email"];
64
+ if(threeDSecureEmail) {
65
+ threeDSecureRequest.email = threeDSecureEmail;
66
+ }
67
+
68
+ NSDictionary* threeDSecureBillingAddress = threeDSecureOptions[@"billingAddress"];
69
+ if(threeDSecureBillingAddress) {
70
+ BTThreeDSecurePostalAddress *billingAddress = [BTThreeDSecurePostalAddress new];
71
+
72
+ if(threeDSecureBillingAddress[@"givenName"]) {
73
+ billingAddress.givenName = threeDSecureBillingAddress[@"givenName"];
74
+ }
75
+ if(threeDSecureBillingAddress[@"surname"]) {
76
+ billingAddress.surname = threeDSecureBillingAddress[@"surname"];
77
+ }
78
+ if(threeDSecureBillingAddress[@"streetAddress"]) {
79
+ billingAddress.streetAddress = threeDSecureBillingAddress[@"streetAddress"];
80
+ }
81
+ if(threeDSecureBillingAddress[@"extendedAddress"]) {
82
+ billingAddress.extendedAddress = threeDSecureBillingAddress[@"extendedAddress"];
83
+ }
84
+ if(threeDSecureBillingAddress[@"locality"]) {
85
+ billingAddress.locality = threeDSecureBillingAddress[@"locality"];
86
+ }
87
+ if(threeDSecureBillingAddress[@"region"]) {
88
+ billingAddress.region = threeDSecureBillingAddress[@"region"];
89
+ }
90
+ if(threeDSecureBillingAddress[@"countryCodeAlpha2"]) {
91
+ billingAddress.countryCodeAlpha2 = threeDSecureBillingAddress[@"countryCodeAlpha2"];
92
+ }
93
+ if(threeDSecureBillingAddress[@"postalCode"]) {
94
+ billingAddress.postalCode = threeDSecureBillingAddress[@"postalCode"];
95
+ }
96
+ if(threeDSecureBillingAddress[@"phoneNumber"]) {
97
+ billingAddress.phoneNumber = threeDSecureBillingAddress[@"phoneNumber"];
98
+ }
99
+ threeDSecureRequest.billingAddress = billingAddress;
100
+ }
101
+
102
+ request.threeDSecureRequest = threeDSecureRequest;
103
+
104
+ }
105
+
106
+ BTAPIClient *apiClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
107
+ self.dataCollector = [[BTDataCollector alloc] initWithAPIClient:apiClient];
108
+ [self.dataCollector collectDeviceData:^(NSString * _Nonnull deviceDataCollector) {
109
+ // Save deviceData
110
+ self.deviceDataCollector = deviceDataCollector;
111
+ }];
112
+
113
+ if([options[@"vaultManager"] boolValue]){
114
+ request.vaultManager = YES;
115
+ }
116
+
117
+ if([options[@"cardDisabled"] boolValue]){
118
+ request.cardDisabled = YES;
119
+ }
120
+
121
+ if([options[@"applePay"] boolValue]){
122
+ NSString* merchantIdentifier = options[@"merchantIdentifier"];
123
+ NSString* countryCode = options[@"countryCode"];
124
+ NSString* currencyCode = options[@"currencyCode"];
125
+ NSString* merchantName = options[@"merchantName"];
126
+ NSDecimalNumber* orderTotal = [NSDecimalNumber decimalNumberWithDecimal:[options[@"orderTotal"] decimalValue]];
127
+ if(!merchantIdentifier || !countryCode || !currencyCode || !merchantName || !orderTotal){
128
+ reject(@"MISSING_OPTIONS", @"Not all required Apple Pay options were provided", nil);
129
+ return;
130
+ }
131
+ self.braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
132
+
133
+ self.paymentRequest = [[PKPaymentRequest alloc] init];
134
+ self.paymentRequest.merchantIdentifier = merchantIdentifier;
135
+ self.paymentRequest.merchantCapabilities = PKMerchantCapability3DS;
136
+ self.paymentRequest.countryCode = countryCode;
137
+ self.paymentRequest.currencyCode = currencyCode;
138
+ self.paymentRequest.supportedNetworks = @[PKPaymentNetworkAmex, PKPaymentNetworkVisa, PKPaymentNetworkMasterCard, PKPaymentNetworkDiscover, PKPaymentNetworkChinaUnionPay];
139
+ self.paymentRequest.paymentSummaryItems =
140
+ @[
141
+ [PKPaymentSummaryItem summaryItemWithLabel:merchantName amount:orderTotal]
142
+ ];
143
+ if (@available(iOS 11.0, *)) {
144
+ self.paymentRequest.requiredBillingContactFields = [[NSSet<PKContactField> alloc] initWithObjects: PKContactFieldPostalAddress, PKContactFieldEmailAddress, PKContactFieldName, nil];
145
+ } else {
146
+ reject(@"MISSING_OPTIONS", @"Not all required Apple Pay options were provided", nil);
147
+ }
148
+ self.viewController = [[PKPaymentAuthorizationViewController alloc] initWithPaymentRequest: self.paymentRequest];
149
+ self.viewController.delegate = self;
150
+ }else{
151
+ request.applePayDisabled = YES;
152
+ }
153
+
154
+ if(![options[@"payPal"] boolValue]){ //disable paypal
155
+ request.paypalDisabled = YES;
156
+ }
157
+
158
+ BTDropInController *dropIn = [[BTDropInController alloc] initWithAuthorization:clientToken request:request handler:^(BTDropInController * _Nonnull controller, BTDropInResult * _Nullable result, NSError * _Nullable error) {
159
+ [self.reactRoot dismissViewControllerAnimated:YES completion:nil];
160
+
161
+ //result.paymentOptionType == .ApplePay
162
+ //NSLog(@"paymentOptionType = %ld", result.paymentOptionType);
163
+
164
+ if (error != nil) {
165
+ reject(error.localizedDescription, error.localizedDescription, error);
166
+ } else if (result.canceled) {
167
+ reject(@"USER_CANCELLATION", @"The user cancelled", nil);
168
+ } else {
169
+ if (threeDSecureOptions && [result.paymentMethod isKindOfClass:[BTCardNonce class]]) {
170
+ BTCardNonce *cardNonce = (BTCardNonce *)result.paymentMethod;
171
+ if (!cardNonce.threeDSecureInfo.liabilityShiftPossible && cardNonce.threeDSecureInfo.wasVerified) {
172
+ reject(@"3DSECURE_NOT_ABLE_TO_SHIFT_LIABILITY", @"3D Secure liability cannot be shifted", nil);
173
+ } else if (!cardNonce.threeDSecureInfo.liabilityShifted && cardNonce.threeDSecureInfo.wasVerified) {
174
+ reject(@"3DSECURE_LIABILITY_NOT_SHIFTED", @"3D Secure liability was not shifted", nil);
175
+ } else{
176
+ [[self class] resolvePayment:result deviceData:self.deviceDataCollector resolver:resolve];
177
+ }
178
+ } else if(result.paymentMethod == nil && (result.paymentMethodType == 16 || result.paymentMethodType == 17 || result.paymentMethodType == 18)){ //Apple Pay
179
+ // UIViewController *ctrl = [[[[UIApplication sharedApplication] delegate] window] rootViewController];
180
+ // [ctrl presentViewController:self.viewController animated:YES completion:nil];
181
+ UIViewController *rootViewController = RCTPresentedViewController();
182
+ [rootViewController presentViewController:self.viewController animated:YES completion:nil];
183
+ } else{
184
+ [[self class] resolvePayment:result deviceData:self.deviceDataCollector resolver:resolve];
185
+ }
186
+ }
187
+ }];
188
+
189
+ if (dropIn != nil) {
190
+ [self.reactRoot presentViewController:dropIn animated:YES completion:nil];
191
+ } else {
192
+ reject(@"INVALID_CLIENT_TOKEN", @"The client token seems invalid", nil);
193
+ }
194
+ }
195
+
196
+ RCT_EXPORT_METHOD(getDeviceData:(NSString*)clientToken resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
197
+ {
198
+ BTAPIClient *braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
199
+ BTDataCollector *dataCollector = [[BTDataCollector alloc] initWithAPIClient:braintreeClient];
200
+ [dataCollector collectDeviceData:^(NSString * _Nonnull deviceData) {
201
+ resolve(deviceData);
202
+ }];
203
+ }
204
+
205
+ RCT_EXPORT_METHOD(fetchMostRecentPaymentMethod:(NSString*)clientToken
206
+ resolver:(RCTPromiseResolveBlock)resolve
207
+ rejecter:(RCTPromiseRejectBlock)reject)
208
+ {
209
+ [BTDropInResult mostRecentPaymentMethodForClientToken:clientToken completion:^(BTDropInResult * _Nullable result, NSError * _Nullable error) {
210
+ if (error != nil) {
211
+ reject(error.localizedDescription, error.localizedDescription, error);
212
+ } else if (result.canceled) {
213
+ reject(@"USER_CANCELLATION", @"The user cancelled", nil);
214
+ } else {
215
+ [[self class] resolvePayment:result deviceData:result.deviceData resolver:resolve];
216
+ }
217
+ }];
218
+ }
219
+
220
+ RCT_EXPORT_METHOD(tokenizeCard:(NSString*)clientToken
221
+ info:(NSDictionary*)cardInfo
222
+ resolver:(RCTPromiseResolveBlock)resolve
223
+ rejecter:(RCTPromiseRejectBlock)reject)
224
+ {
225
+ NSString *number = cardInfo[@"number"];
226
+ NSString *expirationMonth = cardInfo[@"expirationMonth"];
227
+ NSString *expirationYear = cardInfo[@"expirationYear"];
228
+ NSString *cvv = cardInfo[@"cvv"];
229
+ NSString *postalCode = cardInfo[@"postalCode"];
230
+
231
+ if (!number || !expirationMonth || !expirationYear || !cvv || !postalCode) {
232
+ reject(@"INVALID_CARD_INFO", @"Invalid card info", nil);
233
+ return;
234
+ }
235
+
236
+ BTAPIClient *braintreeClient = [[BTAPIClient alloc] initWithAuthorization:clientToken];
237
+ BTCardClient *cardClient = [[BTCardClient alloc] initWithAPIClient:braintreeClient];
238
+ BTCard *card = [[BTCard alloc] init];
239
+ card.number = number;
240
+ card.expirationMonth = expirationMonth;
241
+ card.expirationYear = expirationYear;
242
+ card.cvv = cvv;
243
+ card.postalCode = postalCode;
244
+
245
+ [cardClient tokenizeCard:card
246
+ completion:^(BTCardNonce *tokenizedCard, NSError *error) {
247
+ if (error == nil) {
248
+ resolve(tokenizedCard.nonce);
249
+ } else {
250
+ reject(@"TOKENIZE_ERROR", @"Error tokenizing card.", error);
251
+ }
252
+ }];
253
+ }
254
+
255
+ - (void)paymentAuthorizationViewController:(PKPaymentAuthorizationViewController *)controller
256
+ didAuthorizePayment:(PKPayment *)payment
257
+ handler:(nonnull void (^)(PKPaymentAuthorizationResult * _Nonnull))completion
258
+ {
259
+
260
+ // Example: Tokenize the Apple Pay payment
261
+ BTApplePayClient *applePayClient = [[BTApplePayClient alloc]
262
+ initWithAPIClient:self.braintreeClient];
263
+ [applePayClient tokenizeApplePayPayment:payment
264
+ completion:^(BTApplePayCardNonce *tokenizedApplePayPayment,
265
+ NSError *error) {
266
+ if (tokenizedApplePayPayment) {
267
+ // On success, send nonce to your server for processing.
268
+ // If applicable, address information is accessible in `payment`.
269
+ // NSLog(@"description = %@", tokenizedApplePayPayment.localizedDescription);
270
+
271
+ completion([[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusSuccess errors:nil]);
272
+ self.applePayAuthorized = YES;
273
+
274
+
275
+ NSMutableDictionary* result = [NSMutableDictionary new];
276
+ [result setObject:tokenizedApplePayPayment.nonce forKey:@"nonce"];
277
+ [result setObject:@"Apple Pay" forKey:@"type"];
278
+ [result setObject:[NSString stringWithFormat: @"%@ %@", @"", tokenizedApplePayPayment.type] forKey:@"description"];
279
+ [result setObject:[NSNumber numberWithBool:false] forKey:@"isDefault"];
280
+ [result setObject:self.deviceDataCollector forKey:@"deviceData"];
281
+ if(payment.billingContact && payment.billingContact.postalAddress) {
282
+ [result setObject:payment.billingContact.name.givenName forKey:@"firstName"];
283
+ [result setObject:payment.billingContact.name.familyName forKey:@"lastName"];
284
+ if(payment.billingContact.emailAddress) {
285
+ [result setObject:payment.billingContact.emailAddress forKey:@"email"];
286
+ }
287
+ NSString *street = payment.billingContact.postalAddress.street;
288
+ NSArray *splitArray = [street componentsSeparatedByString:@"\n"];
289
+ [result setObject:splitArray[0] forKey:@"addressLine1"];
290
+ if([splitArray count] > 1 && splitArray[1]) {
291
+ [result setObject:splitArray[1] forKey:@"addressLine2"];
292
+ }
293
+ [result setObject:payment.billingContact.postalAddress.city forKey:@"city"];
294
+ [result setObject:payment.billingContact.postalAddress.state forKey:@"state"];
295
+ [result setObject:payment.billingContact.postalAddress.ISOCountryCode forKey:@"country"];
296
+ [result setObject:payment.billingContact.postalAddress.postalCode forKey:@"zip1"];
297
+ }
298
+ self.resolve(result);
299
+
300
+ } else {
301
+ // Tokenization failed. Check `error` for the cause of the failure.
302
+
303
+ // Indicate failure via the completion callback:
304
+ completion([[PKPaymentAuthorizationResult alloc] initWithStatus:PKPaymentAuthorizationStatusFailure errors:nil]);
305
+ }
306
+ }];
307
+ }
308
+
309
+ // Be sure to implement -paymentAuthorizationViewControllerDidFinish:
310
+ - (void)paymentAuthorizationViewControllerDidFinish:(PKPaymentAuthorizationViewController *)controller{
311
+ [self.reactRoot dismissViewControllerAnimated:YES completion:nil];
312
+ if(self.applePayAuthorized == NO){
313
+ self.reject(@"USER_CANCELLATION", @"The user cancelled", nil);
314
+ }
315
+ }
316
+
317
+ + (void)resolvePayment:(BTDropInResult* _Nullable)result deviceData:(NSString * _Nonnull)deviceDataCollector resolver:(RCTPromiseResolveBlock _Nonnull)resolve {
318
+ //NSLog(@"result = %@", result);
319
+
320
+ if (!result) {
321
+ resolve(nil);
322
+ return;
323
+ }
324
+
325
+ NSMutableDictionary* jsResult = [NSMutableDictionary new];
326
+
327
+ //NSLog(@"paymentMethod = %@", result.paymentMethod);
328
+ //NSLog(@"paymentIcon = %@", result.paymentIcon);
329
+
330
+ [jsResult setObject:result.paymentMethod.nonce forKey:@"nonce"];
331
+ [jsResult setObject:result.paymentMethod.type forKey:@"type"];
332
+ [jsResult setObject:result.paymentDescription forKey:@"description"];
333
+ [jsResult setObject:[NSNumber numberWithBool:result.paymentMethod.isDefault] forKey:@"isDefault"];
334
+ [jsResult setObject:deviceDataCollector forKey:@"deviceData"];
335
+
336
+ resolve(jsResult);
337
+ }
338
+
339
+ - (UIViewController*)reactRoot {
340
+ UIViewController *root = [UIApplication sharedApplication].keyWindow.rootViewController;
341
+ UIViewController *maybeModal = root.presentedViewController;
342
+
343
+ UIViewController *modalRoot = root;
344
+
345
+ if (maybeModal != nil) {
346
+ modalRoot = maybeModal;
347
+ }
348
+
349
+ return modalRoot;
350
+ }
351
+
352
+ @end