framepayments-react-native 2.2.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FrameReactNative.podspec +44 -0
- package/Package.swift +47 -0
- package/README.md +7 -17
- package/android/build.gradle +9 -3
- package/android/src/main/java/com/framepayments/reactnativeframe/FrameSDKModule.kt +7 -6
- package/ios/FramePreloader.h +23 -0
- package/ios/FrameSDKBridge.m +9 -9
- package/ios/FrameSDKBridge.swift +47 -35
- package/lib/native.d.ts.map +1 -1
- package/lib/native.js +14 -8
- package/package.json +8 -2
- package/src/__tests__/native.test.ts +5 -0
- package/src/native.ts +20 -14
- package/ios/FrameReactNative.podspec +0 -32
- package/lib/__tests__/native.test.d.ts +0 -32
- package/lib/__tests__/native.test.d.ts.map +0 -1
- package/lib/__tests__/native.test.js +0 -101
- package/lib/components/FrameApplePayButton.d.ts +0 -30
- package/lib/components/FrameApplePayButton.d.ts.map +0 -1
- package/lib/components/FrameApplePayButton.js +0 -42
- package/lib/components/FrameGooglePayButton.d.ts +0 -28
- package/lib/components/FrameGooglePayButton.d.ts.map +0 -1
- package/lib/components/FrameGooglePayButton.js +0 -24
- package/lib/components/index.d.ts +0 -5
- package/lib/components/index.d.ts.map +0 -1
- package/lib/components/index.js +0 -2
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'FrameReactNative'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.homepage = package['homepage']
|
|
10
|
+
s.license = package['license']
|
|
11
|
+
s.authors = package['author']
|
|
12
|
+
s.platforms = { :ios => '17.0' }
|
|
13
|
+
s.source = { :git => package['repository']['url'], :tag => "#{s.version}" }
|
|
14
|
+
s.source_files = 'ios/**/*.{h,m,mm,swift}'
|
|
15
|
+
s.requires_arc = true
|
|
16
|
+
|
|
17
|
+
# static_framework exposes the pod's generated `FrameReactNative-Swift.h` to
|
|
18
|
+
# consumers — required so host AppDelegate.mm can `#import <FrameReactNative/FrameReactNative-Swift.h>`
|
|
19
|
+
# to reach `FramePreloader`.
|
|
20
|
+
s.static_framework = true
|
|
21
|
+
|
|
22
|
+
s.dependency 'React-Core'
|
|
23
|
+
|
|
24
|
+
# Autolink Frame-iOS (SPM-only) via RN 0.81+'s Podfile SPM hook. spm.rb injects
|
|
25
|
+
# XCRemoteSwiftPackageReferences into Pods.xcodeproj at react_native_post_install;
|
|
26
|
+
# consumers get Frame-iOS + Frame-Onboarding resolved by `pod install` alone.
|
|
27
|
+
#
|
|
28
|
+
# The respond_to? guards use `include_private: true` because both helpers are
|
|
29
|
+
# top-level Ruby `def`s in react_native_pods.rb — i.e. private methods of Object.
|
|
30
|
+
# The guards exist not for RN-version compatibility (peer dep is >= 0.81) but
|
|
31
|
+
# because the RN CLI loads this podspec STANDALONE for autolinking discovery,
|
|
32
|
+
# outside the Podfile's `require 'react_native_pods.rb'` context where the
|
|
33
|
+
# helpers are defined. Without guards, `npx react-native config` would crash
|
|
34
|
+
# and return `ios: null`, breaking `use_native_modules!`.
|
|
35
|
+
if respond_to?(:spm_dependency, true)
|
|
36
|
+
spm_dependency(s,
|
|
37
|
+
url: 'https://github.com/Frame-Payments/frame-ios',
|
|
38
|
+
requirement: { kind: 'upToNextMajorVersion', minimumVersion: package['frameNativeVersions']['ios'] },
|
|
39
|
+
products: ['Frame-iOS', 'Frame-Onboarding']
|
|
40
|
+
)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
install_modules_dependencies(s) if respond_to?(:install_modules_dependencies, true)
|
|
44
|
+
end
|
package/Package.swift
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// swift-tools-version: 5.9
|
|
2
|
+
// Distribution paths:
|
|
3
|
+
// • Pure-SPM consumers: add framepayments-react-native via Swift Package Manager;
|
|
4
|
+
// frame-ios resolves transitively from this manifest.
|
|
5
|
+
// • CocoaPods consumers (the common RN setup): the podspec at
|
|
6
|
+
// ios/FrameReactNative.podspec declares the same frame-ios SPM dependency via
|
|
7
|
+
// RN 0.81+'s `spm_dependency` Podfile hook, so `pod install` resolves it
|
|
8
|
+
// automatically — no Xcode "Add Package Dependencies" step required.
|
|
9
|
+
//
|
|
10
|
+
// IMPORTANT: keep the frame-ios version below in sync with
|
|
11
|
+
// package.json:frameNativeVersions.ios. Swift Package manifests cannot read JSON,
|
|
12
|
+
// so this is the one duplicated version pin. See MAINTAINING.md.
|
|
13
|
+
|
|
14
|
+
import PackageDescription
|
|
15
|
+
|
|
16
|
+
let package = Package(
|
|
17
|
+
name: "framepayments-react-native",
|
|
18
|
+
platforms: [
|
|
19
|
+
.iOS(.v17)
|
|
20
|
+
],
|
|
21
|
+
products: [
|
|
22
|
+
.library(
|
|
23
|
+
name: "framepayments-react-native",
|
|
24
|
+
targets: ["framepayments-react-native"]
|
|
25
|
+
)
|
|
26
|
+
],
|
|
27
|
+
dependencies: [
|
|
28
|
+
.package(
|
|
29
|
+
url: "https://github.com/Frame-Payments/frame-ios",
|
|
30
|
+
from: "2.2.2" // Keep in sync with package.json:frameNativeVersions.ios
|
|
31
|
+
)
|
|
32
|
+
],
|
|
33
|
+
targets: [
|
|
34
|
+
.target(
|
|
35
|
+
name: "framepayments-react-native",
|
|
36
|
+
dependencies: [
|
|
37
|
+
.product(name: "Frame-iOS", package: "frame-ios"),
|
|
38
|
+
.product(name: "Frame-Onboarding", package: "frame-ios")
|
|
39
|
+
],
|
|
40
|
+
path: "ios",
|
|
41
|
+
publicHeadersPath: ".",
|
|
42
|
+
cSettings: [
|
|
43
|
+
.headerSearchPath(".")
|
|
44
|
+
]
|
|
45
|
+
)
|
|
46
|
+
]
|
|
47
|
+
)
|
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ React Native SDK for [Frame Payments](https://framepayments.com). Bridges the na
|
|
|
4
4
|
|
|
5
5
|
## Requirements
|
|
6
6
|
|
|
7
|
-
- React Native >= 0.
|
|
7
|
+
- React Native >= 0.81 (autolinking on iOS depends on RN's `spm_dependency` Podfile hook, which stabilized in 0.81)
|
|
8
8
|
- iOS 17+ / Android 8.0+ (API 26+)
|
|
9
9
|
- A [Frame](https://framepayments.com) account and API key
|
|
10
10
|
|
|
@@ -18,19 +18,13 @@ yarn add framepayments-react-native
|
|
|
18
18
|
|
|
19
19
|
### iOS setup
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
The React Native SDK's native layer depends on the Frame iOS SDK, which must be added manually via SPM — CocoaPods cannot pull it in automatically.
|
|
24
|
-
|
|
25
|
-
In Xcode: **File → Add Package Dependencies**, enter:
|
|
26
|
-
|
|
27
|
-
```
|
|
28
|
-
https://github.com/Frame-Payments/frame-ios
|
|
21
|
+
```bash
|
|
22
|
+
cd ios && pod install && cd ..
|
|
29
23
|
```
|
|
30
24
|
|
|
31
|
-
|
|
25
|
+
That's it. `pod install` autolinks the React Native bridge **and** resolves the underlying Frame iOS SDK (Frame-iOS + Frame-Onboarding) via Swift Package Manager — no Xcode "Add Package Dependencies" step required.
|
|
32
26
|
|
|
33
|
-
####
|
|
27
|
+
#### Preload Frame on the main thread
|
|
34
28
|
|
|
35
29
|
Add this to your `AppDelegate.m` or `AppDelegate.mm` **before** `[super application:didFinishLaunchingWithOptions:]`:
|
|
36
30
|
|
|
@@ -48,15 +42,11 @@ This prevents the **"Helpers are not supported by the default hub"** crash, whic
|
|
|
48
42
|
|
|
49
43
|
> If your app module name isn't the default (i.e., not matching the generated `-Swift.h` header), set `FRAME_SWIFT_HEADER=YourApp-Swift.h` in your target's **Preprocessor Macros** in Xcode build settings.
|
|
50
44
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
```bash
|
|
54
|
-
cd ios && pod install && cd ..
|
|
55
|
-
```
|
|
45
|
+
> Using Swift Package Manager directly instead of CocoaPods? The package's `Package.swift` resolves `frame-ios` transitively, so just add `framepayments-react-native` via **File → Add Package Dependencies** in Xcode.
|
|
56
46
|
|
|
57
47
|
### Android setup
|
|
58
48
|
|
|
59
|
-
No extra steps required. Autolinking handles the native module automatically.
|
|
49
|
+
No extra steps required. Autolinking handles the native module automatically and pulls in `com.framepayments:framesdk*` from Maven Central.
|
|
60
50
|
|
|
61
51
|
---
|
|
62
52
|
|
package/android/build.gradle
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import groovy.json.JsonSlurper
|
|
2
|
+
|
|
1
3
|
apply plugin: 'com.android.library'
|
|
2
4
|
apply plugin: 'kotlin-android'
|
|
3
5
|
apply plugin: 'org.jetbrains.kotlin.plugin.compose'
|
|
@@ -6,6 +8,10 @@ def safeExtGet(prop, fallback) {
|
|
|
6
8
|
rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
|
|
7
9
|
}
|
|
8
10
|
|
|
11
|
+
// Single source of truth for Frame native SDK versions — see package.json:frameNativeVersions.
|
|
12
|
+
def frameNativeVersions = new JsonSlurper().parse(file("$projectDir/../package.json")).frameNativeVersions
|
|
13
|
+
def frameAndroidVersion = frameNativeVersions.android
|
|
14
|
+
|
|
9
15
|
android {
|
|
10
16
|
namespace "com.framepayments.reactnativeframe"
|
|
11
17
|
compileSdk safeExtGet('compileSdkVersion', 36)
|
|
@@ -31,9 +37,9 @@ android {
|
|
|
31
37
|
dependencies {
|
|
32
38
|
implementation 'com.facebook.react:react-native:+'
|
|
33
39
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.0"
|
|
34
|
-
implementation
|
|
35
|
-
implementation
|
|
36
|
-
implementation
|
|
40
|
+
implementation "com.framepayments:framesdk:${frameAndroidVersion}"
|
|
41
|
+
implementation "com.framepayments:framesdk_ui:${frameAndroidVersion}"
|
|
42
|
+
implementation "com.framepayments:framesdk_onboarding:${frameAndroidVersion}"
|
|
37
43
|
// Required by FrameGooglePayButton (PaymentsClient, WalletConstants).
|
|
38
44
|
// framesdk_ui declares this as `implementation`, so it is not exposed transitively.
|
|
39
45
|
implementation 'com.google.android.gms:play-services-wallet:19.4.0'
|
|
@@ -7,9 +7,10 @@ import com.facebook.react.bridge.Promise
|
|
|
7
7
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
8
8
|
import com.facebook.react.bridge.ReactContextBaseJavaModule
|
|
9
9
|
import com.facebook.react.bridge.ReactMethod
|
|
10
|
+
import com.facebook.react.bridge.ReadableArray
|
|
11
|
+
import com.facebook.react.bridge.ReadableMap
|
|
10
12
|
import com.facebook.react.bridge.WritableNativeMap
|
|
11
13
|
import com.framepayments.framesdk.FrameNetworking
|
|
12
|
-
import org.json.JSONObject
|
|
13
14
|
|
|
14
15
|
class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
15
16
|
ReactContextBaseJavaModule(reactContext), ActivityEventListener {
|
|
@@ -35,7 +36,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
35
36
|
secretKey: String,
|
|
36
37
|
publishableKey: String,
|
|
37
38
|
debugMode: Boolean,
|
|
38
|
-
theme:
|
|
39
|
+
theme: ReadableMap?,
|
|
39
40
|
promise: Promise
|
|
40
41
|
) {
|
|
41
42
|
try {
|
|
@@ -69,7 +70,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
69
70
|
@ReactMethod
|
|
70
71
|
fun presentCart(
|
|
71
72
|
accountId: String?,
|
|
72
|
-
items:
|
|
73
|
+
items: ReadableArray,
|
|
73
74
|
shippingAmountInCents: Double,
|
|
74
75
|
promise: Promise
|
|
75
76
|
) {
|
|
@@ -137,7 +138,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
137
138
|
@ReactMethod
|
|
138
139
|
fun presentOnboarding(
|
|
139
140
|
accountId: String?,
|
|
140
|
-
capabilities:
|
|
141
|
+
capabilities: ReadableArray,
|
|
141
142
|
googlePayMerchantId: String?,
|
|
142
143
|
promise: Promise
|
|
143
144
|
) {
|
|
@@ -157,7 +158,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
|
|
160
|
-
private fun readableArrayToJson(items:
|
|
161
|
+
private fun readableArrayToJson(items: ReadableArray): String? {
|
|
161
162
|
val arr = org.json.JSONArray()
|
|
162
163
|
for (i in 0 until items.size()) {
|
|
163
164
|
val item = items.getMap(i) ?: return null
|
|
@@ -171,7 +172,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
171
172
|
return arr.toString()
|
|
172
173
|
}
|
|
173
174
|
|
|
174
|
-
private fun readableArrayToJsonArray(arr:
|
|
175
|
+
private fun readableArrayToJsonArray(arr: ReadableArray): String {
|
|
175
176
|
val jsonArr = org.json.JSONArray()
|
|
176
177
|
for (i in 0 until arr.size()) {
|
|
177
178
|
arr.getString(i)?.let { jsonArr.put(it) }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//
|
|
2
|
+
// FramePreloader.h
|
|
3
|
+
// FrameReactNative
|
|
4
|
+
//
|
|
5
|
+
// Public Obj-C interface for the Swift `FramePreloader` class. Lets consumers
|
|
6
|
+
// reach `+[FramePreloader preloadOnMainThread]` from AppDelegate.mm (or any
|
|
7
|
+
// .m/.mm file) via `#import "FramePreloader.h"`, without needing modules
|
|
8
|
+
// enabled in C++ context.
|
|
9
|
+
//
|
|
10
|
+
|
|
11
|
+
#import <Foundation/Foundation.h>
|
|
12
|
+
|
|
13
|
+
NS_ASSUME_NONNULL_BEGIN
|
|
14
|
+
|
|
15
|
+
@interface FramePreloader : NSObject
|
|
16
|
+
|
|
17
|
+
/// Call from AppDelegate before [super application:didFinishLaunchingWithOptions:].
|
|
18
|
+
/// Forces Frame (and its deps: Evervault, Sift) to load on the main thread.
|
|
19
|
+
+ (void)preloadOnMainThread;
|
|
20
|
+
|
|
21
|
+
@end
|
|
22
|
+
|
|
23
|
+
NS_ASSUME_NONNULL_END
|
package/ios/FrameSDKBridge.m
CHANGED
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
#import <React/RCTBridgeModule.h>
|
|
9
9
|
#import "FrameVCHelper.h"
|
|
10
10
|
|
|
11
|
-
// Import
|
|
12
|
-
//
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
#
|
|
16
|
-
#import "
|
|
17
|
-
#elif __has_include(<
|
|
18
|
-
#import <
|
|
11
|
+
// Import the FrameReactNative pod's auto-generated Swift header so this Obj-C
|
|
12
|
+
// file can reach the Swift `ObjCFrameSDKBridge` class. CocoaPods generates
|
|
13
|
+
// "FrameReactNative-Swift.h" from the pod's Swift sources during the pod's
|
|
14
|
+
// build phase.
|
|
15
|
+
#if __has_include("FrameReactNative-Swift.h")
|
|
16
|
+
#import "FrameReactNative-Swift.h"
|
|
17
|
+
#elif __has_include(<FrameReactNative/FrameReactNative-Swift.h>)
|
|
18
|
+
#import <FrameReactNative/FrameReactNative-Swift.h>
|
|
19
19
|
#else
|
|
20
|
-
#error "Swift
|
|
20
|
+
#error "FrameReactNative-Swift.h not found. The Frame React Native pod's Swift code did not generate its module header — check that pod install ran cleanly."
|
|
21
21
|
#endif
|
|
22
22
|
|
|
23
23
|
@interface FrameSDKModule : NSObject <RCTBridgeModule>
|
package/ios/FrameSDKBridge.swift
CHANGED
|
@@ -106,33 +106,30 @@ public class FrameSDKBridge: NSObject {
|
|
|
106
106
|
// MARK: - Private helpers
|
|
107
107
|
|
|
108
108
|
private func presentCheckoutOnMain(from top: UIViewController, accountId: String, amount: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
// Single dismiss delegate guards against double-resolve: the inner checkout
|
|
110
|
+
// calls `finish(.success)` with the transfer id; bare-dismiss (swipe-down
|
|
111
|
+
// without completing checkout) calls `finish(.cancel)`.
|
|
112
|
+
let delegate = CheckoutDismissDelegate(resolve: resolve, reject: reject)
|
|
113
|
+
let checkoutView = FrameCheckoutView(
|
|
111
114
|
accountId: accountId,
|
|
112
115
|
paymentAmount: amount,
|
|
113
|
-
checkoutCallback: { [weak
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
resolve(transferId)
|
|
119
|
-
} else {
|
|
120
|
-
reject("PAYMENT_FAILED", "Checkout did not produce a transfer id", nil)
|
|
121
|
-
}
|
|
116
|
+
checkoutCallback: { [weak top, delegate] success, transferId in
|
|
117
|
+
if success, let transferId {
|
|
118
|
+
delegate.finish(.success(transferId))
|
|
119
|
+
} else {
|
|
120
|
+
delegate.finish(.failure)
|
|
122
121
|
}
|
|
122
|
+
top?.dismiss(animated: true)
|
|
123
123
|
}
|
|
124
|
-
)
|
|
125
|
-
hosting
|
|
126
|
-
DispatchQueue.main.async {
|
|
127
|
-
reject("USER_CANCELED", "User dismissed checkout without completing payment", nil)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
124
|
+
)
|
|
125
|
+
let hosting = UIHostingController(rootView: checkoutView)
|
|
130
126
|
hosting.modalPresentationStyle = UIModalPresentationStyle.pageSheet
|
|
131
127
|
if let sheet = hosting.sheetPresentationController {
|
|
132
128
|
sheet.detents = [UISheetPresentationController.Detent.large()]
|
|
133
129
|
}
|
|
130
|
+
objc_setAssociatedObject(hosting, &checkoutDismissKey, delegate, .OBJC_ASSOCIATION_RETAIN)
|
|
134
131
|
top.present(hosting, animated: true) {
|
|
135
|
-
hosting.presentationController?.delegate =
|
|
132
|
+
hosting.presentationController?.delegate = delegate
|
|
136
133
|
}
|
|
137
134
|
}
|
|
138
135
|
|
|
@@ -237,30 +234,44 @@ public class FrameSDKBridge: NSObject {
|
|
|
237
234
|
}
|
|
238
235
|
}
|
|
239
236
|
|
|
240
|
-
// MARK: -
|
|
237
|
+
// MARK: - OnboardingHostingController
|
|
241
238
|
|
|
242
|
-
private final class
|
|
243
|
-
var didComplete = false
|
|
244
|
-
var onCancel: (() -> Void)?
|
|
245
|
-
private var cancelled = false
|
|
239
|
+
private final class OnboardingHostingController<V: View>: UIHostingController<V> {}
|
|
246
240
|
|
|
247
|
-
|
|
248
|
-
guard !didComplete, !cancelled else { return }
|
|
249
|
-
cancelled = true
|
|
250
|
-
onCancel?()
|
|
251
|
-
}
|
|
241
|
+
// MARK: - Delegates
|
|
252
242
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
243
|
+
private final class CheckoutDismissDelegate: NSObject, UIAdaptivePresentationControllerDelegate {
|
|
244
|
+
enum Outcome {
|
|
245
|
+
case success(String)
|
|
246
|
+
case failure
|
|
247
|
+
case cancel
|
|
256
248
|
}
|
|
257
|
-
}
|
|
258
249
|
|
|
259
|
-
|
|
250
|
+
private let resolve: RCTPromiseResolveBlock
|
|
251
|
+
private let reject: RCTPromiseRejectBlock
|
|
252
|
+
private var didFinish = false
|
|
260
253
|
|
|
261
|
-
|
|
254
|
+
init(resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
255
|
+
self.resolve = resolve
|
|
256
|
+
self.reject = reject
|
|
257
|
+
}
|
|
262
258
|
|
|
263
|
-
|
|
259
|
+
func finish(_ outcome: Outcome) {
|
|
260
|
+
guard !didFinish else { return }
|
|
261
|
+
didFinish = true
|
|
262
|
+
DispatchQueue.main.async { [resolve, reject] in
|
|
263
|
+
switch outcome {
|
|
264
|
+
case .success(let transferId): resolve(transferId)
|
|
265
|
+
case .failure: reject("PAYMENT_FAILED", "Checkout did not produce a transfer id", nil)
|
|
266
|
+
case .cancel: reject("USER_CANCELED", "User dismissed checkout without completing payment", nil)
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
|
272
|
+
finish(.cancel)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
264
275
|
|
|
265
276
|
private final class CartDismissDelegate: NSObject, UIAdaptivePresentationControllerDelegate {
|
|
266
277
|
enum Outcome {
|
|
@@ -319,5 +330,6 @@ private final class OnboardingDismissDelegate: NSObject, UIAdaptivePresentationC
|
|
|
319
330
|
}
|
|
320
331
|
}
|
|
321
332
|
|
|
333
|
+
private var checkoutDismissKey: UInt8 = 0
|
|
322
334
|
private var cartDismissKey: UInt8 = 0
|
|
323
335
|
private var onboardingDismissKey: UInt8 = 0
|
package/lib/native.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAiCjB,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB;AAwBD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAQlB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,MAAM,CAAC,CAYlB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkB5B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,oBAAoB,EACpB,gBAAgB,EAChB,sBAAsB,EACtB,uBAAuB,EACxB,MAAM,SAAS,CAAC;AAiCjB,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB;;;;;OAKG;IACH,KAAK,CAAC,EAAE,UAAU,CAAC;CACpB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhB;AAwBD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAQlB;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,MAAM,CAAC,CAYlB;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,YAAY,CAAC,EAAE,oBAAoB,EAAE,CAAC;IACtC,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkB5B;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuBhF;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBlF"}
|
package/lib/native.js
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { NativeModules, Platform } from 'react-native';
|
|
5
5
|
import { ErrorCodes } from './errors';
|
|
6
|
+
const LINKING_ERROR = `The package 'framepayments-react-native' doesn't seem to be linked. Make sure you have run 'pod install' (iOS) or rebuilt the app (Android).`;
|
|
7
|
+
const FrameSDK = NativeModules.FrameSDK
|
|
8
|
+
? NativeModules.FrameSDK
|
|
9
|
+
: new Proxy({}, {
|
|
10
|
+
get() {
|
|
11
|
+
throw new Error(LINKING_ERROR);
|
|
12
|
+
},
|
|
13
|
+
});
|
|
6
14
|
/**
|
|
7
15
|
* Throw a coded error from synchronous JS validation. Mirrors the `code`/`message`
|
|
8
16
|
* shape that native rejections produce so consumers can catch `e.code === 'INVALID_*'`
|
|
@@ -15,14 +23,6 @@ function throwCoded(code, message) {
|
|
|
15
23
|
}
|
|
16
24
|
// theme is iOS-only today: frame-android does not yet have a matching theme API,
|
|
17
25
|
// so the field is accepted on both platforms but ignored on Android until it does.
|
|
18
|
-
const LINKING_ERROR = `The package 'framepayments-react-native' doesn't seem to be linked. Make sure you have run 'pod install' (iOS) or rebuilt the app (Android).`;
|
|
19
|
-
const FrameSDK = NativeModules.FrameSDK
|
|
20
|
-
? NativeModules.FrameSDK
|
|
21
|
-
: new Proxy({}, {
|
|
22
|
-
get() {
|
|
23
|
-
throw new Error(LINKING_ERROR);
|
|
24
|
-
},
|
|
25
|
-
});
|
|
26
26
|
let isInitialized = false;
|
|
27
27
|
export function initialize(options) {
|
|
28
28
|
if (!options?.secretKey) {
|
|
@@ -104,6 +104,9 @@ export function presentOnboarding(options) {
|
|
|
104
104
|
*/
|
|
105
105
|
export function presentApplePay(options) {
|
|
106
106
|
guardInitialized();
|
|
107
|
+
if (Platform.OS !== 'ios') {
|
|
108
|
+
throwCoded('PLATFORM_UNSUPPORTED', 'Frame.presentApplePay is iOS-only; use presentGooglePay on Android.');
|
|
109
|
+
}
|
|
107
110
|
if (!options?.owner || (options.owner.type !== 'customer' && options.owner.type !== 'account')) {
|
|
108
111
|
throwCoded(ErrorCodes.INVALID_OWNER, 'Frame.presentApplePay requires owner: { type: "customer" | "account", id: string }');
|
|
109
112
|
}
|
|
@@ -124,6 +127,9 @@ export function presentApplePay(options) {
|
|
|
124
127
|
*/
|
|
125
128
|
export function presentGooglePay(options) {
|
|
126
129
|
guardInitialized();
|
|
130
|
+
if (Platform.OS !== 'android') {
|
|
131
|
+
throwCoded('PLATFORM_UNSUPPORTED', 'Frame.presentGooglePay is Android-only; use presentApplePay on iOS.');
|
|
132
|
+
}
|
|
127
133
|
if (!options?.owner || (options.owner.type !== 'customer' && options.owner.type !== 'account')) {
|
|
128
134
|
throwCoded(ErrorCodes.INVALID_OWNER, 'Frame.presentGooglePay requires owner: { type: "customer" | "account", id: string }');
|
|
129
135
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "framepayments-react-native",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "React Native SDK for Frame Payments - modal checkout and cart, with API usage via frame-node.",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -31,7 +31,11 @@
|
|
|
31
31
|
"homepage": "https://github.com/Frame-Payments/frame-react-native#readme",
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"react": "*",
|
|
34
|
-
"react-native": ">=0.
|
|
34
|
+
"react-native": ">=0.81.0"
|
|
35
|
+
},
|
|
36
|
+
"frameNativeVersions": {
|
|
37
|
+
"ios": "2.2.2",
|
|
38
|
+
"android": "2.0.8"
|
|
35
39
|
},
|
|
36
40
|
"devDependencies": {
|
|
37
41
|
"@types/jest": "^29.5.0",
|
|
@@ -54,6 +58,8 @@
|
|
|
54
58
|
"lib",
|
|
55
59
|
"ios",
|
|
56
60
|
"android",
|
|
61
|
+
"FrameReactNative.podspec",
|
|
62
|
+
"Package.swift",
|
|
57
63
|
"README.md",
|
|
58
64
|
"LICENSE"
|
|
59
65
|
],
|
|
@@ -224,6 +224,11 @@ describe('presentApplePay', () => {
|
|
|
224
224
|
});
|
|
225
225
|
|
|
226
226
|
describe('presentGooglePay', () => {
|
|
227
|
+
beforeEach(() => {
|
|
228
|
+
// presentGooglePay is Android-only; tests run on Android except where noted.
|
|
229
|
+
mockPlatform.OS = 'android';
|
|
230
|
+
});
|
|
231
|
+
|
|
227
232
|
it('throws NOT_INITIALIZED if initialize was not called', async () => {
|
|
228
233
|
try {
|
|
229
234
|
await presentGooglePay({ amountCents: 100, owner: { type: 'account', id: 'acct_1' } });
|
package/src/native.ts
CHANGED
|
@@ -13,20 +13,6 @@ import type {
|
|
|
13
13
|
} from './types';
|
|
14
14
|
import { ErrorCodes } from './errors';
|
|
15
15
|
|
|
16
|
-
/**
|
|
17
|
-
* Throw a coded error from synchronous JS validation. Mirrors the `code`/`message`
|
|
18
|
-
* shape that native rejections produce so consumers can catch `e.code === 'INVALID_*'`
|
|
19
|
-
* uniformly.
|
|
20
|
-
*/
|
|
21
|
-
function throwCoded(code: string, message: string): never {
|
|
22
|
-
const err = new Error(message) as Error & { code: string };
|
|
23
|
-
err.code = code;
|
|
24
|
-
throw err;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
// theme is iOS-only today: frame-android does not yet have a matching theme API,
|
|
28
|
-
// so the field is accepted on both platforms but ignored on Android until it does.
|
|
29
|
-
|
|
30
16
|
const LINKING_ERROR =
|
|
31
17
|
`The package 'framepayments-react-native' doesn't seem to be linked. Make sure you have run 'pod install' (iOS) or rebuilt the app (Android).`;
|
|
32
18
|
|
|
@@ -41,6 +27,20 @@ const FrameSDK = NativeModules.FrameSDK
|
|
|
41
27
|
}
|
|
42
28
|
);
|
|
43
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Throw a coded error from synchronous JS validation. Mirrors the `code`/`message`
|
|
32
|
+
* shape that native rejections produce so consumers can catch `e.code === 'INVALID_*'`
|
|
33
|
+
* uniformly.
|
|
34
|
+
*/
|
|
35
|
+
function throwCoded(code: string, message: string): never {
|
|
36
|
+
const err = new Error(message) as Error & { code: string };
|
|
37
|
+
err.code = code;
|
|
38
|
+
throw err;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// theme is iOS-only today: frame-android does not yet have a matching theme API,
|
|
42
|
+
// so the field is accepted on both platforms but ignored on Android until it does.
|
|
43
|
+
|
|
44
44
|
let isInitialized = false;
|
|
45
45
|
|
|
46
46
|
export function initialize(options: {
|
|
@@ -179,6 +179,9 @@ export function presentOnboarding(options: {
|
|
|
179
179
|
*/
|
|
180
180
|
export function presentApplePay(options: PresentApplePayOptions): Promise<string> {
|
|
181
181
|
guardInitialized();
|
|
182
|
+
if (Platform.OS !== 'ios') {
|
|
183
|
+
throwCoded('PLATFORM_UNSUPPORTED', 'Frame.presentApplePay is iOS-only; use presentGooglePay on Android.');
|
|
184
|
+
}
|
|
182
185
|
if (!options?.owner || (options.owner.type !== 'customer' && options.owner.type !== 'account')) {
|
|
183
186
|
throwCoded(ErrorCodes.INVALID_OWNER, 'Frame.presentApplePay requires owner: { type: "customer" | "account", id: string }');
|
|
184
187
|
}
|
|
@@ -208,6 +211,9 @@ export function presentApplePay(options: PresentApplePayOptions): Promise<string
|
|
|
208
211
|
*/
|
|
209
212
|
export function presentGooglePay(options: PresentGooglePayOptions): Promise<string> {
|
|
210
213
|
guardInitialized();
|
|
214
|
+
if (Platform.OS !== 'android') {
|
|
215
|
+
throwCoded('PLATFORM_UNSUPPORTED', 'Frame.presentGooglePay is Android-only; use presentApplePay on iOS.');
|
|
216
|
+
}
|
|
211
217
|
if (!options?.owner || (options.owner.type !== 'customer' && options.owner.type !== 'account')) {
|
|
212
218
|
throwCoded(ErrorCodes.INVALID_OWNER, 'Frame.presentGooglePay requires owner: { type: "customer" | "account", id: string }');
|
|
213
219
|
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
require 'json'
|
|
2
|
-
|
|
3
|
-
package = JSON.parse(File.read(File.join(__dir__, '..', 'package.json')))
|
|
4
|
-
|
|
5
|
-
Pod::Spec.new do |s|
|
|
6
|
-
s.name = 'FrameReactNative'
|
|
7
|
-
s.version = package['version']
|
|
8
|
-
s.summary = package['description']
|
|
9
|
-
s.homepage = package['homepage']
|
|
10
|
-
s.license = package['license']
|
|
11
|
-
s.authors = package['author']
|
|
12
|
-
s.platforms = { :ios => '17.0' }
|
|
13
|
-
s.source = { :git => package['repository']['url'], :tag => "#{s.version}" }
|
|
14
|
-
s.source_files = '**/*.{h,m,mm,swift}'
|
|
15
|
-
s.requires_arc = true
|
|
16
|
-
|
|
17
|
-
s.dependency 'React-Core'
|
|
18
|
-
|
|
19
|
-
# Frame-iOS SDK (Frame + FrameOnboarding) must be available to the app.
|
|
20
|
-
#
|
|
21
|
-
# SPM users (RN >= 0.73): add framepayments-react-native via Swift Package Manager.
|
|
22
|
-
# Frame and FrameOnboarding are declared as dependencies in Package.swift and resolve
|
|
23
|
-
# automatically — no manual step required.
|
|
24
|
-
#
|
|
25
|
-
# CocoaPods users: add frame-ios manually via Xcode:
|
|
26
|
-
# File → Add Package Dependencies → https://github.com/Frame-Payments/frame-ios
|
|
27
|
-
# Add both the "Frame-iOS" and "Frame-Onboarding" products to your app target.
|
|
28
|
-
# If Frame-iOS is published as a pod in the future, replace the above with:
|
|
29
|
-
# s.dependency 'Frame-iOS'
|
|
30
|
-
|
|
31
|
-
install_modules_dependencies(s) if respond_to?(:install_modules_dependencies)
|
|
32
|
-
end
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unit tests for the native module bridge (initialize, presentCheckout, presentCart).
|
|
3
|
-
* NativeModules.FrameSDK is mocked.
|
|
4
|
-
*/
|
|
5
|
-
declare const mockInitialize: jest.Mock<Promise<void>, [_apiKey: string, _debugMode: boolean], any>;
|
|
6
|
-
declare const mockPresentCheckout: jest.Mock<Promise<{
|
|
7
|
-
id: string;
|
|
8
|
-
amount: number;
|
|
9
|
-
}>, [_customerId: unknown, _amount: number], any>;
|
|
10
|
-
declare const mockPresentCart: jest.Mock<Promise<{
|
|
11
|
-
id: string;
|
|
12
|
-
amount: number;
|
|
13
|
-
}>, [_customerId: unknown, _items: unknown[], _shipping: number], any>;
|
|
14
|
-
declare let initialize: (opts: {
|
|
15
|
-
apiKey: string;
|
|
16
|
-
debugMode?: boolean;
|
|
17
|
-
}) => void;
|
|
18
|
-
declare let presentCheckout: (opts: {
|
|
19
|
-
customerId?: string | null;
|
|
20
|
-
amount: number;
|
|
21
|
-
}) => Promise<unknown>;
|
|
22
|
-
declare let presentCart: (opts: {
|
|
23
|
-
customerId?: string | null;
|
|
24
|
-
items: Array<{
|
|
25
|
-
id: string;
|
|
26
|
-
title: string;
|
|
27
|
-
amountInCents: number;
|
|
28
|
-
imageUrl: string;
|
|
29
|
-
}>;
|
|
30
|
-
shippingAmountInCents: number;
|
|
31
|
-
}) => Promise<unknown>;
|
|
32
|
-
//# sourceMappingURL=native.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"native.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/native.test.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,QAAA,MAAM,cAAc,uEAAuE,CAAC;AAC5F,QAAA,MAAM,mBAAmB;;;iDAAqG,CAAC;AAC/H,QAAA,MAAM,eAAe;;;sEAA0H,CAAC;AAahJ,QAAA,IAAI,UAAU,EAAE,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,KAAK,IAAI,CAAC;AACxE,QAAA,IAAI,eAAe,EAAE,CAAC,IAAI,EAAE;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAChG,QAAA,IAAI,WAAW,EAAE,CAAC,IAAI,EAAE;IACtB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACrF,qBAAqB,EAAE,MAAM,CAAC;CAC/B,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC"}
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* Unit tests for the native module bridge (initialize, presentCheckout, presentCart).
|
|
4
|
-
* NativeModules.FrameSDK is mocked.
|
|
5
|
-
*/
|
|
6
|
-
const mockInitialize = jest.fn((_apiKey, _debugMode) => Promise.resolve());
|
|
7
|
-
const mockPresentCheckout = jest.fn((_customerId, _amount) => Promise.resolve({ id: 'ci_1', amount: 10000 }));
|
|
8
|
-
const mockPresentCart = jest.fn((_customerId, _items, _shipping) => Promise.resolve({ id: 'ci_2', amount: 15000 }));
|
|
9
|
-
jest.mock('react-native', () => ({
|
|
10
|
-
NativeModules: {
|
|
11
|
-
FrameSDK: {
|
|
12
|
-
initialize: mockInitialize,
|
|
13
|
-
presentCheckout: mockPresentCheckout,
|
|
14
|
-
presentCart: mockPresentCart,
|
|
15
|
-
},
|
|
16
|
-
},
|
|
17
|
-
}));
|
|
18
|
-
// Re-import after mock so we get the mocked NativeModules
|
|
19
|
-
let initialize;
|
|
20
|
-
let presentCheckout;
|
|
21
|
-
let presentCart;
|
|
22
|
-
beforeEach(() => {
|
|
23
|
-
jest.resetModules();
|
|
24
|
-
mockInitialize.mockClear();
|
|
25
|
-
mockPresentCheckout.mockClear();
|
|
26
|
-
mockPresentCart.mockClear();
|
|
27
|
-
const native = require('../native');
|
|
28
|
-
initialize = native.initialize;
|
|
29
|
-
presentCheckout = native.presentCheckout;
|
|
30
|
-
presentCart = native.presentCart;
|
|
31
|
-
});
|
|
32
|
-
describe('initialize', () => {
|
|
33
|
-
it('calls native FrameSDK.initialize with apiKey and debugMode', () => {
|
|
34
|
-
initialize({ apiKey: 'sk_test_xxx', debugMode: true });
|
|
35
|
-
expect(mockInitialize).toHaveBeenCalledTimes(1);
|
|
36
|
-
expect(mockInitialize).toHaveBeenCalledWith('sk_test_xxx', true);
|
|
37
|
-
});
|
|
38
|
-
it('defaults debugMode to false', () => {
|
|
39
|
-
initialize({ apiKey: 'sk_test_yyy' });
|
|
40
|
-
expect(mockInitialize).toHaveBeenCalledWith('sk_test_yyy', false);
|
|
41
|
-
});
|
|
42
|
-
it('throws if apiKey is missing', () => {
|
|
43
|
-
expect(() => initialize({ apiKey: '' })).toThrow();
|
|
44
|
-
expect(() => initialize({})).toThrow();
|
|
45
|
-
expect(mockInitialize).not.toHaveBeenCalled();
|
|
46
|
-
});
|
|
47
|
-
});
|
|
48
|
-
describe('presentCheckout', () => {
|
|
49
|
-
it('throws NOT_INITIALIZED if initialize was not called', async () => {
|
|
50
|
-
try {
|
|
51
|
-
await presentCheckout({ amount: 10000 });
|
|
52
|
-
expect(true).toBe(false);
|
|
53
|
-
}
|
|
54
|
-
catch (e) {
|
|
55
|
-
expect(e.code).toBe('NOT_INITIALIZED');
|
|
56
|
-
expect(e.message).toContain('initialized');
|
|
57
|
-
}
|
|
58
|
-
expect(mockPresentCheckout).not.toHaveBeenCalled();
|
|
59
|
-
});
|
|
60
|
-
it('calls native presentCheckout with customerId and amount after initialize', async () => {
|
|
61
|
-
initialize({ apiKey: 'sk_xxx' });
|
|
62
|
-
const result = await presentCheckout({ customerId: 'cus_1', amount: 10000 });
|
|
63
|
-
expect(mockPresentCheckout).toHaveBeenCalledWith('cus_1', 10000);
|
|
64
|
-
expect(result).toEqual({ id: 'ci_1', amount: 10000 });
|
|
65
|
-
});
|
|
66
|
-
it('passes null for customerId when not provided', async () => {
|
|
67
|
-
initialize({ apiKey: 'sk_xxx' });
|
|
68
|
-
await presentCheckout({ amount: 5000 });
|
|
69
|
-
expect(mockPresentCheckout).toHaveBeenCalledWith(null, 5000);
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
describe('presentCart', () => {
|
|
73
|
-
const items = [
|
|
74
|
-
{ id: '1', title: 'Item A', amountInCents: 1000, imageUrl: 'https://example.com/a.jpg' },
|
|
75
|
-
];
|
|
76
|
-
it('throws NOT_INITIALIZED if initialize was not called', async () => {
|
|
77
|
-
try {
|
|
78
|
-
await presentCart({ items, shippingAmountInCents: 500 });
|
|
79
|
-
expect(true).toBe(false);
|
|
80
|
-
}
|
|
81
|
-
catch (e) {
|
|
82
|
-
expect(e.code).toBe('NOT_INITIALIZED');
|
|
83
|
-
}
|
|
84
|
-
expect(mockPresentCart).not.toHaveBeenCalled();
|
|
85
|
-
});
|
|
86
|
-
it('calls native presentCart with customerId, items, shipping after initialize', async () => {
|
|
87
|
-
initialize({ apiKey: 'sk_xxx' });
|
|
88
|
-
const result = await presentCart({
|
|
89
|
-
customerId: 'cus_2',
|
|
90
|
-
items,
|
|
91
|
-
shippingAmountInCents: 500,
|
|
92
|
-
});
|
|
93
|
-
expect(mockPresentCart).toHaveBeenCalledWith('cus_2', items, 500);
|
|
94
|
-
expect(result).toEqual({ id: 'ci_2', amount: 15000 });
|
|
95
|
-
});
|
|
96
|
-
it('passes null for customerId when not provided', async () => {
|
|
97
|
-
initialize({ apiKey: 'sk_xxx' });
|
|
98
|
-
await presentCart({ items, shippingAmountInCents: 0 });
|
|
99
|
-
expect(mockPresentCart).toHaveBeenCalledWith(null, items, 0);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <FrameApplePayButton /> — iOS-only React Native view that wraps Frame iOS SDK's
|
|
3
|
-
* native FrameApplePayButton (PassKit + automatic device attestation).
|
|
4
|
-
*
|
|
5
|
-
* On non-iOS platforms this component renders nothing, so consumers can place it
|
|
6
|
-
* unconditionally in their JSX.
|
|
7
|
-
*/
|
|
8
|
-
import * as React from 'react';
|
|
9
|
-
import { type NativeSyntheticEvent, type ViewProps } from 'react-native';
|
|
10
|
-
import type { ApplePayButtonStyle, ApplePayButtonType, ApplePayOwner, FrameApplePayResultEvent } from '../types';
|
|
11
|
-
export interface FrameApplePayButtonProps extends ViewProps {
|
|
12
|
-
/** Payment amount in cents. */
|
|
13
|
-
amount: number;
|
|
14
|
-
/** ISO 4217 currency code. Defaults to 'usd'. */
|
|
15
|
-
currency?: string;
|
|
16
|
-
/** Customer or account that owns the resulting payment method. */
|
|
17
|
-
owner: ApplePayOwner;
|
|
18
|
-
/** Apple Pay merchant ID configured in your Apple Developer account. */
|
|
19
|
-
merchantId: string;
|
|
20
|
-
/** When true, the button renders a "Or" divider beneath itself for inline checkout layouts. */
|
|
21
|
-
addCheckoutDivider?: boolean;
|
|
22
|
-
/** PassKit button type. Defaults to 'buy'. */
|
|
23
|
-
buttonType?: ApplePayButtonType;
|
|
24
|
-
/** PassKit button style. Defaults to 'black'. */
|
|
25
|
-
buttonStyle?: ApplePayButtonStyle;
|
|
26
|
-
/** Fired when payment completes, fails, or the button reports an error. */
|
|
27
|
-
onResult: (event: NativeSyntheticEvent<FrameApplePayResultEvent>) => void;
|
|
28
|
-
}
|
|
29
|
-
export declare const FrameApplePayButton: React.FC<FrameApplePayButtonProps>;
|
|
30
|
-
//# sourceMappingURL=FrameApplePayButton.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FrameApplePayButton.d.ts","sourceRoot":"","sources":["../../src/components/FrameApplePayButton.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EACV,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,wBAAwB,EACzB,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,wBAAyB,SAAQ,SAAS;IACzD,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kEAAkE;IAClE,KAAK,EAAE,aAAa,CAAC;IACrB,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;IACnB,+FAA+F;IAC/F,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,8CAA8C;IAC9C,UAAU,CAAC,EAAE,kBAAkB,CAAC;IAChC,iDAAiD;IACjD,WAAW,CAAC,EAAE,mBAAmB,CAAC;IAClC,2EAA2E;IAC3E,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,wBAAwB,CAAC,KAAK,IAAI,CAAC;CAC3E;AA+BD,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAclE,CAAC"}
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <FrameApplePayButton /> — iOS-only React Native view that wraps Frame iOS SDK's
|
|
3
|
-
* native FrameApplePayButton (PassKit + automatic device attestation).
|
|
4
|
-
*
|
|
5
|
-
* On non-iOS platforms this component renders nothing, so consumers can place it
|
|
6
|
-
* unconditionally in their JSX.
|
|
7
|
-
*/
|
|
8
|
-
import * as React from 'react';
|
|
9
|
-
import { Platform, StyleSheet, requireNativeComponent, } from 'react-native';
|
|
10
|
-
const NativeFrameApplePayButton = Platform.OS === 'ios'
|
|
11
|
-
? requireNativeComponent('FrameApplePayButtonView')
|
|
12
|
-
: null;
|
|
13
|
-
let warnedAboutOwner = false;
|
|
14
|
-
function warnIfBadOwner(owner) {
|
|
15
|
-
if (!owner ||
|
|
16
|
-
(owner.type !== 'customer' && owner.type !== 'account') ||
|
|
17
|
-
typeof owner.id !== 'string' ||
|
|
18
|
-
owner.id.length === 0) {
|
|
19
|
-
if (!warnedAboutOwner) {
|
|
20
|
-
warnedAboutOwner = true;
|
|
21
|
-
// eslint-disable-next-line no-console
|
|
22
|
-
console.warn('[FrameApplePayButton] `owner` must be { type: "customer" | "account", id: string }. The button will not render until a valid owner is provided.');
|
|
23
|
-
}
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
return true;
|
|
27
|
-
}
|
|
28
|
-
export const FrameApplePayButton = (props) => {
|
|
29
|
-
if (Platform.OS !== 'ios' || NativeFrameApplePayButton === null) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
if (!warnIfBadOwner(props.owner)) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
const { style, ...rest } = props;
|
|
36
|
-
return (<NativeFrameApplePayButton {...rest} style={[styles.button, style]}/>);
|
|
37
|
-
};
|
|
38
|
-
const styles = StyleSheet.create({
|
|
39
|
-
button: {
|
|
40
|
-
height: 50,
|
|
41
|
-
},
|
|
42
|
-
});
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <FrameGooglePayButton /> — Android-only React Native view that wraps Frame Android SDK's
|
|
3
|
-
* native FrameGooglePayButton (Google Pay PaymentsClient + readiness check).
|
|
4
|
-
*
|
|
5
|
-
* On non-Android platforms this component renders nothing, so consumers can place it
|
|
6
|
-
* unconditionally in their JSX.
|
|
7
|
-
*/
|
|
8
|
-
import * as React from 'react';
|
|
9
|
-
import { type NativeSyntheticEvent, type ViewProps } from 'react-native';
|
|
10
|
-
import type { FrameGooglePayResultEvent } from '../types';
|
|
11
|
-
export interface FrameGooglePayButtonProps extends ViewProps {
|
|
12
|
-
/** Payment amount in cents. */
|
|
13
|
-
amountCents: number;
|
|
14
|
-
/** Optional Frame customer ID to associate the resulting payment method with. */
|
|
15
|
-
customerId?: string;
|
|
16
|
-
/** ISO 4217 currency code. Defaults to 'USD'. */
|
|
17
|
-
currencyCode?: string;
|
|
18
|
-
/** Optional override for the Google Pay merchant ID. */
|
|
19
|
-
googlePayMerchantId?: string;
|
|
20
|
-
/** Fired when payment completes, fails, or the user cancels the Google Pay sheet. */
|
|
21
|
-
onResult: (event: NativeSyntheticEvent<FrameGooglePayResultEvent>) => void;
|
|
22
|
-
/** Fired when Google Pay readiness changes (button shows/hides itself accordingly). */
|
|
23
|
-
onReadinessChanged?: (event: NativeSyntheticEvent<{
|
|
24
|
-
isReady: boolean;
|
|
25
|
-
}>) => void;
|
|
26
|
-
}
|
|
27
|
-
export declare const FrameGooglePayButton: React.FC<FrameGooglePayButtonProps>;
|
|
28
|
-
//# sourceMappingURL=FrameGooglePayButton.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"FrameGooglePayButton.d.ts","sourceRoot":"","sources":["../../src/components/FrameGooglePayButton.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AACtB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,UAAU,CAAC;AAE1D,MAAM,WAAW,yBAA0B,SAAQ,SAAS;IAC1D,+BAA+B;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,iFAAiF;IACjF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iDAAiD;IACjD,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,wDAAwD;IACxD,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,qFAAqF;IACrF,QAAQ,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC,yBAAyB,CAAC,KAAK,IAAI,CAAC;IAC3E,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,CAAC,KAAK,EAAE,oBAAoB,CAAC;QAAE,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,KAAK,IAAI,CAAC;CAClF;AAOD,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CAWpE,CAAC"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* <FrameGooglePayButton /> — Android-only React Native view that wraps Frame Android SDK's
|
|
3
|
-
* native FrameGooglePayButton (Google Pay PaymentsClient + readiness check).
|
|
4
|
-
*
|
|
5
|
-
* On non-Android platforms this component renders nothing, so consumers can place it
|
|
6
|
-
* unconditionally in their JSX.
|
|
7
|
-
*/
|
|
8
|
-
import * as React from 'react';
|
|
9
|
-
import { Platform, StyleSheet, requireNativeComponent, } from 'react-native';
|
|
10
|
-
const NativeFrameGooglePayButton = Platform.OS === 'android'
|
|
11
|
-
? requireNativeComponent('FrameGooglePayButtonView')
|
|
12
|
-
: null;
|
|
13
|
-
export const FrameGooglePayButton = (props) => {
|
|
14
|
-
if (Platform.OS !== 'android' || NativeFrameGooglePayButton === null) {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
const { style, ...rest } = props;
|
|
18
|
-
return (<NativeFrameGooglePayButton {...rest} style={[styles.button, style]}/>);
|
|
19
|
-
};
|
|
20
|
-
const styles = StyleSheet.create({
|
|
21
|
-
button: {
|
|
22
|
-
height: 48,
|
|
23
|
-
},
|
|
24
|
-
});
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
export { FrameApplePayButton } from './FrameApplePayButton';
|
|
2
|
-
export type { FrameApplePayButtonProps } from './FrameApplePayButton';
|
|
3
|
-
export { FrameGooglePayButton } from './FrameGooglePayButton';
|
|
4
|
-
export type { FrameGooglePayButtonProps } from './FrameGooglePayButton';
|
|
5
|
-
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,YAAY,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/lib/components/index.js
DELETED