@gmisoftware/react-native-pay 0.0.12 → 0.0.14

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 +45 -12
  3. package/android/src/main/java/com/margelo/nitro/pay/HybridPaymentHandler.kt +27 -8
  4. package/ios/HybridPaymentHandler.swift +116 -9
  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 +21 -4
  154. package/src/hooks/__tests__/usePaymentCheckout.integration.test.ts +248 -0
  155. package/src/hooks/usePaymentCheckout.ts +68 -9
  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 +127 -0
  162. package/src/utils/paymentHelpers.ts +30 -15
@@ -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
+ })
@@ -0,0 +1,66 @@
1
+ const mockAddMetaDataItemToMainApplication = jest.fn()
2
+ const mockGetMainApplicationOrThrow = jest.fn()
3
+ const mockRemoveMetaDataItemFromMainApplication = jest.fn()
4
+ const mockWithAndroidManifest = jest.fn(
5
+ (config: Record<string, unknown>, action: (input: any) => any) =>
6
+ action({ modResults: config })
7
+ )
8
+
9
+ jest.mock('expo/config-plugins', () => ({
10
+ AndroidConfig: {
11
+ Manifest: {
12
+ addMetaDataItemToMainApplication: (...args: any[]) =>
13
+ mockAddMetaDataItemToMainApplication(...args),
14
+ getMainApplicationOrThrow: (...args: any[]) =>
15
+ mockGetMainApplicationOrThrow(...args),
16
+ removeMetaDataItemFromMainApplication: (...args: any[]) =>
17
+ mockRemoveMetaDataItemFromMainApplication(...args),
18
+ },
19
+ },
20
+ withAndroidManifest: (config: any, action: (input: any) => any) =>
21
+ mockWithAndroidManifest(config, action),
22
+ }))
23
+
24
+ import { setGooglePayMetaData, withGooglePay } from '../withGooglePay'
25
+
26
+ describe('withGooglePay', () => {
27
+ beforeEach(() => {
28
+ mockGetMainApplicationOrThrow.mockReturnValue({ name: 'main-app' })
29
+ })
30
+
31
+ it('enables Google Pay metadata when enabled=true', () => {
32
+ const manifest = { application: [] }
33
+ const result = setGooglePayMetaData(true, manifest as any)
34
+
35
+ expect(result).toBe(manifest)
36
+ expect(mockGetMainApplicationOrThrow).toHaveBeenCalledWith(manifest)
37
+ expect(mockAddMetaDataItemToMainApplication).toHaveBeenCalledWith(
38
+ { name: 'main-app' },
39
+ 'com.google.android.gms.wallet.api.enabled',
40
+ 'true'
41
+ )
42
+ expect(mockRemoveMetaDataItemFromMainApplication).not.toHaveBeenCalled()
43
+ })
44
+
45
+ it('removes Google Pay metadata when enabled=false', () => {
46
+ const manifest = { application: [] }
47
+ const result = setGooglePayMetaData(false, manifest as any)
48
+
49
+ expect(result).toBe(manifest)
50
+ expect(mockGetMainApplicationOrThrow).toHaveBeenCalledWith(manifest)
51
+ expect(mockRemoveMetaDataItemFromMainApplication).toHaveBeenCalledWith(
52
+ { name: 'main-app' },
53
+ 'com.google.android.gms.wallet.api.enabled'
54
+ )
55
+ expect(mockAddMetaDataItemToMainApplication).not.toHaveBeenCalled()
56
+ })
57
+
58
+ it('wires withAndroidManifest and applies metadata by plugin prop', () => {
59
+ const config = { name: 'app' }
60
+ const result = withGooglePay(config as any, { enableGooglePay: true })
61
+
62
+ expect(mockWithAndroidManifest).toHaveBeenCalledTimes(1)
63
+ expect(result).toEqual({ modResults: { name: 'app' } })
64
+ expect(mockAddMetaDataItemToMainApplication).toHaveBeenCalled()
65
+ })
66
+ })
@@ -1,13 +1,18 @@
1
- import { withEntitlementsPlist, type ConfigPlugin } from 'expo/config-plugins'
1
+ import {
2
+ withEntitlementsPlist,
3
+ withInfoPlist,
4
+ type ConfigPlugin,
5
+ } from 'expo/config-plugins'
2
6
  import type { ReactNativePayPluginProps } from './type'
3
7
 
8
+ const APPLE_PAY_ENTITLEMENT_KEY = 'com.apple.developer.in-app-payments'
9
+ const APPLE_PAY_INFO_PLIST_KEY = 'ReactNativePayApplePayMerchantIdentifiers'
10
+
4
11
  export function setApplePayEntitlement(
5
12
  merchantIdentifiers: string | string[],
6
13
  entitlements: Record<string, any>
7
14
  ): Record<string, any> {
8
- const key = 'com.apple.developer.in-app-payments'
9
-
10
- const merchants: string[] = entitlements[key] ?? []
15
+ const merchants: string[] = entitlements[APPLE_PAY_ENTITLEMENT_KEY] ?? []
11
16
 
12
17
  if (!Array.isArray(merchantIdentifiers)) {
13
18
  merchantIdentifiers = [merchantIdentifiers]
@@ -20,11 +25,26 @@ export function setApplePayEntitlement(
20
25
  }
21
26
 
22
27
  if (merchants.length) {
23
- entitlements[key] = merchants
28
+ entitlements[APPLE_PAY_ENTITLEMENT_KEY] = merchants
24
29
  }
25
30
  return entitlements
26
31
  }
27
32
 
33
+ export function setApplePayMerchantIdentifiersInInfoPlist(
34
+ merchantIdentifiers: string | string[],
35
+ infoPlist: Record<string, any>
36
+ ): Record<string, any> {
37
+ const merchants: string[] = Array.isArray(merchantIdentifiers)
38
+ ? merchantIdentifiers.filter(Boolean)
39
+ : [merchantIdentifiers].filter(Boolean)
40
+
41
+ if (merchants.length) {
42
+ infoPlist[APPLE_PAY_INFO_PLIST_KEY] = [...new Set(merchants)]
43
+ }
44
+
45
+ return infoPlist
46
+ }
47
+
28
48
  export const withApplePay: ConfigPlugin<ReactNativePayPluginProps> = (
29
49
  expoConfig,
30
50
  { merchantIdentifier }
@@ -34,11 +54,19 @@ export const withApplePay: ConfigPlugin<ReactNativePayPluginProps> = (
34
54
  return expoConfig
35
55
  }
36
56
 
37
- return withEntitlementsPlist(expoConfig, (config) => {
57
+ const withEntitlements = withEntitlementsPlist(expoConfig, (config) => {
38
58
  config.modResults = setApplePayEntitlement(
39
59
  merchantIdentifier,
40
60
  config.modResults
41
61
  )
42
62
  return config
43
63
  })
64
+
65
+ return withInfoPlist(withEntitlements, (config) => {
66
+ config.modResults = setApplePayMerchantIdentifiersInInfoPlist(
67
+ merchantIdentifier,
68
+ config.modResults
69
+ )
70
+ return config
71
+ })
44
72
  }
@@ -72,7 +72,9 @@ export interface PaymentToken {
72
72
  paymentData: string // Base64 encoded Data from PKPaymentToken
73
73
  }
74
74
  export interface PaymentRequest {
75
- merchantIdentifier: string
75
+ // Optional Apple Pay override for apps with multiple configured merchant IDs.
76
+ // When omitted, iOS resolves the first configured entitlement automatically.
77
+ applePayMerchantIdentifier?: string
76
78
  merchantName?: string
77
79
  countryCode: string
78
80
  currencyCode: string
@@ -84,6 +86,7 @@ export interface PaymentRequest {
84
86
  billingContactRequired?: boolean
85
87
  shippingContactRequired?: boolean
86
88
  // Google Pay specific configuration (Android only)
89
+ googlePayMerchantId?: string
87
90
  googlePayEnvironment?: GooglePayEnvironment
88
91
  googlePayGateway?: string
89
92
  googlePayGatewayMerchantId?: string
@@ -0,0 +1,127 @@
1
+ import {
2
+ CommonNetworks,
3
+ calculateTotal,
4
+ createPaymentItem,
5
+ createPaymentRequest,
6
+ formatAmount,
7
+ formatNetworkName,
8
+ isNetworkSupported,
9
+ parseAmount,
10
+ sanitizePaymentRequest,
11
+ } from '../paymentHelpers'
12
+
13
+ describe('paymentHelpers', () => {
14
+ it('creates payment items with default and explicit type', () => {
15
+ expect(createPaymentItem('Coffee', 4.99)).toEqual({
16
+ label: 'Coffee',
17
+ amount: 4.99,
18
+ type: 'final',
19
+ })
20
+ expect(createPaymentItem('Shipping', 2.5, 'pending')).toEqual({
21
+ label: 'Shipping',
22
+ amount: 2.5,
23
+ type: 'pending',
24
+ })
25
+ })
26
+
27
+ it('calculates totals from line items', () => {
28
+ expect(
29
+ calculateTotal([
30
+ createPaymentItem('Product', 10),
31
+ createPaymentItem('Tax', 2.15),
32
+ createPaymentItem('Shipping', 3.35),
33
+ ])
34
+ ).toBeCloseTo(15.5)
35
+ })
36
+
37
+ it('creates payment requests with sane defaults', () => {
38
+ const request = createPaymentRequest({
39
+ amount: 19.99,
40
+ label: 'Pro Plan',
41
+ })
42
+
43
+ expect(request).toEqual({
44
+ countryCode: 'US',
45
+ currencyCode: 'USD',
46
+ paymentItems: [{ label: 'Pro Plan', amount: 19.99, type: 'final' }],
47
+ supportedNetworks: [
48
+ CommonNetworks.VISA,
49
+ CommonNetworks.MASTERCARD,
50
+ CommonNetworks.AMEX,
51
+ CommonNetworks.DISCOVER,
52
+ ],
53
+ merchantCapabilities: ['3DS'],
54
+ })
55
+ })
56
+
57
+ it('allows overriding defaults in payment requests', () => {
58
+ const request = createPaymentRequest({
59
+ amount: 39.99,
60
+ label: 'Deluxe',
61
+ countryCode: 'PL',
62
+ currencyCode: 'PLN',
63
+ supportedNetworks: ['visa'],
64
+ merchantCapabilities: ['EMV'],
65
+ merchantName: 'My Store',
66
+ applePayMerchantIdentifier: 'merchant.com.apple.override',
67
+ googlePayMerchantId: 'google-pay-merchant-id',
68
+ })
69
+
70
+ expect(request.countryCode).toBe('PL')
71
+ expect(request.currencyCode).toBe('PLN')
72
+ expect(request.supportedNetworks).toEqual(['visa'])
73
+ expect(request.merchantCapabilities).toEqual(['EMV'])
74
+ expect(request.merchantName).toBe('My Store')
75
+ expect(request.applePayMerchantIdentifier).toBe(
76
+ 'merchant.com.apple.override'
77
+ )
78
+ expect(request.googlePayMerchantId).toBe('google-pay-merchant-id')
79
+ })
80
+
81
+ it('omits undefined optional fields from created payment requests', () => {
82
+ const request = createPaymentRequest({
83
+ amount: 10,
84
+ label: 'Order',
85
+ merchantName: undefined,
86
+ googlePayMerchantId: undefined,
87
+ googlePayGateway: 'stripe',
88
+ })
89
+
90
+ expect(request).not.toHaveProperty('merchantName')
91
+ expect(request).not.toHaveProperty('googlePayMerchantId')
92
+ expect(request.googlePayGateway).toBe('stripe')
93
+ })
94
+
95
+ it('sanitizes payment requests before native bridging', () => {
96
+ const request = sanitizePaymentRequest({
97
+ countryCode: 'PL',
98
+ currencyCode: 'PLN',
99
+ paymentItems: [{ label: 'Order', amount: 10, type: 'final' }],
100
+ supportedNetworks: ['visa'],
101
+ merchantCapabilities: ['3DS'],
102
+ merchantName: undefined,
103
+ googlePayGateway: 'przelewy24',
104
+ googlePayGatewayMerchantId: undefined,
105
+ } as any)
106
+
107
+ expect(request).not.toHaveProperty('merchantName')
108
+ expect(request).not.toHaveProperty('googlePayGatewayMerchantId')
109
+ expect(request.googlePayGateway).toBe('przelewy24')
110
+ })
111
+
112
+ it('formats and parses amount values', () => {
113
+ expect(formatAmount(29.9)).toBe('29.90')
114
+ expect(parseAmount('29.90')).toBeCloseTo(29.9)
115
+ })
116
+
117
+ it('checks network support using case-insensitive matching', () => {
118
+ expect(isNetworkSupported('AMEX', ['visa', 'amex'])).toBe(true)
119
+ expect(isNetworkSupported('discover', ['visa', 'mastercard'])).toBe(false)
120
+ })
121
+
122
+ it('formats known payment networks for display', () => {
123
+ expect(formatNetworkName('visa')).toBe('Visa')
124
+ expect(formatNetworkName('amex')).toBe('American Express')
125
+ expect(formatNetworkName('privateLabel')).toBe('Private Label')
126
+ })
127
+ })
@@ -11,7 +11,6 @@
11
11
  * import { createPaymentRequest, calculateTotal } from 'react-native-pay'
12
12
  *
13
13
  * const request = createPaymentRequest({
14
- * merchantIdentifier: 'merchant.com.example',
15
14
  * amount: 29.99,
16
15
  * label: 'Coffee Subscription'
17
16
  * })
@@ -30,6 +29,31 @@ export const CommonNetworks = {
30
29
  DISCOVER: 'discover',
31
30
  } as const
32
31
 
32
+ const DEFAULT_SUPPORTED_NETWORKS: PaymentRequest['supportedNetworks'] = [
33
+ CommonNetworks.VISA,
34
+ CommonNetworks.MASTERCARD,
35
+ CommonNetworks.AMEX,
36
+ CommonNetworks.DISCOVER,
37
+ ]
38
+
39
+ const DEFAULT_MERCHANT_CAPABILITIES: PaymentRequest['merchantCapabilities'] = [
40
+ '3DS',
41
+ ]
42
+
43
+ function omitUndefinedProperties<T extends object>(value: T): T {
44
+ return Object.fromEntries(
45
+ Object.entries(value as Record<string, unknown>).filter(
46
+ ([, entryValue]) => entryValue !== undefined
47
+ )
48
+ ) as T
49
+ }
50
+
51
+ export function sanitizePaymentRequest(
52
+ request: PaymentRequest
53
+ ): PaymentRequest {
54
+ return omitUndefinedProperties(request)
55
+ }
56
+
33
57
  /**
34
58
  * Creates a payment item with the specified label, amount, and type.
35
59
  *
@@ -80,13 +104,12 @@ export function calculateTotal(items: PaymentItem[]): number {
80
104
  * - supportedNetworks: ['visa', 'mastercard', 'amex', 'discover']
81
105
  * - merchantCapabilities: ['3DS']
82
106
  *
83
- * @param options - Payment request options (merchantIdentifier, amount, label required)
107
+ * @param options - Payment request options (amount and label required)
84
108
  * @returns Complete PaymentRequest object
85
109
  *
86
110
  * @example
87
111
  * ```typescript
88
112
  * const request = createPaymentRequest({
89
- * merchantIdentifier: 'merchant.com.example',
90
113
  * amount: 29.99,
91
114
  * label: 'Coffee Subscription',
92
115
  * countryCode: 'CA', // override default
@@ -96,36 +119,28 @@ export function calculateTotal(items: PaymentItem[]): number {
96
119
  */
97
120
  export function createPaymentRequest(
98
121
  options: Partial<PaymentRequest> & {
99
- merchantIdentifier: string
100
122
  amount: number
101
123
  label: string
102
124
  }
103
125
  ): PaymentRequest {
104
126
  const {
105
- merchantIdentifier,
106
127
  amount,
107
128
  label,
108
129
  countryCode = 'US',
109
130
  currencyCode = 'USD',
110
- supportedNetworks = [
111
- CommonNetworks.VISA,
112
- CommonNetworks.MASTERCARD,
113
- CommonNetworks.AMEX,
114
- CommonNetworks.DISCOVER,
115
- ],
116
- merchantCapabilities = ['3DS'],
131
+ supportedNetworks = DEFAULT_SUPPORTED_NETWORKS,
132
+ merchantCapabilities = DEFAULT_MERCHANT_CAPABILITIES,
117
133
  ...rest
118
134
  } = options
119
135
 
120
- return {
121
- merchantIdentifier,
136
+ return sanitizePaymentRequest({
122
137
  countryCode,
123
138
  currencyCode,
124
139
  paymentItems: [createPaymentItem(label, amount, 'final')],
125
140
  supportedNetworks,
126
141
  merchantCapabilities,
127
142
  ...rest,
128
- }
143
+ } as PaymentRequest)
129
144
  }
130
145
 
131
146
  /**