@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.
- package/README.md +223 -220
- package/android/src/main/java/com/margelo/nitro/pay/GooglePayRequestBuilder.kt +45 -12
- package/android/src/main/java/com/margelo/nitro/pay/HybridPaymentHandler.kt +27 -8
- package/ios/HybridPaymentHandler.swift +116 -9
- package/lib/hooks/__tests__/usePaymentCheckout.integration.test.d.ts +1 -0
- package/lib/hooks/__tests__/usePaymentCheckout.integration.test.js +191 -0
- package/lib/hooks/usePaymentCheckout.d.ts +47 -3
- package/lib/hooks/usePaymentCheckout.js +6 -4
- package/lib/plugin/__tests__/index.test.d.ts +1 -0
- package/lib/plugin/__tests__/index.test.js +33 -0
- package/lib/plugin/__tests__/withApplePay.test.d.ts +1 -0
- package/lib/plugin/__tests__/withApplePay.test.js +58 -0
- package/lib/plugin/__tests__/withGooglePay.test.d.ts +1 -0
- package/lib/plugin/__tests__/withGooglePay.test.js +45 -0
- package/lib/plugin/withApplePay.d.ts +1 -0
- package/lib/plugin/withApplePay.js +19 -4
- package/lib/types/Payment.d.ts +2 -1
- package/lib/utils/__tests__/paymentHelpers.test.d.ts +1 -0
- package/lib/utils/__tests__/paymentHelpers.test.js +75 -0
- package/lib/utils/paymentHelpers.d.ts +1 -4
- package/lib/utils/paymentHelpers.js +2 -5
- package/nitrogen/generated/android/NitroPay+autolinking.cmake +1 -1
- package/nitrogen/generated/android/NitroPay+autolinking.gradle +1 -1
- package/nitrogen/generated/android/NitroPayOnLoad.cpp +1 -1
- package/nitrogen/generated/android/NitroPayOnLoad.hpp +1 -1
- package/nitrogen/generated/android/c++/JCNContact.hpp +1 -1
- package/nitrogen/generated/android/c++/JCNContactType.hpp +1 -1
- package/nitrogen/generated/android/c++/JCNLabeledEmailAddress.hpp +1 -1
- package/nitrogen/generated/android/c++/JCNLabeledPhoneNumber.hpp +1 -1
- package/nitrogen/generated/android/c++/JCNLabeledPostalAddress.hpp +1 -1
- package/nitrogen/generated/android/c++/JCNPhoneNumber.hpp +1 -1
- package/nitrogen/generated/android/c++/JCNPostalAddress.hpp +1 -1
- package/nitrogen/generated/android/c++/JFunc_void.hpp +1 -1
- package/nitrogen/generated/android/c++/JGooglePayButtonTheme.hpp +1 -1
- package/nitrogen/generated/android/c++/JGooglePayButtonType.hpp +1 -1
- package/nitrogen/generated/android/c++/JGooglePayEnvironment.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridGooglePayButtonSpec.cpp +1 -1
- package/nitrogen/generated/android/c++/JHybridGooglePayButtonSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JHybridPaymentHandlerSpec.cpp +1 -1
- package/nitrogen/generated/android/c++/JHybridPaymentHandlerSpec.hpp +1 -1
- package/nitrogen/generated/android/c++/JPKSecureElementPass.hpp +1 -1
- package/nitrogen/generated/android/c++/JPassActivationState.hpp +1 -1
- package/nitrogen/generated/android/c++/JPayServiceStatus.hpp +1 -1
- package/nitrogen/generated/android/c++/JPaymentItem.hpp +1 -1
- package/nitrogen/generated/android/c++/JPaymentItemType.hpp +1 -1
- package/nitrogen/generated/android/c++/JPaymentMethod.hpp +1 -1
- package/nitrogen/generated/android/c++/JPaymentMethodType.hpp +1 -1
- package/nitrogen/generated/android/c++/JPaymentNetwork.hpp +1 -1
- package/nitrogen/generated/android/c++/JPaymentRequest.hpp +10 -6
- package/nitrogen/generated/android/c++/JPaymentResult.hpp +1 -1
- package/nitrogen/generated/android/c++/JPaymentToken.hpp +1 -1
- package/nitrogen/generated/android/c++/views/JHybridGooglePayButtonStateUpdater.cpp +1 -1
- package/nitrogen/generated/android/c++/views/JHybridGooglePayButtonStateUpdater.hpp +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNContact.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNContactType.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNLabeledEmailAddress.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNLabeledPhoneNumber.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNLabeledPostalAddress.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNPhoneNumber.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/CNPostalAddress.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/Func_void.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/GooglePayButtonTheme.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/GooglePayButtonType.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/GooglePayEnvironment.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/HybridGooglePayButtonSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/HybridPaymentHandlerSpec.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/NitroPayOnLoad.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PKSecureElementPass.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PassActivationState.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PayServiceStatus.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentItem.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentItemType.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentMethod.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentMethodType.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentNetwork.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentRequest.kt +7 -4
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentResult.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/PaymentToken.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/views/HybridGooglePayButtonManager.kt +1 -1
- package/nitrogen/generated/android/kotlin/com/margelo/nitro/pay/views/HybridGooglePayButtonStateUpdater.kt +1 -1
- package/nitrogen/generated/ios/NitroPay+autolinking.rb +1 -1
- package/nitrogen/generated/ios/NitroPay-Swift-Cxx-Bridge.cpp +1 -1
- package/nitrogen/generated/ios/NitroPay-Swift-Cxx-Bridge.hpp +1 -1
- package/nitrogen/generated/ios/NitroPay-Swift-Cxx-Umbrella.hpp +1 -1
- package/nitrogen/generated/ios/NitroPayAutolinking.mm +1 -1
- package/nitrogen/generated/ios/NitroPayAutolinking.swift +1 -1
- package/nitrogen/generated/ios/c++/HybridApplePayButtonSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridApplePayButtonSpecSwift.hpp +1 -1
- package/nitrogen/generated/ios/c++/HybridPaymentHandlerSpecSwift.cpp +1 -1
- package/nitrogen/generated/ios/c++/HybridPaymentHandlerSpecSwift.hpp +1 -1
- package/nitrogen/generated/ios/c++/views/HybridApplePayButtonComponent.mm +1 -1
- package/nitrogen/generated/ios/swift/ApplePayButtonStyle.swift +1 -1
- package/nitrogen/generated/ios/swift/ApplePayButtonType.swift +1 -1
- package/nitrogen/generated/ios/swift/CNContact.swift +1 -1
- package/nitrogen/generated/ios/swift/CNContactType.swift +1 -1
- package/nitrogen/generated/ios/swift/CNLabeledEmailAddress.swift +1 -1
- package/nitrogen/generated/ios/swift/CNLabeledPhoneNumber.swift +1 -1
- package/nitrogen/generated/ios/swift/CNLabeledPostalAddress.swift +1 -1
- package/nitrogen/generated/ios/swift/CNPhoneNumber.swift +1 -1
- package/nitrogen/generated/ios/swift/CNPostalAddress.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_PaymentResult.swift +1 -1
- package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -1
- package/nitrogen/generated/ios/swift/GooglePayEnvironment.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridApplePayButtonSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridApplePayButtonSpec_cxx.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridPaymentHandlerSpec.swift +1 -1
- package/nitrogen/generated/ios/swift/HybridPaymentHandlerSpec_cxx.swift +1 -1
- package/nitrogen/generated/ios/swift/PKSecureElementPass.swift +1 -1
- package/nitrogen/generated/ios/swift/PassActivationState.swift +1 -1
- package/nitrogen/generated/ios/swift/PayServiceStatus.swift +1 -1
- package/nitrogen/generated/ios/swift/PaymentItem.swift +1 -1
- package/nitrogen/generated/ios/swift/PaymentItemType.swift +1 -1
- package/nitrogen/generated/ios/swift/PaymentMethod.swift +1 -1
- package/nitrogen/generated/ios/swift/PaymentMethodType.swift +1 -1
- package/nitrogen/generated/ios/swift/PaymentNetwork.swift +1 -1
- package/nitrogen/generated/ios/swift/PaymentRequest.swift +55 -6
- package/nitrogen/generated/ios/swift/PaymentResult.swift +1 -1
- package/nitrogen/generated/ios/swift/PaymentToken.swift +1 -1
- package/nitrogen/generated/shared/c++/ApplePayButtonStyle.hpp +1 -1
- package/nitrogen/generated/shared/c++/ApplePayButtonType.hpp +1 -1
- package/nitrogen/generated/shared/c++/CNContact.hpp +1 -1
- package/nitrogen/generated/shared/c++/CNContactType.hpp +1 -1
- package/nitrogen/generated/shared/c++/CNLabeledEmailAddress.hpp +1 -1
- package/nitrogen/generated/shared/c++/CNLabeledPhoneNumber.hpp +1 -1
- package/nitrogen/generated/shared/c++/CNLabeledPostalAddress.hpp +1 -1
- package/nitrogen/generated/shared/c++/CNPhoneNumber.hpp +1 -1
- package/nitrogen/generated/shared/c++/CNPostalAddress.hpp +1 -1
- package/nitrogen/generated/shared/c++/GooglePayButtonTheme.hpp +1 -1
- package/nitrogen/generated/shared/c++/GooglePayButtonType.hpp +1 -1
- package/nitrogen/generated/shared/c++/GooglePayEnvironment.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridApplePayButtonSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridApplePayButtonSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridGooglePayButtonSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridGooglePayButtonSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/HybridPaymentHandlerSpec.cpp +1 -1
- package/nitrogen/generated/shared/c++/HybridPaymentHandlerSpec.hpp +1 -1
- package/nitrogen/generated/shared/c++/PKSecureElementPass.hpp +1 -1
- package/nitrogen/generated/shared/c++/PassActivationState.hpp +1 -1
- package/nitrogen/generated/shared/c++/PayServiceStatus.hpp +1 -1
- package/nitrogen/generated/shared/c++/PaymentItem.hpp +1 -1
- package/nitrogen/generated/shared/c++/PaymentItemType.hpp +1 -1
- package/nitrogen/generated/shared/c++/PaymentMethod.hpp +1 -1
- package/nitrogen/generated/shared/c++/PaymentMethodType.hpp +1 -1
- package/nitrogen/generated/shared/c++/PaymentNetwork.hpp +1 -1
- package/nitrogen/generated/shared/c++/PaymentRequest.hpp +10 -6
- package/nitrogen/generated/shared/c++/PaymentResult.hpp +1 -1
- package/nitrogen/generated/shared/c++/PaymentToken.hpp +1 -1
- package/nitrogen/generated/shared/c++/views/HybridApplePayButtonComponent.cpp +1 -1
- package/nitrogen/generated/shared/c++/views/HybridApplePayButtonComponent.hpp +1 -1
- package/nitrogen/generated/shared/c++/views/HybridGooglePayButtonComponent.cpp +1 -1
- package/nitrogen/generated/shared/c++/views/HybridGooglePayButtonComponent.hpp +1 -1
- package/package.json +21 -4
- package/src/hooks/__tests__/usePaymentCheckout.integration.test.ts +248 -0
- package/src/hooks/usePaymentCheckout.ts +68 -9
- package/src/plugin/__tests__/index.test.ts +37 -0
- package/src/plugin/__tests__/withApplePay.test.ts +83 -0
- package/src/plugin/__tests__/withGooglePay.test.ts +66 -0
- package/src/plugin/withApplePay.ts +34 -6
- package/src/types/Payment.ts +4 -1
- package/src/utils/__tests__/paymentHelpers.test.ts +127 -0
- 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 {
|
|
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
|
|
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[
|
|
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
|
-
|
|
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
|
}
|
package/src/types/Payment.ts
CHANGED
|
@@ -72,7 +72,9 @@ export interface PaymentToken {
|
|
|
72
72
|
paymentData: string // Base64 encoded Data from PKPaymentToken
|
|
73
73
|
}
|
|
74
74
|
export interface PaymentRequest {
|
|
75
|
-
|
|
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 (
|
|
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
|
-
|
|
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
|
/**
|