framepayments-react-native 1.0.0 → 1.0.1
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 +28 -8
- package/android/build/.transforms/3db830673120be833016e77c88c53305/results.bin +1 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$Companion.dex +0 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$tryShowCheckout$1.dex +0 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity.dex +0 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameFlowActivity$CartItemDto.dex +0 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameFlowActivity$Companion.dex +0 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameFlowActivity$parseCartItems$type$1.dex +0 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameFlowActivity.dex +0 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameSDKModule.dex +0 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/com/framepayments/reactnativeframe/FrameSDKPackage.dex +0 -0
- package/android/build/.transforms/3db830673120be833016e77c88c53305/transformed/debug/desugar_graph.bin +0 -0
- package/android/build/.transforms/e32bd1e24a69eac3ebaf0c3a5e659207/results.bin +1 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/AndroidManifest.xml +18 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/aapt/output-metadata.json +18 -0
- package/android/build/intermediates/aar_metadata/debug/aar-metadata.properties +5 -0
- package/android/build/intermediates/annotation_processor_list/debug/annotationProcessors.json +1 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/classes.jar +0 -0
- package/android/build/intermediates/compile_r_class_jar/debug/R.jar +0 -0
- package/android/build/intermediates/compile_symbol_list/debug/R.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
- package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
- package/android/build/intermediates/java_res/debug/out/META-INF/framepayments-react-native_debug.kotlin_module +0 -0
- package/android/build/intermediates/local_only_symbol_list/debug/R-def.txt +2 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/manifest-merger-blame-debug-report.txt +27 -0
- package/android/build/intermediates/merged_manifest/debug/AndroidManifest.xml +18 -0
- package/android/build/intermediates/navigation_json/debug/navigation.json +1 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/META-INF/framepayments-react-native_debug.kotlin_module +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$tryShowCheckout$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameFlowActivity$CartItemDto.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameFlowActivity$Companion.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameFlowActivity$parseCartItems$type$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameFlowActivity.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameSDKModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/com/framepayments/reactnativeframe/FrameSDKPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/classes.jar +0 -0
- package/android/build/intermediates/symbol_list_with_package_name/debug/package-aware-r.txt +1 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/inputs/source-to-output.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-attributes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/class-fq-name-to-source.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/constants.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/internal-name-to-source.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/proto.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/source-to-classes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/subtypes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/jvm/kotlin/supertypes.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/counters.tab +2 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/file-to-id.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/id-to-file.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.keystream.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab.values.at +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/caches-jvm/lookups/lookups.tab_i.len +0 -0
- package/android/build/kotlin/compileDebugKotlin/cacheable/last-build.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/classpath-snapshot/shrunk-classpath-snapshot.bin +0 -0
- package/android/build/kotlin/compileDebugKotlin/local-state/build-history.bin +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +35 -0
- package/android/build/tmp/kotlin-classes/debug/META-INF/framepayments-react-native_debug.kotlin_module +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity$tryShowCheckout$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameCheckoutActivity.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity$CartItemDto.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity$Companion.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity$parseCartItems$type$1.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameFlowActivity.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameSDKModule.class +0 -0
- package/android/build/tmp/kotlin-classes/debug/com/framepayments/reactnativeframe/FrameSDKPackage.class +0 -0
- package/android/build.gradle +6 -2
- package/android/src/main/AndroidManifest.xml +2 -1
- package/android/src/main/java/com/framepayments/reactnativeframe/FrameCheckoutActivity.kt +44 -0
- package/android/src/main/java/com/framepayments/reactnativeframe/FrameSDKModule.kt +14 -10
- package/ios/FramePreloader.swift +28 -0
- package/ios/FrameSDKBridge.m +57 -1
- package/ios/FrameSDKBridge.swift +35 -54
- package/ios/FrameVCHelper.h +12 -0
- package/ios/FrameVCHelper.m +11 -0
- package/lib/__tests__/native.test.d.ts +32 -0
- package/lib/__tests__/native.test.d.ts.map +1 -0
- package/lib/__tests__/native.test.js +101 -0
- package/lib/index.d.ts +9 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -1
- package/lib/native.d.ts +1 -1
- package/lib/native.d.ts.map +1 -1
- package/lib/native.js +4 -3
- package/package.json +11 -8
- package/src/index.ts +6 -1
- package/src/native.ts +7 -4
|
Binary file
|
|
Binary file
|
package/android/build.gradle
CHANGED
|
@@ -5,7 +5,7 @@ buildscript {
|
|
|
5
5
|
}
|
|
6
6
|
dependencies {
|
|
7
7
|
classpath 'com.android.tools.build:gradle:8.1.0'
|
|
8
|
-
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.
|
|
8
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:2.1.0"
|
|
9
9
|
}
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -40,7 +40,11 @@ repositories {
|
|
|
40
40
|
|
|
41
41
|
dependencies {
|
|
42
42
|
implementation 'com.facebook.react:react-native:+'
|
|
43
|
-
implementation "org.jetbrains.kotlin:kotlin-stdlib:1.
|
|
43
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib:2.1.0"
|
|
44
44
|
implementation 'com.framepayments:framesdk:1.2.0'
|
|
45
45
|
implementation 'com.framepayments:framesdk_ui:1.2.0'
|
|
46
|
+
implementation 'com.google.code.gson:gson:2.10.1'
|
|
47
|
+
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
|
48
|
+
// Frame SDK UI uses Compose; LocalLifecycleOwner requires lifecycle-runtime-compose 2.8+
|
|
49
|
+
implementation 'androidx.lifecycle:lifecycle-runtime-compose:2.8.2'
|
|
46
50
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
1
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
2
|
+
package="com.framepayments.reactnativeframe">
|
|
2
3
|
<application>
|
|
3
4
|
<activity
|
|
4
5
|
android:name="com.framepayments.reactnativeframe.FrameCheckoutActivity"
|
|
@@ -2,6 +2,8 @@ package com.framepayments.reactnativeframe
|
|
|
2
2
|
|
|
3
3
|
import android.content.Intent
|
|
4
4
|
import android.os.Bundle
|
|
5
|
+
import android.os.Handler
|
|
6
|
+
import android.os.Looper
|
|
5
7
|
import android.widget.FrameLayout
|
|
6
8
|
import androidx.appcompat.app.AppCompatActivity
|
|
7
9
|
import com.framepayments.framesdk.FrameNetworking
|
|
@@ -11,6 +13,9 @@ import com.google.gson.Gson
|
|
|
11
13
|
|
|
12
14
|
class FrameCheckoutActivity : AppCompatActivity() {
|
|
13
15
|
|
|
16
|
+
private val handler = Handler(Looper.getMainLooper())
|
|
17
|
+
private var pollRunnable: Runnable? = null
|
|
18
|
+
|
|
14
19
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
15
20
|
super.onCreate(savedInstanceState)
|
|
16
21
|
val container = FrameLayout(this).apply {
|
|
@@ -22,6 +27,40 @@ class FrameCheckoutActivity : AppCompatActivity() {
|
|
|
22
27
|
setContentView(container)
|
|
23
28
|
val customerId = intent.getStringExtra(EXTRA_CUSTOMER_ID)
|
|
24
29
|
val amount = intent.getIntExtra(EXTRA_AMOUNT, 0)
|
|
30
|
+
|
|
31
|
+
// Evervault must be configured before FrameCheckoutView (EncryptedPaymentCardInput) can inflate.
|
|
32
|
+
// configureEvervault() is async on first launch; direct checkout opens before it completes.
|
|
33
|
+
tryShowCheckout(container, customerId, amount)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
private fun tryShowCheckout(container: FrameLayout, customerId: String?, amount: Int) {
|
|
37
|
+
if (FrameNetworking.isEvervaultConfigured) {
|
|
38
|
+
addCheckoutView(container, customerId, amount)
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
var attempts = 0
|
|
42
|
+
val maxAttempts = 50 // 5 seconds
|
|
43
|
+
pollRunnable = object : Runnable {
|
|
44
|
+
override fun run() {
|
|
45
|
+
if (isFinishing) return
|
|
46
|
+
if (FrameNetworking.isEvervaultConfigured) {
|
|
47
|
+
addCheckoutView(container, customerId, amount)
|
|
48
|
+
pollRunnable = null
|
|
49
|
+
return
|
|
50
|
+
}
|
|
51
|
+
attempts++
|
|
52
|
+
if (attempts >= maxAttempts) {
|
|
53
|
+
setResult(RESULT_CANCELED)
|
|
54
|
+
finish()
|
|
55
|
+
return
|
|
56
|
+
}
|
|
57
|
+
handler.postDelayed(this, 100)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
handler.postDelayed(pollRunnable!!, 100)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private fun addCheckoutView(container: FrameLayout, customerId: String?, amount: Int) {
|
|
25
64
|
val checkoutView = FrameCheckoutView(this)
|
|
26
65
|
checkoutView.configure(customerId, amount) { chargeIntent ->
|
|
27
66
|
val json = Gson().toJson(chargeIntent)
|
|
@@ -31,6 +70,11 @@ class FrameCheckoutActivity : AppCompatActivity() {
|
|
|
31
70
|
container.addView(checkoutView)
|
|
32
71
|
}
|
|
33
72
|
|
|
73
|
+
override fun onDestroy() {
|
|
74
|
+
pollRunnable?.let { handler.removeCallbacks(it) }
|
|
75
|
+
super.onDestroy()
|
|
76
|
+
}
|
|
77
|
+
|
|
34
78
|
companion object {
|
|
35
79
|
const val EXTRA_CUSTOMER_ID = "customer_id"
|
|
36
80
|
const val EXTRA_AMOUNT = "amount"
|
|
@@ -43,11 +43,13 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
43
43
|
return
|
|
44
44
|
}
|
|
45
45
|
checkoutPromise = promise
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
activity.runOnUiThread {
|
|
47
|
+
val intent = Intent(activity, FrameCheckoutActivity::class.java).apply {
|
|
48
|
+
putExtra(FrameCheckoutActivity.EXTRA_CUSTOMER_ID, customerId)
|
|
49
|
+
putExtra(FrameCheckoutActivity.EXTRA_AMOUNT, amount.toInt())
|
|
50
|
+
}
|
|
51
|
+
activity.startActivityForResult(intent, FrameCheckoutActivity.REQUEST_CODE)
|
|
49
52
|
}
|
|
50
|
-
activity.startActivityForResult(intent, FrameCheckoutActivity.REQUEST_CODE)
|
|
51
53
|
}
|
|
52
54
|
|
|
53
55
|
@ReactMethod
|
|
@@ -66,12 +68,14 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
66
68
|
return
|
|
67
69
|
}
|
|
68
70
|
cartPromise = promise
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
activity.runOnUiThread {
|
|
72
|
+
val intent = Intent(activity, FrameFlowActivity::class.java).apply {
|
|
73
|
+
putExtra(FrameFlowActivity.EXTRA_CUSTOMER_ID, customerId)
|
|
74
|
+
putExtra(FrameFlowActivity.EXTRA_ITEMS_JSON, itemsJson)
|
|
75
|
+
putExtra(FrameFlowActivity.EXTRA_SHIPPING_CENTS, shippingAmountInCents.toInt())
|
|
76
|
+
}
|
|
77
|
+
activity.startActivityForResult(intent, FrameFlowActivity.REQUEST_CODE)
|
|
73
78
|
}
|
|
74
|
-
activity.startActivityForResult(intent, FrameFlowActivity.REQUEST_CODE)
|
|
75
79
|
}
|
|
76
80
|
|
|
77
81
|
private fun readableArrayToJson(items: com.facebook.react.bridge.ReadableArray): String? {
|
|
@@ -82,7 +86,7 @@ class FrameSDKModule(reactContext: ReactApplicationContext) :
|
|
|
82
86
|
obj.put("id", item.getString("id"))
|
|
83
87
|
obj.put("title", item.getString("title"))
|
|
84
88
|
obj.put("amountInCents", item.getDouble("amountInCents").toInt())
|
|
85
|
-
obj.put("imageUrl", item.getString("imageUrl"))
|
|
89
|
+
obj.put("imageUrl", item.getString("imageUrl") ?: "")
|
|
86
90
|
arr.put(obj)
|
|
87
91
|
}
|
|
88
92
|
return arr.toString()
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//
|
|
2
|
+
// FramePreloader.swift
|
|
3
|
+
// FrameReactNative
|
|
4
|
+
//
|
|
5
|
+
// Preloads the Frame module on the main thread BEFORE the React Native bridge
|
|
6
|
+
// initializes. This avoids "Helpers are not supported by the default hub" crash
|
|
7
|
+
// that occurs when Frame/Evervault/Sift load on a background thread during
|
|
8
|
+
// bridge module discovery.
|
|
9
|
+
//
|
|
10
|
+
|
|
11
|
+
import Foundation
|
|
12
|
+
import Frame
|
|
13
|
+
|
|
14
|
+
@objc(FramePreloader)
|
|
15
|
+
public final class FramePreloader: NSObject {
|
|
16
|
+
|
|
17
|
+
/// Call from AppDelegate before [super application:didFinishLaunchingWithOptions].
|
|
18
|
+
/// Forces Frame (and its deps: Evervault, Sift) to load on main thread.
|
|
19
|
+
@objc public static func preloadOnMainThread() {
|
|
20
|
+
guard Thread.isMainThread else {
|
|
21
|
+
DispatchQueue.main.sync { preloadOnMainThread() }
|
|
22
|
+
return
|
|
23
|
+
}
|
|
24
|
+
// Touch FrameNetworking to trigger Frame module load on main thread.
|
|
25
|
+
// Evervault/Sift config is deferred to initializeWithAPIKey.
|
|
26
|
+
_ = FrameNetworking.shared
|
|
27
|
+
}
|
|
28
|
+
}
|
package/ios/FrameSDKBridge.m
CHANGED
|
@@ -2,10 +2,28 @@
|
|
|
2
2
|
// FrameSDKBridge.m
|
|
3
3
|
// FrameReactNative
|
|
4
4
|
//
|
|
5
|
+
// ObjC adapter that forwards to Swift FrameSDKBridge.
|
|
6
|
+
//
|
|
5
7
|
|
|
6
8
|
#import <React/RCTBridgeModule.h>
|
|
9
|
+
#import "FrameVCHelper.h"
|
|
10
|
+
|
|
11
|
+
// Import app's Swift header (ObjCFrameSDKBridge, FramePreloader). The example uses FrameExampleTemp.
|
|
12
|
+
// If your app has a different module name, add Preprocessor Macro: FRAME_SWIFT_HEADER="YourApp-Swift.h"
|
|
13
|
+
#if defined(FRAME_SWIFT_HEADER)
|
|
14
|
+
#import FRAME_SWIFT_HEADER
|
|
15
|
+
#elif __has_include("FrameExampleTemp-Swift.h")
|
|
16
|
+
#import "FrameExampleTemp-Swift.h"
|
|
17
|
+
#elif __has_include(<FrameExampleTemp/FrameExampleTemp-Swift.h>)
|
|
18
|
+
#import <FrameExampleTemp/FrameExampleTemp-Swift.h>
|
|
19
|
+
#else
|
|
20
|
+
#error "Swift header not found. Add FRAME_SWIFT_HEADER=\"YourApp-Swift.h\" to your app target's Preprocessor Macros, or ensure Swift files compile before this file."
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
@interface FrameSDKModule : NSObject <RCTBridgeModule>
|
|
24
|
+
@end
|
|
7
25
|
|
|
8
|
-
@interface RCT_EXTERN_MODULE(FrameSDK,
|
|
26
|
+
@interface RCT_EXTERN_MODULE(FrameSDK, FrameSDKModule)
|
|
9
27
|
|
|
10
28
|
RCT_EXTERN_METHOD(initialize:(NSString *)apiKey
|
|
11
29
|
debugMode:(BOOL)debugMode
|
|
@@ -24,3 +42,41 @@ RCT_EXTERN_METHOD(presentCart:(id)customerId
|
|
|
24
42
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
25
43
|
|
|
26
44
|
@end
|
|
45
|
+
|
|
46
|
+
@implementation FrameSDK
|
|
47
|
+
@end
|
|
48
|
+
|
|
49
|
+
@implementation FrameSDKModule
|
|
50
|
+
|
|
51
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
52
|
+
return YES;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
- (void)initialize:(NSString *)apiKey debugMode:(BOOL)debugMode resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
|
|
56
|
+
[[[ObjCFrameSDKBridge alloc] init] initialize:apiKey debugMode:debugMode resolver:resolve rejecter:reject];
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
- (void)presentCheckout:(id)customerId amount:(NSNumber *)amount resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
|
|
60
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
61
|
+
UIViewController *topVC = FrameGetTopViewController();
|
|
62
|
+
if (!topVC) {
|
|
63
|
+
reject(@"NO_ROOT_VC", @"Could not find root view controller to present checkout", nil);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
NSString *cId = [customerId isKindOfClass:[NSString class]] ? (NSString *)customerId : nil;
|
|
67
|
+
[[[ObjCFrameSDKBridge alloc] init] presentCheckoutFrom:topVC customerId:cId amount:amount.intValue resolver:resolve rejecter:reject];
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
- (void)presentCart:(id)customerId items:(NSArray *)items shippingAmountInCents:(NSNumber *)shippingAmountInCents resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
|
|
72
|
+
dispatch_async(dispatch_get_main_queue(), ^{
|
|
73
|
+
UIViewController *topVC = FrameGetTopViewController();
|
|
74
|
+
if (!topVC) {
|
|
75
|
+
reject(@"NO_ROOT_VC", @"Could not find root view controller to present cart", nil);
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
[[[ObjCFrameSDKBridge alloc] init] presentCartFrom:topVC customerId:customerId items:items shippingAmountInCents:shippingAmountInCents resolver:resolve rejecter:reject];
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
@end
|
package/ios/FrameSDKBridge.swift
CHANGED
|
@@ -11,14 +11,14 @@ import UIKit
|
|
|
11
11
|
import SwiftUI
|
|
12
12
|
import Frame
|
|
13
13
|
|
|
14
|
-
@objc(
|
|
15
|
-
class FrameSDKBridge: NSObject {
|
|
14
|
+
@objc(ObjCFrameSDKBridge)
|
|
15
|
+
public class FrameSDKBridge: NSObject {
|
|
16
16
|
|
|
17
|
-
@objc static func requiresMainQueueSetup() -> Bool {
|
|
17
|
+
@objc public static func requiresMainQueueSetup() -> Bool {
|
|
18
18
|
return true
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
@objc
|
|
21
|
+
@objc public
|
|
22
22
|
func initialize(_ apiKey: String, debugMode: Bool, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
23
23
|
DispatchQueue.main.async {
|
|
24
24
|
FrameNetworking.shared.initializeWithAPIKey(apiKey, debugMode: debugMode)
|
|
@@ -26,43 +26,41 @@ class FrameSDKBridge: NSObject {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
@objc
|
|
30
|
-
func presentCheckout(
|
|
31
|
-
|
|
32
|
-
let amountInt = amount.intValue
|
|
33
|
-
DispatchQueue.main.async { [weak self] in
|
|
34
|
-
self?.presentCheckoutOnMain(customerId: cId, amount: amountInt, resolve: resolve, reject: reject)
|
|
35
|
-
}
|
|
29
|
+
@objc public
|
|
30
|
+
func presentCheckout(from viewController: UIViewController, customerId: String?, amount: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
31
|
+
presentCheckoutOnMain(from: viewController, customerId: customerId, amount: amount, resolve: resolve, reject: reject)
|
|
36
32
|
}
|
|
37
33
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
let rootVC = windowScene.windows.first(where: { $0.isKeyWindow })?.rootViewController else {
|
|
43
|
-
reject("NO_ROOT_VC", "Could not find root view controller to present checkout", nil)
|
|
34
|
+
@objc public
|
|
35
|
+
func presentCart(from viewController: UIViewController, customerId: NSObject?, items: NSArray, shippingAmountInCents: Int, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
36
|
+
guard let cartItems = parseCartItems(items) else {
|
|
37
|
+
reject("INVALID_ITEMS", "Invalid cart items array", nil)
|
|
44
38
|
return
|
|
45
39
|
}
|
|
46
|
-
|
|
47
|
-
|
|
40
|
+
presentCartOnMain(from: viewController, customerId: customerId as? String, cartItems: cartItems, shippingAmountInCents: shippingAmountInCents, resolve: resolve, reject: reject)
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private func presentCheckoutOnMain(from top: UIViewController, customerId: String?, amount: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
48
44
|
let delegate = CheckoutDismissDelegate(resolve: resolve, reject: reject)
|
|
49
45
|
let checkoutView = FrameCheckoutView(
|
|
50
46
|
customerId: customerId,
|
|
51
47
|
paymentAmount: amount,
|
|
52
|
-
checkoutCallback: { [weak
|
|
48
|
+
checkoutCallback: { [weak delegate] chargeIntent in
|
|
53
49
|
delegate?.didComplete = true
|
|
54
|
-
top
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
50
|
+
top.dismiss(animated: true)
|
|
51
|
+
DispatchQueue.main.async {
|
|
52
|
+
if let dict = Self.encodeChargeIntent(chargeIntent) {
|
|
53
|
+
resolve(dict)
|
|
54
|
+
} else {
|
|
55
|
+
reject("ENCODE_ERROR", "Failed to encode charge intent", nil)
|
|
56
|
+
}
|
|
59
57
|
}
|
|
60
58
|
}
|
|
61
59
|
)
|
|
62
60
|
let hosting = UIHostingController(rootView: checkoutView)
|
|
63
|
-
hosting.modalPresentationStyle = .pageSheet
|
|
61
|
+
hosting.modalPresentationStyle = UIModalPresentationStyle.pageSheet
|
|
64
62
|
if let sheet = hosting.sheetPresentationController {
|
|
65
|
-
sheet.detents = [.large()]
|
|
63
|
+
sheet.detents = [UISheetPresentationController.Detent.large()]
|
|
66
64
|
}
|
|
67
65
|
objc_setAssociatedObject(hosting, &checkoutDismissKey, delegate, .OBJC_ASSOCIATION_RETAIN)
|
|
68
66
|
hosting.presentationController?.delegate = delegate
|
|
@@ -74,19 +72,6 @@ class FrameSDKBridge: NSObject {
|
|
|
74
72
|
return try? JSONSerialization.jsonObject(with: data) as? [String: Any]
|
|
75
73
|
}
|
|
76
74
|
|
|
77
|
-
@objc
|
|
78
|
-
func presentCart(_ customerId: NSObject, items: NSArray, shippingAmountInCents: NSNumber, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
79
|
-
let cId = customerId as? String
|
|
80
|
-
let shipping = shippingAmountInCents.intValue
|
|
81
|
-
guard let cartItems = parseCartItems(items) else {
|
|
82
|
-
reject("INVALID_ITEMS", "Invalid cart items array", nil)
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
DispatchQueue.main.async { [weak self] in
|
|
86
|
-
self?.presentCartOnMain(customerId: cId, cartItems: cartItems, shippingAmountInCents: shipping, resolve: resolve, reject: reject)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
75
|
private struct RNFrameCartItem: FrameCartItem {
|
|
91
76
|
var id: String
|
|
92
77
|
var imageURL: String
|
|
@@ -107,25 +92,16 @@ class FrameSDKBridge: NSObject {
|
|
|
107
92
|
return result
|
|
108
93
|
}
|
|
109
94
|
|
|
110
|
-
private func presentCartOnMain(customerId: String?, cartItems: [RNFrameCartItem], shippingAmountInCents: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
111
|
-
guard let windowScene = UIApplication.shared.connectedScenes
|
|
112
|
-
.compactMap({ $0 as? UIWindowScene })
|
|
113
|
-
.first(where: { $0.activationState == .foregroundActive }),
|
|
114
|
-
let rootVC = windowScene.windows.first(where: { $0.isKeyWindow })?.rootViewController else {
|
|
115
|
-
reject("NO_ROOT_VC", "Could not find root view controller to present cart", nil)
|
|
116
|
-
return
|
|
117
|
-
}
|
|
118
|
-
var top = rootVC
|
|
119
|
-
while let presented = top.presentedViewController { top = presented }
|
|
95
|
+
private func presentCartOnMain(from top: UIViewController, customerId: String?, cartItems: [RNFrameCartItem], shippingAmountInCents: Int, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
|
120
96
|
let cartView = FrameCartView(
|
|
121
97
|
customer: nil,
|
|
122
98
|
cartItems: cartItems,
|
|
123
99
|
shippingAmountInCents: shippingAmountInCents
|
|
124
100
|
)
|
|
125
101
|
let hosting = UIHostingController(rootView: cartView)
|
|
126
|
-
hosting.modalPresentationStyle = .pageSheet
|
|
102
|
+
hosting.modalPresentationStyle = UIModalPresentationStyle.pageSheet
|
|
127
103
|
if let sheet = hosting.sheetPresentationController {
|
|
128
|
-
sheet.detents = [.large()]
|
|
104
|
+
sheet.detents = [UISheetPresentationController.Detent.large()]
|
|
129
105
|
}
|
|
130
106
|
// When the sheet is dismissed (swipe or close), resolve. Note: FrameCartView does not expose ChargeIntent from nested checkout.
|
|
131
107
|
let delegate = CartDismissDelegate(resolve: resolve)
|
|
@@ -145,7 +121,9 @@ private final class CheckoutDismissDelegate: NSObject, UIAdaptivePresentationCon
|
|
|
145
121
|
}
|
|
146
122
|
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
|
147
123
|
guard !didComplete else { return }
|
|
148
|
-
|
|
124
|
+
DispatchQueue.main.async { [reject] in
|
|
125
|
+
reject("USER_CANCELED", "User dismissed checkout without completing payment", nil)
|
|
126
|
+
}
|
|
149
127
|
}
|
|
150
128
|
}
|
|
151
129
|
|
|
@@ -153,9 +131,12 @@ private final class CartDismissDelegate: NSObject, UIAdaptivePresentationControl
|
|
|
153
131
|
let resolve: RCTPromiseResolveBlock
|
|
154
132
|
init(resolve: @escaping RCTPromiseResolveBlock) { self.resolve = resolve }
|
|
155
133
|
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
|
156
|
-
resolve
|
|
134
|
+
DispatchQueue.main.async { [resolve] in
|
|
135
|
+
resolve([String: Any]())
|
|
136
|
+
}
|
|
157
137
|
}
|
|
158
138
|
}
|
|
159
139
|
|
|
160
140
|
private var cartDismissKey: UInt8 = 0
|
|
161
141
|
private var checkoutDismissKey: UInt8 = 0
|
|
142
|
+
|
|
@@ -0,0 +1,32 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,101 @@
|
|
|
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
|
+
});
|
package/lib/index.d.ts
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* framepayments-react-native
|
|
3
3
|
*
|
|
4
4
|
* React Native SDK for Frame Payments.
|
|
5
5
|
* - Initialize the SDK, then use presentCheckout / presentCart for payment UI.
|
|
6
6
|
* - For API calls (customers, charge intents, refunds), use the framepayments (frame-node) package from JS.
|
|
7
7
|
*/
|
|
8
|
+
import { initialize, presentCheckout, presentCart } from './native';
|
|
8
9
|
export { initialize, presentCheckout, presentCart } from './native';
|
|
9
10
|
export type { FrameCartItem, ChargeIntent, FrameError } from './types';
|
|
10
11
|
export { ErrorCodes } from './errors';
|
|
11
12
|
export type { FrameErrorShape, FrameErrorCode } from './errors';
|
|
13
|
+
/** Default export for Frame.initialize(), Frame.presentCheckout(), etc. */
|
|
14
|
+
declare const _default: {
|
|
15
|
+
initialize: typeof initialize;
|
|
16
|
+
presentCheckout: typeof presentCheckout;
|
|
17
|
+
presentCart: typeof presentCart;
|
|
18
|
+
};
|
|
19
|
+
export default _default;
|
|
12
20
|
//# sourceMappingURL=index.d.ts.map
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACpE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEpE,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AACpE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAEhE,2EAA2E;;;;;;AAC3E,wBAA4D"}
|
package/lib/index.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* framepayments-react-native
|
|
3
3
|
*
|
|
4
4
|
* React Native SDK for Frame Payments.
|
|
5
5
|
* - Initialize the SDK, then use presentCheckout / presentCart for payment UI.
|
|
6
6
|
* - For API calls (customers, charge intents, refunds), use the framepayments (frame-node) package from JS.
|
|
7
7
|
*/
|
|
8
|
+
import { initialize, presentCheckout, presentCart } from './native';
|
|
8
9
|
export { initialize, presentCheckout, presentCart } from './native';
|
|
9
10
|
export { ErrorCodes } from './errors';
|
|
11
|
+
/** Default export for Frame.initialize(), Frame.presentCheckout(), etc. */
|
|
12
|
+
export default { initialize, presentCheckout, presentCart };
|
package/lib/native.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import type { ChargeIntent, FrameCartItem } from './types';
|
|
|
5
5
|
export declare function initialize(options: {
|
|
6
6
|
apiKey: string;
|
|
7
7
|
debugMode?: boolean;
|
|
8
|
-
}): void
|
|
8
|
+
}): Promise<void>;
|
|
9
9
|
export declare function presentCheckout(options: {
|
|
10
10
|
customerId?: string | null;
|
|
11
11
|
amount: number;
|
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,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAmB3D,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"native.d.ts","sourceRoot":"","sources":["../src/native.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAmB3D,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAS1F;AAwBD,wBAAgB,eAAe,CAAC,OAAO,EAAE;IACvC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,YAAY,CAAC,CAKxB;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE;IACnC,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,aAAa,EAAE,CAAC;IACvB,qBAAqB,EAAE,MAAM,CAAC;CAC/B,GAAG,OAAO,CAAC,YAAY,CAAC,CASxB"}
|
package/lib/native.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { NativeModules } from 'react-native';
|
|
5
5
|
import { ErrorCodes } from './errors';
|
|
6
|
-
const LINKING_ERROR = `The package '
|
|
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
7
|
const FrameSDK = NativeModules.FrameSDK
|
|
8
8
|
? NativeModules.FrameSDK
|
|
9
9
|
: new Proxy({}, {
|
|
@@ -16,8 +16,9 @@ export function initialize(options) {
|
|
|
16
16
|
if (!options?.apiKey) {
|
|
17
17
|
throw new Error('Frame.initialize requires apiKey');
|
|
18
18
|
}
|
|
19
|
-
FrameSDK.initialize(options.apiKey, options.debugMode ?? false)
|
|
20
|
-
|
|
19
|
+
return wrapPromise(FrameSDK.initialize(options.apiKey, options.debugMode ?? false)).then(() => {
|
|
20
|
+
isInitialized = true;
|
|
21
|
+
});
|
|
21
22
|
}
|
|
22
23
|
function guardInitialized() {
|
|
23
24
|
if (!isInitialized) {
|