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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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