@gmisoftware/react-native-pay 0.0.12 → 0.0.13

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.
Files changed (162) hide show
  1. package/README.md +223 -220
  2. package/android/src/main/java/com/margelo/nitro/pay/GooglePayRequestBuilder.kt +37 -10
  3. package/android/src/main/java/com/margelo/nitro/pay/HybridPaymentHandler.kt +27 -8
  4. package/ios/HybridPaymentHandler.swift +90 -6
  5. package/lib/hooks/__tests__/usePaymentCheckout.integration.test.d.ts +1 -0
  6. package/lib/hooks/__tests__/usePaymentCheckout.integration.test.js +191 -0
  7. package/lib/hooks/usePaymentCheckout.d.ts +47 -3
  8. package/lib/hooks/usePaymentCheckout.js +6 -4
  9. package/lib/plugin/__tests__/index.test.d.ts +1 -0
  10. package/lib/plugin/__tests__/index.test.js +33 -0
  11. package/lib/plugin/__tests__/withApplePay.test.d.ts +1 -0
  12. package/lib/plugin/__tests__/withApplePay.test.js +58 -0
  13. package/lib/plugin/__tests__/withGooglePay.test.d.ts +1 -0
  14. package/lib/plugin/__tests__/withGooglePay.test.js +45 -0
  15. package/lib/plugin/withApplePay.d.ts +1 -0
  16. package/lib/plugin/withApplePay.js +19 -4
  17. package/lib/types/Payment.d.ts +2 -1
  18. package/lib/utils/__tests__/paymentHelpers.test.d.ts +1 -0
  19. package/lib/utils/__tests__/paymentHelpers.test.js +75 -0
  20. package/lib/utils/paymentHelpers.d.ts +1 -4
  21. package/lib/utils/paymentHelpers.js +2 -5
  22. package/nitrogen/generated/android/NitroPay+autolinking.cmake +1 -1
  23. package/nitrogen/generated/android/NitroPay+autolinking.gradle +1 -1
  24. package/nitrogen/generated/android/NitroPayOnLoad.cpp +1 -1
  25. package/nitrogen/generated/android/NitroPayOnLoad.hpp +1 -1
  26. package/nitrogen/generated/android/c++/JCNContact.hpp +1 -1
  27. package/nitrogen/generated/android/c++/JCNContactType.hpp +1 -1
  28. package/nitrogen/generated/android/c++/JCNLabeledEmailAddress.hpp +1 -1
  29. package/nitrogen/generated/android/c++/JCNLabeledPhoneNumber.hpp +1 -1
  30. package/nitrogen/generated/android/c++/JCNLabeledPostalAddress.hpp +1 -1
  31. package/nitrogen/generated/android/c++/JCNPhoneNumber.hpp +1 -1
  32. package/nitrogen/generated/android/c++/JCNPostalAddress.hpp +1 -1
  33. package/nitrogen/generated/android/c++/JFunc_void.hpp +1 -1
  34. package/nitrogen/generated/android/c++/JGooglePayButtonTheme.hpp +1 -1
  35. package/nitrogen/generated/android/c++/JGooglePayButtonType.hpp +1 -1
  36. package/nitrogen/generated/android/c++/JGooglePayEnvironment.hpp +1 -1
  37. package/nitrogen/generated/android/c++/JHybridGooglePayButtonSpec.cpp +1 -1
  38. package/nitrogen/generated/android/c++/JHybridGooglePayButtonSpec.hpp +1 -1
  39. package/nitrogen/generated/android/c++/JHybridPaymentHandlerSpec.cpp +1 -1
  40. package/nitrogen/generated/android/c++/JHybridPaymentHandlerSpec.hpp +1 -1
  41. package/nitrogen/generated/android/c++/JPKSecureElementPass.hpp +1 -1
  42. package/nitrogen/generated/android/c++/JPassActivationState.hpp +1 -1
  43. package/nitrogen/generated/android/c++/JPayServiceStatus.hpp +1 -1
  44. package/nitrogen/generated/android/c++/JPaymentItem.hpp +1 -1
  45. package/nitrogen/generated/android/c++/JPaymentItemType.hpp +1 -1
  46. package/nitrogen/generated/android/c++/JPaymentMethod.hpp +1 -1
  47. package/nitrogen/generated/android/c++/JPaymentMethodType.hpp +1 -1
  48. package/nitrogen/generated/android/c++/JPaymentNetwork.hpp +1 -1
  49. package/nitrogen/generated/android/c++/JPaymentRequest.hpp +10 -6
  50. package/nitrogen/generated/android/c++/JPaymentResult.hpp +1 -1
  51. package/nitrogen/generated/android/c++/JPaymentToken.hpp +1 -1
  52. package/nitrogen/generated/android/c++/views/JHybridGooglePayButtonStateUpdater.cpp +1 -1
  53. package/nitrogen/generated/android/c++/views/JHybridGooglePayButtonStateUpdater.hpp +1 -1
  54. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNContact.kt +1 -1
  55. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNContactType.kt +1 -1
  56. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNLabeledEmailAddress.kt +1 -1
  57. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNLabeledPhoneNumber.kt +1 -1
  58. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNLabeledPostalAddress.kt +1 -1
  59. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNPhoneNumber.kt +1 -1
  60. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNPostalAddress.kt +1 -1
  61. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/Func_void.kt +1 -1
  62. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/GooglePayButtonTheme.kt +1 -1
  63. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/GooglePayButtonType.kt +1 -1
  64. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/GooglePayEnvironment.kt +1 -1
  65. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/HybridGooglePayButtonSpec.kt +1 -1
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/HybridPaymentHandlerSpec.kt +1 -1
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/NitroPayOnLoad.kt +1 -1
  68. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PKSecureElementPass.kt +1 -1
  69. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PassActivationState.kt +1 -1
  70. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PayServiceStatus.kt +1 -1
  71. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentItem.kt +1 -1
  72. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentItemType.kt +1 -1
  73. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentMethod.kt +1 -1
  74. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentMethodType.kt +1 -1
  75. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentNetwork.kt +1 -1
  76. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentRequest.kt +7 -4
  77. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentResult.kt +1 -1
  78. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentToken.kt +1 -1
  79. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/views/HybridGooglePayButtonManager.kt +1 -1
  80. package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/views/HybridGooglePayButtonStateUpdater.kt +1 -1
  81. package/nitrogen/generated/ios/NitroPay+autolinking.rb +1 -1
  82. package/nitrogen/generated/ios/NitroPay-Swift-Cxx-Bridge.cpp +1 -1
  83. package/nitrogen/generated/ios/NitroPay-Swift-Cxx-Bridge.hpp +1 -1
  84. package/nitrogen/generated/ios/NitroPay-Swift-Cxx-Umbrella.hpp +1 -1
  85. package/nitrogen/generated/ios/NitroPayAutolinking.mm +1 -1
  86. package/nitrogen/generated/ios/NitroPayAutolinking.swift +1 -1
  87. package/nitrogen/generated/ios/c++/HybridApplePayButtonSpecSwift.cpp +1 -1
  88. package/nitrogen/generated/ios/c++/HybridApplePayButtonSpecSwift.hpp +1 -1
  89. package/nitrogen/generated/ios/c++/HybridPaymentHandlerSpecSwift.cpp +1 -1
  90. package/nitrogen/generated/ios/c++/HybridPaymentHandlerSpecSwift.hpp +1 -1
  91. package/nitrogen/generated/ios/c++/views/HybridApplePayButtonComponent.mm +1 -1
  92. package/nitrogen/generated/ios/swift/ApplePayButtonStyle.swift +1 -1
  93. package/nitrogen/generated/ios/swift/ApplePayButtonType.swift +1 -1
  94. package/nitrogen/generated/ios/swift/CNContact.swift +1 -1
  95. package/nitrogen/generated/ios/swift/CNContactType.swift +1 -1
  96. package/nitrogen/generated/ios/swift/CNLabeledEmailAddress.swift +1 -1
  97. package/nitrogen/generated/ios/swift/CNLabeledPhoneNumber.swift +1 -1
  98. package/nitrogen/generated/ios/swift/CNLabeledPostalAddress.swift +1 -1
  99. package/nitrogen/generated/ios/swift/CNPhoneNumber.swift +1 -1
  100. package/nitrogen/generated/ios/swift/CNPostalAddress.swift +1 -1
  101. package/nitrogen/generated/ios/swift/Func_void.swift +1 -1
  102. package/nitrogen/generated/ios/swift/Func_void_PaymentResult.swift +1 -1
  103. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -1
  104. package/nitrogen/generated/ios/swift/GooglePayEnvironment.swift +1 -1
  105. package/nitrogen/generated/ios/swift/HybridApplePayButtonSpec.swift +1 -1
  106. package/nitrogen/generated/ios/swift/HybridApplePayButtonSpec_cxx.swift +1 -1
  107. package/nitrogen/generated/ios/swift/HybridPaymentHandlerSpec.swift +1 -1
  108. package/nitrogen/generated/ios/swift/HybridPaymentHandlerSpec_cxx.swift +1 -1
  109. package/nitrogen/generated/ios/swift/PKSecureElementPass.swift +1 -1
  110. package/nitrogen/generated/ios/swift/PassActivationState.swift +1 -1
  111. package/nitrogen/generated/ios/swift/PayServiceStatus.swift +1 -1
  112. package/nitrogen/generated/ios/swift/PaymentItem.swift +1 -1
  113. package/nitrogen/generated/ios/swift/PaymentItemType.swift +1 -1
  114. package/nitrogen/generated/ios/swift/PaymentMethod.swift +1 -1
  115. package/nitrogen/generated/ios/swift/PaymentMethodType.swift +1 -1
  116. package/nitrogen/generated/ios/swift/PaymentNetwork.swift +1 -1
  117. package/nitrogen/generated/ios/swift/PaymentRequest.swift +55 -6
  118. package/nitrogen/generated/ios/swift/PaymentResult.swift +1 -1
  119. package/nitrogen/generated/ios/swift/PaymentToken.swift +1 -1
  120. package/nitrogen/generated/shared/c++/ApplePayButtonStyle.hpp +1 -1
  121. package/nitrogen/generated/shared/c++/ApplePayButtonType.hpp +1 -1
  122. package/nitrogen/generated/shared/c++/CNContact.hpp +1 -1
  123. package/nitrogen/generated/shared/c++/CNContactType.hpp +1 -1
  124. package/nitrogen/generated/shared/c++/CNLabeledEmailAddress.hpp +1 -1
  125. package/nitrogen/generated/shared/c++/CNLabeledPhoneNumber.hpp +1 -1
  126. package/nitrogen/generated/shared/c++/CNLabeledPostalAddress.hpp +1 -1
  127. package/nitrogen/generated/shared/c++/CNPhoneNumber.hpp +1 -1
  128. package/nitrogen/generated/shared/c++/CNPostalAddress.hpp +1 -1
  129. package/nitrogen/generated/shared/c++/GooglePayButtonTheme.hpp +1 -1
  130. package/nitrogen/generated/shared/c++/GooglePayButtonType.hpp +1 -1
  131. package/nitrogen/generated/shared/c++/GooglePayEnvironment.hpp +1 -1
  132. package/nitrogen/generated/shared/c++/HybridApplePayButtonSpec.cpp +1 -1
  133. package/nitrogen/generated/shared/c++/HybridApplePayButtonSpec.hpp +1 -1
  134. package/nitrogen/generated/shared/c++/HybridGooglePayButtonSpec.cpp +1 -1
  135. package/nitrogen/generated/shared/c++/HybridGooglePayButtonSpec.hpp +1 -1
  136. package/nitrogen/generated/shared/c++/HybridPaymentHandlerSpec.cpp +1 -1
  137. package/nitrogen/generated/shared/c++/HybridPaymentHandlerSpec.hpp +1 -1
  138. package/nitrogen/generated/shared/c++/PKSecureElementPass.hpp +1 -1
  139. package/nitrogen/generated/shared/c++/PassActivationState.hpp +1 -1
  140. package/nitrogen/generated/shared/c++/PayServiceStatus.hpp +1 -1
  141. package/nitrogen/generated/shared/c++/PaymentItem.hpp +1 -1
  142. package/nitrogen/generated/shared/c++/PaymentItemType.hpp +1 -1
  143. package/nitrogen/generated/shared/c++/PaymentMethod.hpp +1 -1
  144. package/nitrogen/generated/shared/c++/PaymentMethodType.hpp +1 -1
  145. package/nitrogen/generated/shared/c++/PaymentNetwork.hpp +1 -1
  146. package/nitrogen/generated/shared/c++/PaymentRequest.hpp +10 -6
  147. package/nitrogen/generated/shared/c++/PaymentResult.hpp +1 -1
  148. package/nitrogen/generated/shared/c++/PaymentToken.hpp +1 -1
  149. package/nitrogen/generated/shared/c++/views/HybridApplePayButtonComponent.cpp +1 -1
  150. package/nitrogen/generated/shared/c++/views/HybridApplePayButtonComponent.hpp +1 -1
  151. package/nitrogen/generated/shared/c++/views/HybridGooglePayButtonComponent.cpp +1 -1
  152. package/nitrogen/generated/shared/c++/views/HybridGooglePayButtonComponent.hpp +1 -1
  153. package/package.json +11 -4
  154. package/src/hooks/__tests__/usePaymentCheckout.integration.test.ts +244 -0
  155. package/src/hooks/usePaymentCheckout.ts +60 -5
  156. package/src/plugin/__tests__/index.test.ts +37 -0
  157. package/src/plugin/__tests__/withApplePay.test.ts +83 -0
  158. package/src/plugin/__tests__/withGooglePay.test.ts +66 -0
  159. package/src/plugin/withApplePay.ts +34 -6
  160. package/src/types/Payment.ts +4 -1
  161. package/src/utils/__tests__/paymentHelpers.test.ts +93 -0
  162. package/src/utils/paymentHelpers.ts +1 -6
@@ -2,7 +2,7 @@
2
2
  /// PaymentRequest.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -41,7 +41,7 @@ namespace margelo::nitro::pay {
41
41
  */
42
42
  struct PaymentRequest {
43
43
  public:
44
- std::string merchantIdentifier SWIFT_PRIVATE;
44
+ std::optional<std::string> applePayMerchantIdentifier SWIFT_PRIVATE;
45
45
  std::optional<std::string> merchantName SWIFT_PRIVATE;
46
46
  std::string countryCode SWIFT_PRIVATE;
47
47
  std::string currencyCode SWIFT_PRIVATE;
@@ -52,13 +52,14 @@ namespace margelo::nitro::pay {
52
52
  std::optional<std::vector<PaymentItem>> shippingMethods SWIFT_PRIVATE;
53
53
  std::optional<bool> billingContactRequired SWIFT_PRIVATE;
54
54
  std::optional<bool> shippingContactRequired SWIFT_PRIVATE;
55
+ std::optional<std::string> googlePayMerchantId SWIFT_PRIVATE;
55
56
  std::optional<GooglePayEnvironment> googlePayEnvironment SWIFT_PRIVATE;
56
57
  std::optional<std::string> googlePayGateway SWIFT_PRIVATE;
57
58
  std::optional<std::string> googlePayGatewayMerchantId SWIFT_PRIVATE;
58
59
 
59
60
  public:
60
61
  PaymentRequest() = default;
61
- explicit PaymentRequest(std::string merchantIdentifier, std::optional<std::string> merchantName, std::string countryCode, std::string currencyCode, std::vector<PaymentItem> paymentItems, std::vector<std::string> merchantCapabilities, std::vector<std::string> supportedNetworks, std::optional<std::string> shippingType, std::optional<std::vector<PaymentItem>> shippingMethods, std::optional<bool> billingContactRequired, std::optional<bool> shippingContactRequired, std::optional<GooglePayEnvironment> googlePayEnvironment, std::optional<std::string> googlePayGateway, std::optional<std::string> googlePayGatewayMerchantId): merchantIdentifier(merchantIdentifier), merchantName(merchantName), countryCode(countryCode), currencyCode(currencyCode), paymentItems(paymentItems), merchantCapabilities(merchantCapabilities), supportedNetworks(supportedNetworks), shippingType(shippingType), shippingMethods(shippingMethods), billingContactRequired(billingContactRequired), shippingContactRequired(shippingContactRequired), googlePayEnvironment(googlePayEnvironment), googlePayGateway(googlePayGateway), googlePayGatewayMerchantId(googlePayGatewayMerchantId) {}
62
+ explicit PaymentRequest(std::optional<std::string> applePayMerchantIdentifier, std::optional<std::string> merchantName, std::string countryCode, std::string currencyCode, std::vector<PaymentItem> paymentItems, std::vector<std::string> merchantCapabilities, std::vector<std::string> supportedNetworks, std::optional<std::string> shippingType, std::optional<std::vector<PaymentItem>> shippingMethods, std::optional<bool> billingContactRequired, std::optional<bool> shippingContactRequired, std::optional<std::string> googlePayMerchantId, std::optional<GooglePayEnvironment> googlePayEnvironment, std::optional<std::string> googlePayGateway, std::optional<std::string> googlePayGatewayMerchantId): applePayMerchantIdentifier(applePayMerchantIdentifier), merchantName(merchantName), countryCode(countryCode), currencyCode(currencyCode), paymentItems(paymentItems), merchantCapabilities(merchantCapabilities), supportedNetworks(supportedNetworks), shippingType(shippingType), shippingMethods(shippingMethods), billingContactRequired(billingContactRequired), shippingContactRequired(shippingContactRequired), googlePayMerchantId(googlePayMerchantId), googlePayEnvironment(googlePayEnvironment), googlePayGateway(googlePayGateway), googlePayGatewayMerchantId(googlePayGatewayMerchantId) {}
62
63
  };
63
64
 
64
65
  } // namespace margelo::nitro::pay
@@ -71,7 +72,7 @@ namespace margelo::nitro {
71
72
  static inline margelo::nitro::pay::PaymentRequest fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
72
73
  jsi::Object obj = arg.asObject(runtime);
73
74
  return margelo::nitro::pay::PaymentRequest(
74
- JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, "merchantIdentifier")),
75
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "applePayMerchantIdentifier")),
75
76
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "merchantName")),
76
77
  JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, "countryCode")),
77
78
  JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, "currencyCode")),
@@ -82,6 +83,7 @@ namespace margelo::nitro {
82
83
  JSIConverter<std::optional<std::vector<margelo::nitro::pay::PaymentItem>>>::fromJSI(runtime, obj.getProperty(runtime, "shippingMethods")),
83
84
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, "billingContactRequired")),
84
85
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, "shippingContactRequired")),
86
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "googlePayMerchantId")),
85
87
  JSIConverter<std::optional<margelo::nitro::pay::GooglePayEnvironment>>::fromJSI(runtime, obj.getProperty(runtime, "googlePayEnvironment")),
86
88
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "googlePayGateway")),
87
89
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, "googlePayGatewayMerchantId"))
@@ -89,7 +91,7 @@ namespace margelo::nitro {
89
91
  }
90
92
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::pay::PaymentRequest& arg) {
91
93
  jsi::Object obj(runtime);
92
- obj.setProperty(runtime, "merchantIdentifier", JSIConverter<std::string>::toJSI(runtime, arg.merchantIdentifier));
94
+ obj.setProperty(runtime, "applePayMerchantIdentifier", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.applePayMerchantIdentifier));
93
95
  obj.setProperty(runtime, "merchantName", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.merchantName));
94
96
  obj.setProperty(runtime, "countryCode", JSIConverter<std::string>::toJSI(runtime, arg.countryCode));
95
97
  obj.setProperty(runtime, "currencyCode", JSIConverter<std::string>::toJSI(runtime, arg.currencyCode));
@@ -100,6 +102,7 @@ namespace margelo::nitro {
100
102
  obj.setProperty(runtime, "shippingMethods", JSIConverter<std::optional<std::vector<margelo::nitro::pay::PaymentItem>>>::toJSI(runtime, arg.shippingMethods));
101
103
  obj.setProperty(runtime, "billingContactRequired", JSIConverter<std::optional<bool>>::toJSI(runtime, arg.billingContactRequired));
102
104
  obj.setProperty(runtime, "shippingContactRequired", JSIConverter<std::optional<bool>>::toJSI(runtime, arg.shippingContactRequired));
105
+ obj.setProperty(runtime, "googlePayMerchantId", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.googlePayMerchantId));
103
106
  obj.setProperty(runtime, "googlePayEnvironment", JSIConverter<std::optional<margelo::nitro::pay::GooglePayEnvironment>>::toJSI(runtime, arg.googlePayEnvironment));
104
107
  obj.setProperty(runtime, "googlePayGateway", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.googlePayGateway));
105
108
  obj.setProperty(runtime, "googlePayGatewayMerchantId", JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.googlePayGatewayMerchantId));
@@ -113,7 +116,7 @@ namespace margelo::nitro {
113
116
  if (!nitro::isPlainObject(runtime, obj)) {
114
117
  return false;
115
118
  }
116
- if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, "merchantIdentifier"))) return false;
119
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "applePayMerchantIdentifier"))) return false;
117
120
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "merchantName"))) return false;
118
121
  if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, "countryCode"))) return false;
119
122
  if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, "currencyCode"))) return false;
@@ -124,6 +127,7 @@ namespace margelo::nitro {
124
127
  if (!JSIConverter<std::optional<std::vector<margelo::nitro::pay::PaymentItem>>>::canConvert(runtime, obj.getProperty(runtime, "shippingMethods"))) return false;
125
128
  if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, "billingContactRequired"))) return false;
126
129
  if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, "shippingContactRequired"))) return false;
130
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "googlePayMerchantId"))) return false;
127
131
  if (!JSIConverter<std::optional<margelo::nitro::pay::GooglePayEnvironment>>::canConvert(runtime, obj.getProperty(runtime, "googlePayEnvironment"))) return false;
128
132
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "googlePayGateway"))) return false;
129
133
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, "googlePayGatewayMerchantId"))) return false;
@@ -2,7 +2,7 @@
2
2
  /// PaymentResult.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -2,7 +2,7 @@
2
2
  /// PaymentToken.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -2,7 +2,7 @@
2
2
  /// HybridApplePayButtonComponent.cpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #include "HybridApplePayButtonComponent.hpp"
@@ -2,7 +2,7 @@
2
2
  /// HybridApplePayButtonComponent.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
@@ -2,7 +2,7 @@
2
2
  /// HybridGooglePayButtonComponent.cpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #include "HybridGooglePayButtonComponent.hpp"
@@ -2,7 +2,7 @@
2
2
  /// HybridGooglePayButtonComponent.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
- /// Copyright © 2025 Marc Rousavy @ Margelo
5
+ /// Copyright © 2026 Marc Rousavy @ Margelo
6
6
  ///
7
7
 
8
8
  #pragma once
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gmisoftware/react-native-pay",
3
- "version": "0.0.12",
3
+ "version": "0.0.13",
4
4
  "author": "gmi.software",
5
5
  "repository": {
6
6
  "type": "git",
@@ -10,15 +10,19 @@
10
10
  "module": "lib/index",
11
11
  "devDependencies": {
12
12
  "@react-native/eslint-config": "0.82.0",
13
- "@types/jest": "^29.5.12",
13
+ "@testing-library/react-native": "^13.3.3",
14
+ "@types/jest": "^30.0.0",
14
15
  "@types/react": "^19.1.03",
16
+ "babel-jest": "^30.2.0",
15
17
  "eslint": "^8.57.0",
16
18
  "eslint-config-prettier": "^9.1.0",
17
19
  "eslint-plugin-prettier": "^5.2.1",
20
+ "jest": "^30.2.0",
18
21
  "nitrogen": "*",
19
22
  "prettier": "^3.3.3",
20
- "typescript": "^5.8.3",
21
- "release-it": "^19.0.0"
23
+ "react-test-renderer": "19.1.0",
24
+ "release-it": "^19.0.0",
25
+ "typescript": "^5.8.3"
22
26
  },
23
27
  "peerDependencies": {
24
28
  "react": "*",
@@ -105,6 +109,9 @@
105
109
  "postpack": "rm ./README.md",
106
110
  "postinstall": "tsc || exit 0;",
107
111
  "typecheck": "tsc --noEmit",
112
+ "test": "jest",
113
+ "test:watch": "jest --watch",
114
+ "test:ci": "jest --runInBand --ci",
108
115
  "clean": "rm -rf android/build node_modules/**/android/build lib",
109
116
  "lint": "eslint \"**/*.{js,ts,tsx}\" --fix",
110
117
  "lint-ci": "eslint \"**/*.{js,ts,tsx}\" -f @jamesacarr/github-actions",
@@ -0,0 +1,244 @@
1
+ import { act, renderHook, waitFor } from '@testing-library/react-native'
2
+
3
+ const mockPayServiceStatus = jest.fn()
4
+ const mockStartPayment = jest.fn()
5
+
6
+ jest.mock('react-native-nitro-modules', () => ({
7
+ NitroModules: {
8
+ createHybridObject: jest.fn(() => ({
9
+ payServiceStatus: (...args: any[]) => mockPayServiceStatus(...args),
10
+ startPayment: (...args: any[]) => mockStartPayment(...args),
11
+ })),
12
+ },
13
+ }))
14
+
15
+ import { usePaymentCheckout } from '../usePaymentCheckout'
16
+
17
+ describe('usePaymentCheckout integration', () => {
18
+ beforeEach(() => {
19
+ mockPayServiceStatus.mockReturnValue({
20
+ canMakePayments: true,
21
+ canSetupCards: true,
22
+ })
23
+ mockStartPayment.mockReset()
24
+ })
25
+
26
+ const renderCheckout = () =>
27
+ renderHook(() =>
28
+ usePaymentCheckout({})
29
+ )
30
+
31
+ it('loads payment service status on mount', async () => {
32
+ const { result } = renderCheckout()
33
+
34
+ await waitFor(() => {
35
+ expect(result.current.isCheckingStatus).toBe(false)
36
+ })
37
+
38
+ expect(result.current.canMakePayments).toBe(true)
39
+ expect(result.current.canSetupCards).toBe(true)
40
+ })
41
+
42
+ it('falls back to unavailable status when status check fails', async () => {
43
+ mockPayServiceStatus.mockImplementationOnce(() => {
44
+ throw new Error('Native status failure')
45
+ })
46
+ const consoleSpy = jest.spyOn(console, 'error').mockImplementation(() => {})
47
+
48
+ const { result } = renderCheckout()
49
+
50
+ await waitFor(() => {
51
+ expect(result.current.isCheckingStatus).toBe(false)
52
+ })
53
+
54
+ expect(result.current.canMakePayments).toBe(false)
55
+ expect(result.current.canSetupCards).toBe(false)
56
+ expect(consoleSpy).toHaveBeenCalled()
57
+ consoleSpy.mockRestore()
58
+ })
59
+
60
+ it('manages cart operations and total correctly', async () => {
61
+ const { result } = renderCheckout()
62
+
63
+ await waitFor(() => {
64
+ expect(result.current.isCheckingStatus).toBe(false)
65
+ })
66
+
67
+ act(() => {
68
+ result.current.addItem('Coffee', 4.5)
69
+ result.current.addItems([
70
+ { label: 'Sandwich', amount: 8.25 },
71
+ { label: 'Tip', amount: 1.25, type: 'pending' },
72
+ ])
73
+ })
74
+
75
+ expect(result.current.items).toEqual([
76
+ { label: 'Coffee', amount: 4.5, type: 'final' },
77
+ { label: 'Sandwich', amount: 8.25, type: 'final' },
78
+ { label: 'Tip', amount: 1.25, type: 'pending' },
79
+ ])
80
+ expect(result.current.total).toBeCloseTo(14)
81
+
82
+ act(() => {
83
+ result.current.updateItem(0, { amount: 5 })
84
+ })
85
+ expect(result.current.items[0]?.amount).toBe(5)
86
+ expect(result.current.total).toBeCloseTo(14.5)
87
+
88
+ act(() => {
89
+ result.current.removeItem(1)
90
+ })
91
+ expect(result.current.items.map((item) => item.label)).toEqual([
92
+ 'Coffee',
93
+ 'Tip',
94
+ ])
95
+
96
+ act(() => {
97
+ result.current.clearItems()
98
+ })
99
+ expect(result.current.items).toEqual([])
100
+ expect(result.current.total).toBe(0)
101
+ })
102
+
103
+ it('provides default fallback payment item when cart is empty', () => {
104
+ const { result } = renderCheckout()
105
+
106
+ expect(result.current.paymentRequest.paymentItems).toEqual([
107
+ { label: 'Total', amount: 0, type: 'final' },
108
+ ])
109
+ expect(result.current.paymentRequest.countryCode).toBe('US')
110
+ expect(result.current.paymentRequest.currencyCode).toBe('USD')
111
+ })
112
+
113
+ it('rejects startPayment when cart is empty', async () => {
114
+ const { result } = renderCheckout()
115
+
116
+ let paymentResult: any = 'not-called'
117
+ await act(async () => {
118
+ paymentResult = await result.current.startPayment()
119
+ })
120
+
121
+ expect(paymentResult).toBeNull()
122
+ expect(result.current.error?.message).toBe('Cart is empty')
123
+ expect(mockStartPayment).not.toHaveBeenCalled()
124
+ })
125
+
126
+ it('handles successful payments', async () => {
127
+ const nativeSuccess = { success: true, transactionId: 'tx_123' }
128
+ mockStartPayment.mockResolvedValueOnce(nativeSuccess)
129
+ const { result } = renderCheckout()
130
+
131
+ act(() => {
132
+ result.current.addItem('Coffee', 4.99)
133
+ })
134
+
135
+ let paymentResult: any = null
136
+ await act(async () => {
137
+ paymentResult = await result.current.startPayment()
138
+ })
139
+
140
+ expect(mockStartPayment).toHaveBeenCalledTimes(1)
141
+ expect(mockStartPayment).toHaveBeenCalledWith(
142
+ expect.objectContaining({
143
+ paymentItems: [{ label: 'Coffee', amount: 4.99, type: 'final' }],
144
+ })
145
+ )
146
+ expect(paymentResult).toEqual(nativeSuccess)
147
+ expect(result.current.result).toEqual(nativeSuccess)
148
+ expect(result.current.error).toBeNull()
149
+ expect(result.current.isProcessing).toBe(false)
150
+ })
151
+
152
+ it('sets an error when native payment response has success=false', async () => {
153
+ mockStartPayment.mockResolvedValueOnce({
154
+ success: false,
155
+ error: 'Declined by issuer',
156
+ })
157
+ const { result } = renderCheckout()
158
+
159
+ act(() => {
160
+ result.current.addItem('Order', 9.99)
161
+ })
162
+
163
+ await act(async () => {
164
+ await result.current.startPayment()
165
+ })
166
+
167
+ expect(result.current.error?.message).toBe('Declined by issuer')
168
+ expect(result.current.result).toEqual({
169
+ success: false,
170
+ error: 'Declined by issuer',
171
+ })
172
+ })
173
+
174
+ it('forwards Apple Pay override and Google Pay config when provided', async () => {
175
+ mockStartPayment.mockResolvedValueOnce({ success: true })
176
+
177
+ const { result } = renderHook(() =>
178
+ usePaymentCheckout({
179
+ applePayMerchantIdentifier: 'merchant.com.apple.override',
180
+ googlePayMerchantId: 'google-pay-merchant-id',
181
+ googlePayEnvironment: 'PRODUCTION',
182
+ googlePayGateway: 'stripe',
183
+ googlePayGatewayMerchantId: 'gateway-merchant-id',
184
+ })
185
+ )
186
+
187
+ act(() => {
188
+ result.current.addItem('Order', 12)
189
+ })
190
+
191
+ await act(async () => {
192
+ await result.current.startPayment()
193
+ })
194
+
195
+ expect(mockStartPayment).toHaveBeenCalledWith(
196
+ expect.objectContaining({
197
+ applePayMerchantIdentifier: 'merchant.com.apple.override',
198
+ googlePayMerchantId: 'google-pay-merchant-id',
199
+ googlePayEnvironment: 'PRODUCTION',
200
+ googlePayGateway: 'stripe',
201
+ googlePayGatewayMerchantId: 'gateway-merchant-id',
202
+ })
203
+ )
204
+ })
205
+
206
+ it('uses generic error for non-Error thrown values', async () => {
207
+ mockStartPayment.mockRejectedValueOnce('native crash')
208
+ const { result } = renderCheckout()
209
+
210
+ act(() => {
211
+ result.current.addItem('Order', 12)
212
+ })
213
+
214
+ let paymentResult: any = 'not-null'
215
+ await act(async () => {
216
+ paymentResult = await result.current.startPayment()
217
+ })
218
+
219
+ expect(paymentResult).toBeNull()
220
+ expect(result.current.error?.message).toBe('Payment processing failed')
221
+ })
222
+
223
+ it('resets transient checkout state', async () => {
224
+ mockStartPayment.mockResolvedValueOnce({ success: false, error: 'Failed' })
225
+ const { result } = renderCheckout()
226
+
227
+ act(() => {
228
+ result.current.addItem('Order', 3)
229
+ })
230
+ await act(async () => {
231
+ await result.current.startPayment()
232
+ })
233
+
234
+ expect(result.current.error).not.toBeNull()
235
+
236
+ act(() => {
237
+ result.current.reset()
238
+ })
239
+
240
+ expect(result.current.error).toBeNull()
241
+ expect(result.current.result).toBeNull()
242
+ expect(result.current.isProcessing).toBe(false)
243
+ })
244
+ })
@@ -13,15 +13,67 @@ import type {
13
13
  } from '../types'
14
14
  import { createPaymentItem, calculateTotal } from '../utils'
15
15
 
16
+ /**
17
+ * Configuration for `usePaymentCheckout`.
18
+ */
16
19
  export interface UsePaymentCheckoutConfig {
17
- merchantIdentifier: string
20
+ /**
21
+ * Merchant name shown by payment providers that support displaying it.
22
+ * Used primarily by Google Pay.
23
+ */
18
24
  merchantName?: string
25
+
26
+ /**
27
+ * ISO 3166-1 alpha-2 country code for the transaction.
28
+ * Defaults to `'US'`.
29
+ */
19
30
  countryCode?: string
31
+
32
+ /**
33
+ * ISO 4217 currency code for all payment items.
34
+ * Defaults to `'USD'`.
35
+ */
20
36
  currencyCode?: string
37
+
38
+ /**
39
+ * Supported card networks for the payment sheet.
40
+ * Defaults to `['visa', 'mastercard', 'amex', 'discover']`.
41
+ */
21
42
  supportedNetworks?: string[]
43
+
44
+ /**
45
+ * Merchant capabilities passed to Apple Pay.
46
+ * Defaults to `['3DS']`.
47
+ */
22
48
  merchantCapabilities?: string[]
49
+
50
+ /**
51
+ * Optional Apple Pay Merchant ID override.
52
+ * When omitted, iOS reads the Merchant ID from the app entitlements.
53
+ */
54
+ applePayMerchantIdentifier?: string
55
+
56
+ /**
57
+ * Google Pay merchant ID used in Android production requests.
58
+ * Not needed for iOS.
59
+ */
60
+ googlePayMerchantId?: string
61
+
62
+ /**
63
+ * Google Pay environment for Android requests.
64
+ * Use `'TEST'` for sandbox flows and `'PRODUCTION'` for live payments.
65
+ */
23
66
  googlePayEnvironment?: GooglePayEnvironment
67
+
68
+ /**
69
+ * Payment gateway identifier for Google Pay tokenization.
70
+ * Examples include `'stripe'`, `'braintree'`, and `'adyen'`.
71
+ */
24
72
  googlePayGateway?: string
73
+
74
+ /**
75
+ * Merchant ID provided by your payment gateway for Google Pay tokenization.
76
+ */
25
77
  googlePayGatewayMerchantId?: string
26
78
  }
27
79
 
@@ -62,7 +114,8 @@ export interface UsePaymentCheckoutReturn {
62
114
  * - Payment processing
63
115
  * - State management
64
116
  *
65
- * @param config - Payment configuration
117
+ * @param config - Hook configuration including locale, supported networks,
118
+ * Apple Pay override, and Google Pay gateway settings.
66
119
  * @returns Complete payment checkout interface
67
120
  *
68
121
  * @example
@@ -79,9 +132,9 @@ export interface UsePaymentCheckoutReturn {
79
132
  * isProcessing,
80
133
  * error,
81
134
  * } = usePaymentCheckout({
82
- * merchantIdentifier: 'merchant.com.example',
83
135
  * currencyCode: 'USD',
84
136
  * countryCode: 'US',
137
+ * googlePayMerchantId: 'your_google_pay_merchant_id',
85
138
  * })
86
139
  *
87
140
  * // Add single item
@@ -142,19 +195,20 @@ export function usePaymentCheckout(
142
195
 
143
196
  const paymentRequest = useMemo<PaymentRequest>(() => {
144
197
  const {
145
- merchantIdentifier,
146
198
  merchantName,
147
199
  countryCode = 'US',
148
200
  currencyCode = 'USD',
149
201
  supportedNetworks = ['visa', 'mastercard', 'amex', 'discover'],
150
202
  merchantCapabilities = ['3DS'],
203
+ applePayMerchantIdentifier,
204
+ googlePayMerchantId,
151
205
  googlePayEnvironment,
152
206
  googlePayGateway,
153
207
  googlePayGatewayMerchantId,
154
208
  } = config
155
209
 
156
210
  return {
157
- merchantIdentifier,
211
+ applePayMerchantIdentifier,
158
212
  countryCode,
159
213
  merchantName,
160
214
  currencyCode,
@@ -162,6 +216,7 @@ export function usePaymentCheckout(
162
216
  merchantCapabilities,
163
217
  paymentItems:
164
218
  items.length > 0 ? items : [createPaymentItem('Total', 0, 'final')],
219
+ googlePayMerchantId,
165
220
  googlePayEnvironment,
166
221
  googlePayGateway,
167
222
  googlePayGatewayMerchantId,
@@ -0,0 +1,37 @@
1
+ const mockWithGooglePay = jest.fn((config, _props) => ({
2
+ ...config,
3
+ googlePay: true,
4
+ }))
5
+ const mockWithApplePay = jest.fn((config, _props) => ({
6
+ ...config,
7
+ applePay: true,
8
+ }))
9
+
10
+ jest.mock('../withGooglePay', () => ({
11
+ withGooglePay: (config: any, props: any) => mockWithGooglePay(config, props),
12
+ }))
13
+
14
+ jest.mock('../withApplePay', () => ({
15
+ withApplePay: (config: any, props: any) => mockWithApplePay(config, props),
16
+ }))
17
+
18
+ import withReactNativePay from '../index'
19
+
20
+ describe('withReactNativePay', () => {
21
+ it('applies Google Pay and Apple Pay plugins in order', () => {
22
+ const inputConfig = { name: 'my-app' }
23
+ const props = {
24
+ merchantIdentifier: 'merchant.com.test',
25
+ enableGooglePay: true,
26
+ }
27
+
28
+ const result = withReactNativePay(inputConfig as any, props)
29
+
30
+ expect(mockWithGooglePay).toHaveBeenCalledWith(inputConfig, props)
31
+ expect(mockWithApplePay).toHaveBeenCalledWith(
32
+ { name: 'my-app', googlePay: true },
33
+ props
34
+ )
35
+ expect(result).toEqual({ name: 'my-app', googlePay: true, applePay: true })
36
+ })
37
+ })
@@ -0,0 +1,83 @@
1
+ import {
2
+ withApplePay,
3
+ setApplePayEntitlement,
4
+ setApplePayMerchantIdentifiersInInfoPlist,
5
+ } from '../withApplePay'
6
+
7
+ const mockWithEntitlementsPlist = jest.fn(
8
+ (config: Record<string, unknown>, action: (input: any) => any) =>
9
+ action('modResults' in config ? config : { modResults: config })
10
+ )
11
+ const mockWithInfoPlist = jest.fn(
12
+ (config: Record<string, unknown>, action: (input: any) => any) =>
13
+ action('modResults' in config ? config : { modResults: config })
14
+ )
15
+
16
+ jest.mock('expo/config-plugins', () => ({
17
+ withEntitlementsPlist: (config: any, action: (input: any) => any) =>
18
+ mockWithEntitlementsPlist(config, action),
19
+ withInfoPlist: (config: any, action: (input: any) => any) =>
20
+ mockWithInfoPlist(config, action),
21
+ }))
22
+
23
+ describe('withApplePay', () => {
24
+ it('adds a single merchant entitlement', () => {
25
+ const result = setApplePayEntitlement('merchant.com.one', {})
26
+ expect(result).toEqual({
27
+ 'com.apple.developer.in-app-payments': ['merchant.com.one'],
28
+ })
29
+ })
30
+
31
+ it('adds multiple merchants and de-duplicates existing values', () => {
32
+ const result = setApplePayEntitlement(
33
+ ['merchant.com.a', 'merchant.com.b', 'merchant.com.a', ''],
34
+ {
35
+ 'com.apple.developer.in-app-payments': ['merchant.com.a'],
36
+ }
37
+ )
38
+ expect(result).toEqual({
39
+ 'com.apple.developer.in-app-payments': [
40
+ 'merchant.com.a',
41
+ 'merchant.com.b',
42
+ ],
43
+ })
44
+ })
45
+
46
+ it('writes merchant identifiers into Info.plist', () => {
47
+ const result = setApplePayMerchantIdentifiersInInfoPlist(
48
+ ['merchant.com.a', 'merchant.com.b', 'merchant.com.a', ''],
49
+ {}
50
+ )
51
+
52
+ expect(result).toEqual({
53
+ ReactNativePayApplePayMerchantIdentifiers: [
54
+ 'merchant.com.a',
55
+ 'merchant.com.b',
56
+ ],
57
+ })
58
+ })
59
+
60
+ it('does not modify config when merchantIdentifier is missing', () => {
61
+ const config = { name: 'app' }
62
+ const result = withApplePay(config as any, {})
63
+ expect(result).toBe(config)
64
+ expect(mockWithEntitlementsPlist).not.toHaveBeenCalled()
65
+ expect(mockWithInfoPlist).not.toHaveBeenCalled()
66
+ })
67
+
68
+ it('applies entitlements when merchantIdentifier is provided', () => {
69
+ const config = {}
70
+ const result = withApplePay(config as any, {
71
+ merchantIdentifier: 'merchant.com.test',
72
+ })
73
+
74
+ expect(mockWithEntitlementsPlist).toHaveBeenCalledTimes(1)
75
+ expect(mockWithInfoPlist).toHaveBeenCalledTimes(1)
76
+ expect(result).toEqual({
77
+ modResults: {
78
+ 'com.apple.developer.in-app-payments': ['merchant.com.test'],
79
+ ReactNativePayApplePayMerchantIdentifiers: ['merchant.com.test'],
80
+ },
81
+ })
82
+ })
83
+ })