@jimrising/easymerchantsdk-react-native 2.0.6 → 2.0.9
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 +134 -1783
- package/android/build/.transforms/15b6a8a60a6b32d0dcaf609723cf365b/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1$1.dex +0 -0
- package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
- package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
- package/android/build/.transforms/8508f1428f740032c45a43f48b1bbe1e/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
- package/android/build/.transforms/eef2d06269ef2e204b4f065513034fca/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$1$1.dex +0 -0
- package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
- package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
- package/android/build/.transforms/ffabb40f9809b32eb9546ce76fc51764/transformed/bundleLibRuntimeToDirRelease/bundleLibRuntimeToDirRelease_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
- package/android/build/intermediates/aar_main_jar/release/syncReleaseLibJars/classes.jar +0 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/compile_library_classes_jar/release/bundleLibCompileToJarRelease/classes.jar +0 -0
- package/android/build/intermediates/full_jar/release/createFullJarRelease/full.jar +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +1 -1
- package/android/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-dependencies.xml +4 -4
- package/android/build/intermediates/incremental/lintVitalAnalyzeRelease/release-artifact-libraries.xml +4 -4
- package/android/build/intermediates/incremental/release/mergeReleaseResources/compile-file-map.properties +526 -525
- package/android/build/intermediates/incremental/release/mergeReleaseResources/merged.dir/values/values.xml +1 -1
- package/android/build/intermediates/incremental/release/mergeReleaseResources/merger.xml +3 -3
- package/android/build/intermediates/incremental/release/packageReleaseResources/compile-file-map.properties +1 -1
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
- package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
- package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/javac/release/compileReleaseJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/androidx/core/group-index.xml +4 -3
- package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/androidx/lifecycle/group-index.xml +165 -165
- package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/com/android/tools/build/group-index.xml +15 -15
- package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/maven.google/master-index.xml +1 -0
- package/android/build/intermediates/lint-cache/lintVitalAnalyzeRelease/sdk_index/snapshot.gz +0 -0
- package/android/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-dependencies.xml +4 -4
- package/android/build/intermediates/lint_model/release/generateReleaseLintModel/release-artifact-libraries.xml +4 -4
- package/android/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-dependencies.xml +4 -4
- package/android/build/intermediates/lint_vital_lint_model/release/generateReleaseLintVitalModel/release-artifact-libraries.xml +4 -4
- package/android/build/intermediates/local_aar_for_lint/release/out.aar +0 -0
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/drawable/close_icon_main.xml +16 -0
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_card_addition_ifo.xml +1 -0
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_card_billing_info.xml +1 -0
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_card_scan.xml +1 -0
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_payment_done.xml +1 -0
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_payment_done_url.xml +3 -3
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_payment_error.xml +1 -0
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_select_payment_method.xml +25 -6
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/layout/activity_verify_email.xml +1 -0
- package/android/build/intermediates/merged_res/release/mergeReleaseResources/values/values.xml +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/multi-v2/values-night-v8.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/multi-v2/values.json +102 -102
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/anim-v21.json +8 -8
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/anim.json +23 -23
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/animator-v21.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/animator.json +26 -26
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/color-night-v8.json +3 -3
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/color-v31.json +10 -10
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/color.json +153 -153
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-hdpi-v4.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-mdpi-v4.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-v21.json +3 -3
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-v23.json +7 -7
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-xhdpi-v4.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-xxhdpi-v4.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable-xxxhdpi-v4.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/drawable.json +141 -137
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/font.json +9 -9
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/interpolator-v21.json +10 -10
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/interpolator.json +11 -11
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-land.json +3 -3
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-sw600dp-v13.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout-v26.json +1 -1
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/layout.json +93 -93
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-anydpi-v26.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-hdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-mdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xhdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xxhdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/mipmap-xxxhdpi-v4.json +2 -2
- package/android/build/intermediates/merged_res_blame_folder/release/mergeReleaseResources/out/single/xml.json +3 -3
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/release/bundleLibRuntimeToDirRelease/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/release/bundleLibRuntimeToJarRelease/classes.jar +0 -0
- package/android/build/intermediates/source_set_path_map/release/mapReleaseSourceSetPaths/file-map.txt +8 -8
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/drawable_close_icon_main.xml.flat +0 -0
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_card_addition_ifo.xml.flat +0 -0
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_card_billing_info.xml.flat +0 -0
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_card_scan.xml.flat +0 -0
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_payment_done.xml.flat +0 -0
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_payment_done_url.xml.flat +0 -0
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_payment_error.xml.flat +0 -0
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_select_payment_method.xml.flat +0 -0
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/layout_activity_verify_email.xml.flat +0 -0
- package/android/build/intermediates/verified_library_resources/release/verifyReleaseResources/compiled/values_values.arsc.flat +0 -0
- package/android/build/outputs/aar/jimrising_easymerchantsdk-react-native-release.aar +0 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +10 -10
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1$1.class.uniqueId1 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1.class.uniqueId0 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$2.class.uniqueId3 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule.class.uniqueId2 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkPackage.class.uniqueId4 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build/tmp/compileReleaseJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkModule.java +93 -26
- package/ios/Classes/EasyMerchantSdk.m +4 -4
- package/ios/Classes/EasyMerchantSdk.swift +116 -60
- package/ios/Classes/EasyPayViewController.swift +3 -5
- package/ios/CustomComponents/CheckboxButton.swift +66 -0
- package/ios/Helper/GrailPayHelper.swift +1 -0
- package/ios/Models/Request.swift +8 -8
- package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +233 -97
- package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +376 -104
- package/ios/Pods/ViewControllers/OTPVerificationVC.swift +28 -27
- package/ios/Pods/ViewControllers/PaymentErrorVC.swift +22 -25
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +575 -190
- package/ios/easymerchantsdk.podspec +1 -1
- package/ios/easymerchantsdk.storyboard +15 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,48 +1,62 @@
|
|
|
1
1
|
# EasyMerchantSdk React Native Implementation
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
This guide provides step-by-step instructions to integrate the EasyMerchantSdk into your React Native application for both Android and iOS platforms.
|
|
4
4
|
|
|
5
|
-
##
|
|
6
|
-
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Node.js and npm installed
|
|
8
|
+
- React Native development environment set up
|
|
9
|
+
- Ruby 3.2.8 (for iOS setup)
|
|
10
|
+
- Xcode (for iOS development)
|
|
11
|
+
- Android Studio (for Android development)
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
### 1. Add the SDK to Your Project
|
|
16
|
+
|
|
17
|
+
Add the EasyMerchantSdk to your project by including it in your `package.json` file under the `dependencies` section:
|
|
7
18
|
|
|
8
19
|
```json
|
|
9
20
|
"dependencies": {
|
|
10
|
-
"@jimrising/easymerchantsdk-react-native": "^2.0.
|
|
11
|
-
}
|
|
21
|
+
"@jimrising/easymerchantsdk-react-native": "^2.0.9"
|
|
22
|
+
}
|
|
12
23
|
```
|
|
13
24
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
25
|
+
Alternatively, install it using the following command:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @jimrising/easymerchantsdk-react-native
|
|
17
29
|
```
|
|
18
30
|
|
|
19
|
-
|
|
20
|
-
|
|
31
|
+
### 2. Android Configuration
|
|
32
|
+
|
|
33
|
+
1. Open the `android/build.gradle` file in your project.
|
|
34
|
+
2. Add the following code to the `allprojects.repositories` section to ensure the SDK can access required dependencies:
|
|
35
|
+
|
|
21
36
|
```gradle
|
|
22
37
|
allprojects {
|
|
23
38
|
repositories {
|
|
24
39
|
google()
|
|
25
40
|
mavenCentral()
|
|
26
41
|
maven { url 'https://jitpack.io' }
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
42
|
+
maven {
|
|
43
|
+
url = uri(properties.getProperty('GITHUB_URL'))
|
|
44
|
+
credentials {
|
|
45
|
+
username = properties.getProperty('GITHUB_USERNAME')
|
|
46
|
+
password = properties.getProperty('GITHUB_PASSWORD')
|
|
47
|
+
}
|
|
48
|
+
}
|
|
34
49
|
}
|
|
35
50
|
}
|
|
36
51
|
```
|
|
37
52
|
|
|
38
|
-
|
|
39
|
-
Add below content inside the AppDelegate.swift File :-
|
|
53
|
+
3. Sync your project with Gradle to apply the changes.
|
|
40
54
|
|
|
41
|
-
|
|
42
|
-
- Ruby 3.2.8
|
|
55
|
+
### 3. iOS Configuration
|
|
43
56
|
|
|
57
|
+
1. **Update AppDelegate.swift**
|
|
58
|
+
Create or modify the `AppDelegate.swift` file in your iOS project to include the following code:
|
|
44
59
|
|
|
45
|
-
Create a new file named AppDelegate.swift
|
|
46
60
|
```swift
|
|
47
61
|
import UIKit
|
|
48
62
|
import easymerchantsdk
|
|
@@ -50,7 +64,7 @@ import React
|
|
|
50
64
|
|
|
51
65
|
@UIApplicationMain
|
|
52
66
|
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
53
|
-
var window: UIWindow?
|
|
67
|
+
var window: UIWindow?
|
|
54
68
|
|
|
55
69
|
func application(
|
|
56
70
|
_ application: UIApplication,
|
|
@@ -76,7 +90,7 @@ var window: UIWindow?
|
|
|
76
90
|
|
|
77
91
|
let rootView = RCTRootView(
|
|
78
92
|
bridge: validBridge,
|
|
79
|
-
moduleName: "EasyMerchantTestApp",
|
|
93
|
+
moduleName: "EasyMerchantTestApp", // Replace with your app name
|
|
80
94
|
initialProperties: nil
|
|
81
95
|
)
|
|
82
96
|
|
|
@@ -85,8 +99,8 @@ var window: UIWindow?
|
|
|
85
99
|
rootViewController.view = rootView
|
|
86
100
|
self.window?.rootViewController = rootViewController
|
|
87
101
|
self.window?.makeKeyAndVisible()
|
|
88
|
-
|
|
89
|
-
|
|
102
|
+
|
|
103
|
+
if let easyMerchantSdkPlugin = bridge?.module(for: EasyMerchantSdkPlugin.self) as? EasyMerchantSdkPlugin {
|
|
90
104
|
easyMerchantSdkPlugin.setViewController(rootViewController)
|
|
91
105
|
} else {
|
|
92
106
|
print("Failed to retrieve EasyMerchantSdkPlugin instance from React Native bridge.")
|
|
@@ -96,154 +110,43 @@ var window: UIWindow?
|
|
|
96
110
|
}
|
|
97
111
|
```
|
|
98
112
|
|
|
99
|
-
|
|
100
|
-
|
|
113
|
+
2. **Update Podfile**
|
|
114
|
+
Open your `ios/Podfile` and add the following to include the EasyMerchantSdk pod:
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
require_relative '../node_modules/react-native/scripts/react_native_pods'
|
|
118
|
+
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
|
101
119
|
|
|
102
|
-
|
|
103
|
-
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'
|
|
120
|
+
platform :ios, '16.0'
|
|
104
121
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
pod 'easymerchantsdk', :path => '../node_modules/easymerchantsdk-react-native/ios'
|
|
122
|
+
pod 'easymerchantsdk', :path => '../node_modules/easymerchantsdk-react-native/ios'
|
|
108
123
|
```
|
|
109
124
|
|
|
125
|
+
3. Run `pod install` in the `ios` directory to install the dependencies:
|
|
110
126
|
|
|
127
|
+
```bash
|
|
128
|
+
cd ios
|
|
129
|
+
pod install
|
|
130
|
+
```
|
|
111
131
|
|
|
112
|
-
##
|
|
113
|
-
you can call the sdk using below example:
|
|
132
|
+
## Usage in Your React Native App
|
|
114
133
|
|
|
134
|
+
To integrate the EasyMerchantSdk into your React Native application, you can use the provided `App.js` as a reference. Below is a summary of how to call the SDK in your `App.js`:
|
|
115
135
|
|
|
116
|
-
|
|
136
|
+
1. **Import Necessary Modules**
|
|
137
|
+
Ensure you import the required React Native components and the EasyMerchantSdk NativeModules:
|
|
117
138
|
|
|
139
|
+
```javascript
|
|
118
140
|
import React, { useState, useEffect } from 'react';
|
|
119
|
-
import {
|
|
120
|
-
StyleSheet,
|
|
121
|
-
Text,
|
|
122
|
-
View,
|
|
123
|
-
TextInput,
|
|
124
|
-
Button,
|
|
125
|
-
Alert,
|
|
126
|
-
ScrollView,
|
|
127
|
-
Platform,
|
|
128
|
-
NativeModules,
|
|
129
|
-
Switch,
|
|
130
|
-
TouchableOpacity,
|
|
131
|
-
NativeEventEmitter,
|
|
132
|
-
KeyboardAvoidingView,
|
|
133
|
-
Keyboard,
|
|
134
|
-
TouchableWithoutFeedback,
|
|
135
|
-
Modal,
|
|
136
|
-
} from 'react-native';
|
|
141
|
+
import { StyleSheet, Text, View, TextInput, Button, Alert, ScrollView, Platform, NativeModules, Switch, TouchableOpacity, NativeEventEmitter, KeyboardAvoidingView, Keyboard, TouchableWithoutFeedback, Modal } from 'react-native';
|
|
137
142
|
|
|
138
143
|
const { RNEasymerchantsdk, EasyMerchantSdk } = NativeModules;
|
|
144
|
+
```
|
|
139
145
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
const [isOpen, setIsOpen] = useState(false);
|
|
143
|
-
|
|
144
|
-
// Handler to close modal when tapping outside
|
|
145
|
-
const handleClose = () => setIsOpen(false);
|
|
146
|
-
|
|
147
|
-
return (
|
|
148
|
-
<View style={styles.dropdownContainer} pointerEvents="box-none">
|
|
149
|
-
<TouchableOpacity
|
|
150
|
-
style={styles.dropdownButton}
|
|
151
|
-
onPress={() => setIsOpen(!isOpen)}
|
|
152
|
-
>
|
|
153
|
-
<Text style={styles.dropdownButtonText}>
|
|
154
|
-
{value || placeholder}
|
|
155
|
-
</Text>
|
|
156
|
-
<Text style={styles.dropdownArrow}>
|
|
157
|
-
{isOpen ? '▲' : '▼'}
|
|
158
|
-
</Text>
|
|
159
|
-
</TouchableOpacity>
|
|
160
|
-
{Platform.OS === 'android' ? (
|
|
161
|
-
<Modal
|
|
162
|
-
visible={isOpen}
|
|
163
|
-
transparent={true}
|
|
164
|
-
animationType="fade"
|
|
165
|
-
onRequestClose={handleClose}
|
|
166
|
-
>
|
|
167
|
-
<TouchableWithoutFeedback onPress={handleClose}>
|
|
168
|
-
<View style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.2)' }}>
|
|
169
|
-
<View style={[styles.dropdownOptions, { position: 'absolute', top: '30%', left: 20, right: 20, maxHeight: 300, elevation: 20 }]}>
|
|
170
|
-
<ScrollView
|
|
171
|
-
style={[styles.dropdownScrollView, { maxHeight: 280 }]}
|
|
172
|
-
showsVerticalScrollIndicator={true}
|
|
173
|
-
persistentScrollbar={true}
|
|
174
|
-
nestedScrollEnabled={true}
|
|
175
|
-
keyboardShouldPersistTaps="handled"
|
|
176
|
-
>
|
|
177
|
-
{options.map((option, index) => (
|
|
178
|
-
<TouchableOpacity
|
|
179
|
-
key={index}
|
|
180
|
-
style={styles.dropdownOption}
|
|
181
|
-
onPress={() => {
|
|
182
|
-
onValueChange(option);
|
|
183
|
-
setIsOpen(false);
|
|
184
|
-
}}
|
|
185
|
-
>
|
|
186
|
-
<Text style={styles.dropdownOptionText}>{option}</Text>
|
|
187
|
-
</TouchableOpacity>
|
|
188
|
-
))}
|
|
189
|
-
</ScrollView>
|
|
190
|
-
</View>
|
|
191
|
-
</View>
|
|
192
|
-
</TouchableWithoutFeedback>
|
|
193
|
-
</Modal>
|
|
194
|
-
) : (
|
|
195
|
-
isOpen && (
|
|
196
|
-
<View style={styles.dropdownOptions}>
|
|
197
|
-
<ScrollView
|
|
198
|
-
style={styles.dropdownScrollView}
|
|
199
|
-
showsVerticalScrollIndicator={true}
|
|
200
|
-
persistentScrollbar={true}
|
|
201
|
-
nestedScrollEnabled={true}
|
|
202
|
-
keyboardShouldPersistTaps="handled"
|
|
203
|
-
>
|
|
204
|
-
{options.map((option, index) => (
|
|
205
|
-
<TouchableOpacity
|
|
206
|
-
key={index}
|
|
207
|
-
style={styles.dropdownOption}
|
|
208
|
-
onPress={() => {
|
|
209
|
-
onValueChange(option);
|
|
210
|
-
setIsOpen(false);
|
|
211
|
-
}}
|
|
212
|
-
>
|
|
213
|
-
<Text style={styles.dropdownOptionText}>{option}</Text>
|
|
214
|
-
</TouchableOpacity>
|
|
215
|
-
))}
|
|
216
|
-
</ScrollView>
|
|
217
|
-
</View>
|
|
218
|
-
)
|
|
219
|
-
)}
|
|
220
|
-
</View>
|
|
221
|
-
);
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
// Custom Filled Button Component
|
|
225
|
-
const FilledButton = ({ title, onPress, disabled = false, style = {}, textStyle = {} }) => {
|
|
226
|
-
return (
|
|
227
|
-
<TouchableOpacity
|
|
228
|
-
style={[
|
|
229
|
-
styles.filledButton,
|
|
230
|
-
disabled && styles.filledButtonDisabled,
|
|
231
|
-
style,
|
|
232
|
-
]}
|
|
233
|
-
onPress={onPress}
|
|
234
|
-
disabled={disabled}
|
|
235
|
-
>
|
|
236
|
-
<Text style={[
|
|
237
|
-
styles.filledButtonText,
|
|
238
|
-
disabled && styles.filledButtonTextDisabled,
|
|
239
|
-
textStyle,
|
|
240
|
-
]}>
|
|
241
|
-
{title}
|
|
242
|
-
</Text>
|
|
243
|
-
</TouchableOpacity>
|
|
244
|
-
);
|
|
245
|
-
};
|
|
146
|
+
2. **Set Up Configuration**
|
|
147
|
+
Define the configuration object for the SDK, including payment details, theme settings, and other parameters. The provided `App.js` includes a comprehensive `externalConfig` object that you can customize:
|
|
246
148
|
|
|
149
|
+
```javascript
|
|
247
150
|
const externalConfig = {
|
|
248
151
|
amount: '',
|
|
249
152
|
email: '',
|
|
@@ -257,11 +160,11 @@ const externalConfig = {
|
|
|
257
160
|
billingInfo: {
|
|
258
161
|
visibility: { billing: false, additional: false },
|
|
259
162
|
billing: {
|
|
260
|
-
address: '
|
|
261
|
-
country: '
|
|
262
|
-
state: '
|
|
263
|
-
city: '
|
|
264
|
-
postal_code: '
|
|
163
|
+
address: 'Address',
|
|
164
|
+
country: 'Country',
|
|
165
|
+
state: 'State',
|
|
166
|
+
city: 'City',
|
|
167
|
+
postal_code: '000000',
|
|
265
168
|
},
|
|
266
169
|
billingRequired: {
|
|
267
170
|
address: true,
|
|
@@ -271,30 +174,32 @@ const externalConfig = {
|
|
|
271
174
|
postal_code: true,
|
|
272
175
|
},
|
|
273
176
|
additional: {
|
|
274
|
-
|
|
177
|
+
name: 'Test User',
|
|
178
|
+
email_address: 'test@gmail.com',
|
|
275
179
|
phone_number: '2140871329',
|
|
276
180
|
description: 'Test',
|
|
277
181
|
},
|
|
278
182
|
additionalRequired: {
|
|
279
|
-
|
|
183
|
+
name: true,
|
|
184
|
+
email_address: true,
|
|
280
185
|
phone_number: true,
|
|
281
186
|
description: false,
|
|
282
187
|
},
|
|
283
188
|
},
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
189
|
+
themeConfiguration: {
|
|
190
|
+
bodyBackgroundColor: '#1E3A8A',
|
|
191
|
+
containerBackgroundColor: '#1E40AF',
|
|
192
|
+
primaryFontColor: '#FFFFFF',
|
|
193
|
+
secondaryFontColor: '#BFDBFE',
|
|
194
|
+
primaryButtonBackgroundColor: '#3B82F6',
|
|
195
|
+
primaryButtonHoverColor: '#2563EB',
|
|
196
|
+
primaryButtonFontColor: '#FFFFFF',
|
|
197
|
+
secondaryButtonBackgroundColor: '#1D4ED8',
|
|
198
|
+
secondaryButtonHoverColor: '#1E40AF',
|
|
199
|
+
secondaryButtonFontColor: '#FFFFFF',
|
|
200
|
+
borderRadius: '8',
|
|
201
|
+
fontSize: '14',
|
|
202
|
+
},
|
|
298
203
|
grailPayParams: {
|
|
299
204
|
role: 'business',
|
|
300
205
|
timeout: 10,
|
|
@@ -306,7 +211,7 @@ const externalConfig = {
|
|
|
306
211
|
recurringData: {
|
|
307
212
|
allowCycles: 2,
|
|
308
213
|
intervals: ['daily', 'weekly', 'monthly'],
|
|
309
|
-
recurringStartType:
|
|
214
|
+
recurringStartType: 'custom',
|
|
310
215
|
recurringStartDate: new Date().toLocaleDateString('en-US', { month: '2-digit', day: '2-digit', year: 'numeric' }),
|
|
311
216
|
},
|
|
312
217
|
androidConfig: {
|
|
@@ -329,7 +234,8 @@ const externalConfig = {
|
|
|
329
234
|
{ name: 'postal_code', required: true, value: '1432456' },
|
|
330
235
|
],
|
|
331
236
|
additional: [
|
|
332
|
-
|
|
237
|
+
{ name: 'name', required: true, value: 'Test User 7' },
|
|
238
|
+
{ name: 'email_address', required: true, value: 'usertest@gmail.com' },
|
|
333
239
|
{ name: 'phone_number', required: true, value: '8978967895' },
|
|
334
240
|
{ name: 'description', required: true, value: 'Hi This is description' },
|
|
335
241
|
],
|
|
@@ -353,139 +259,56 @@ const externalConfig = {
|
|
|
353
259
|
},
|
|
354
260
|
},
|
|
355
261
|
};
|
|
262
|
+
```
|
|
356
263
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
const [email, setEmail] = useState(externalConfig.email);
|
|
360
|
-
const [name, setName] = useState('');
|
|
361
|
-
const [environment, setEnvironment] = useState('sandbox');
|
|
362
|
-
const [isRecurring, setIsRecurring] = useState(externalConfig.isRecurring);
|
|
363
|
-
const [isAuthenticatedACH, setAuthenticatedACH] = useState(externalConfig.isAuthenticatedACH);
|
|
364
|
-
const [isSecureAuthentication, setSecureAuthentication] = useState(externalConfig.isSecureAuthentication);
|
|
365
|
-
const [isBillingVisible, setBillingVisible] = useState(externalConfig.isBillingVisible);
|
|
366
|
-
const [isAdditionalVisible, setAdditionalVisible] = useState(externalConfig.isAdditionalVisible);
|
|
367
|
-
const [emailEditable, setEmailEditable] = useState(externalConfig.emailEditable); // Android
|
|
368
|
-
const [isEmail, setIsEmail] = useState(externalConfig.isEmail); // iOS
|
|
369
|
-
const [billingInfo, setBillingInfo] = useState(externalConfig.billingInfo);
|
|
370
|
-
const [themeConfiguration, setThemeConfiguration] = useState(externalConfig.themeConfiguration);
|
|
371
|
-
const [grailPayParams, setGrailPayParams] = useState(externalConfig.grailPayParams);
|
|
372
|
-
const [recurringData, setRecurringData] = useState(externalConfig.recurringData);
|
|
373
|
-
const [androidConfig, setAndroidConfig] = useState(externalConfig.androidConfig);
|
|
374
|
-
const [result, setResult] = useState('');
|
|
375
|
-
const [referenceToken, setReferenceToken] = useState('');
|
|
376
|
-
const [loading, setLoading] = useState(false);
|
|
377
|
-
const [showSecretKey, setShowSecretKey] = useState(false);
|
|
378
|
-
const metadata = {
|
|
379
|
-
metaKey: 'metaValue',
|
|
380
|
-
metaKLey1: 'metaValue1',
|
|
381
|
-
metaKLey2: 'metaValue2',
|
|
382
|
-
metaKLey3: 'metaValue3',
|
|
383
|
-
metaKLey4: 'metaValue4',
|
|
384
|
-
};
|
|
385
|
-
|
|
386
|
-
const [apiKeys, setApiKeys] = useState({
|
|
387
|
-
sandbox: {
|
|
388
|
-
apiKey: 'sandboxApiKey',
|
|
389
|
-
secretKey: 'sandboxSecretKey',
|
|
390
|
-
},
|
|
391
|
-
staging: {
|
|
392
|
-
apiKey: 'stagingApiKey',
|
|
393
|
-
secretKey: 'stagingSecretKey',
|
|
394
|
-
},
|
|
395
|
-
});
|
|
396
|
-
const [isEnvironmentLoading, setIsEnvironmentLoading] = useState(false);
|
|
397
|
-
const [showConfig, setShowConfig] = useState(true);
|
|
398
|
-
|
|
399
|
-
// Debug useEffect to track payment method changes
|
|
400
|
-
useEffect(() => {
|
|
401
|
-
console.log('Payment methods state changed:', androidConfig.paymentMethod);
|
|
402
|
-
}, [androidConfig.paymentMethod]);
|
|
403
|
-
|
|
404
|
-
// Debug useEffect to track theme configuration changes
|
|
405
|
-
useEffect(() => {
|
|
406
|
-
console.log('Theme configuration changed:', themeConfiguration);
|
|
407
|
-
}, [themeConfiguration]);
|
|
264
|
+
3. **Handle Payments**
|
|
265
|
+
Use the `handlePayment` function to initiate payments. This function validates inputs and calls platform-specific billing functions (`handleAndroidBilling` for Android and `handleIosBilling` for iOS). Example:
|
|
408
266
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
267
|
+
```javascript
|
|
268
|
+
const handlePayment = async () => {
|
|
269
|
+
if (!amount || isNaN(parseFloat(amount)) || parseFloat(amount) <= 0) {
|
|
270
|
+
return Alert.alert('Error', 'Please enter a valid amount');
|
|
271
|
+
}
|
|
413
272
|
|
|
273
|
+
if (isRecurring && (!recurringData.intervals || recurringData.intervals.length === 0)) {
|
|
274
|
+
return Alert.alert('Error', 'Please select at least one interval for recurring payment');
|
|
275
|
+
}
|
|
414
276
|
|
|
415
|
-
|
|
416
|
-
const updateEnvironment = async () => {
|
|
417
|
-
const { apiKey, secretKey } = apiKeys[environment];
|
|
277
|
+
setLoading(true);
|
|
418
278
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
};
|
|
279
|
+
try {
|
|
280
|
+
if (Platform.OS === 'android') {
|
|
281
|
+
await handleAndroidBilling();
|
|
282
|
+
} else {
|
|
283
|
+
await handleIosBilling();
|
|
284
|
+
}
|
|
285
|
+
} finally {
|
|
286
|
+
setLoading(false);
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
```
|
|
433
290
|
|
|
434
|
-
|
|
435
|
-
|
|
291
|
+
4. **Event Listeners for Android**
|
|
292
|
+
Set up event listeners for payment success, status, and errors using `NativeEventEmitter`:
|
|
436
293
|
|
|
294
|
+
```javascript
|
|
437
295
|
useEffect(() => {
|
|
438
|
-
if (Platform.OS !== 'android')
|
|
439
|
-
console.log('Event listeners skipped: not Android');
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
if (!RNEasymerchantsdk) {
|
|
444
|
-
console.warn('RNEasymerchantsdk native module is not available.');
|
|
445
|
-
return;
|
|
446
|
-
}
|
|
296
|
+
if (Platform.OS !== 'android') return;
|
|
447
297
|
|
|
448
298
|
const easyMerchantEvents = new NativeEventEmitter(RNEasymerchantsdk);
|
|
449
299
|
|
|
450
300
|
const successSub = easyMerchantEvents.addListener('PaymentSuccess', (data) => {
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
try {
|
|
454
|
-
const parsed = JSON.parse(data.response);
|
|
455
|
-
console.log('Parsed PaymentSuccess:', parsed);
|
|
456
|
-
|
|
457
|
-
const billing = safeParseMaybeJSON(parsed.billingInfo);
|
|
458
|
-
const additional = safeParseMaybeJSON(parsed.additional_info);
|
|
459
|
-
|
|
460
|
-
console.log('Billing Info:', billing);
|
|
461
|
-
console.log('Additional Info:', additional);
|
|
462
|
-
|
|
463
|
-
// Replace raw with parsed versions
|
|
464
|
-
parsed.billingInfo = billing;
|
|
465
|
-
parsed.additional_info = additional;
|
|
466
|
-
|
|
467
|
-
setResult(JSON.stringify(parsed, null, 2));
|
|
468
|
-
} catch (err) {
|
|
469
|
-
console.error('Error parsing PaymentSuccess response:', err);
|
|
470
|
-
}
|
|
301
|
+
const parsed = JSON.parse(data.response);
|
|
302
|
+
setResult(JSON.stringify(parsed, null, 2));
|
|
471
303
|
});
|
|
472
304
|
|
|
473
305
|
const statusSub = easyMerchantEvents.addListener('PaymentStatus', (data) => {
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
try {
|
|
477
|
-
const parsed = JSON.parse(data.statusResponse);
|
|
478
|
-
console.log('Parsed PaymentStatus:', parsed);
|
|
479
|
-
|
|
480
|
-
setResult(JSON.stringify(parsed, null, 2));
|
|
481
|
-
} catch (err) {
|
|
482
|
-
console.error('Error parsing PaymentStatus response:', err);
|
|
483
|
-
}
|
|
306
|
+
const parsed = JSON.parse(data.statusResponse);
|
|
307
|
+
setResult(JSON.stringify(parsed, null, 2));
|
|
484
308
|
});
|
|
485
309
|
|
|
486
310
|
const statusErrorSub = easyMerchantEvents.addListener('PaymentStatusError', (data) => {
|
|
487
|
-
|
|
488
|
-
setResult(`Status Error: ${JSON.stringify(data)}`);
|
|
311
|
+
setResult(`Status Error: ${JSON.stringify(data.error, null, 2)}`);
|
|
489
312
|
});
|
|
490
313
|
|
|
491
314
|
return () => {
|
|
@@ -494,1493 +317,21 @@ useEffect(() => {
|
|
|
494
317
|
statusErrorSub.remove();
|
|
495
318
|
};
|
|
496
319
|
}, []);
|
|
320
|
+
```
|
|
497
321
|
|
|
322
|
+
5. **UI Components**
|
|
323
|
+
The provided `App.js` includes custom components like `Dropdown` and `FilledButton` for a user-friendly interface. Customize the styles in the `StyleSheet` to match your app's design.
|
|
498
324
|
|
|
499
|
-
|
|
500
|
-
if (typeof value === 'string') {
|
|
501
|
-
try {
|
|
502
|
-
return JSON.parse(value);
|
|
503
|
-
} catch (e) {
|
|
504
|
-
console.warn('Failed to parse JSON string:', value);
|
|
505
|
-
return value;
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
return value;
|
|
509
|
-
};
|
|
510
|
-
|
|
511
|
-
useEffect(() => {
|
|
512
|
-
setBillingInfo(prev => ({
|
|
513
|
-
...prev,
|
|
514
|
-
visibility: {
|
|
515
|
-
billing: isBillingVisible,
|
|
516
|
-
additional: isAdditionalVisible,
|
|
517
|
-
},
|
|
518
|
-
}));
|
|
519
|
-
}, [isBillingVisible, isAdditionalVisible]);
|
|
520
|
-
|
|
521
|
-
const updateBillingInfo = (section, field, value) => {
|
|
522
|
-
setBillingInfo(prev => ({
|
|
523
|
-
...prev,
|
|
524
|
-
[section]: {
|
|
525
|
-
...prev[section],
|
|
526
|
-
[field]: value,
|
|
527
|
-
},
|
|
528
|
-
}));
|
|
529
|
-
};
|
|
530
|
-
|
|
531
|
-
const updateAndroidConfig = (field, value) => {
|
|
532
|
-
setAndroidConfig(prev => ({
|
|
533
|
-
...prev,
|
|
534
|
-
[field]: value,
|
|
535
|
-
}));
|
|
536
|
-
};
|
|
537
|
-
|
|
538
|
-
const updateAndroidConfigFields = (section, index, field, value) => {
|
|
539
|
-
setAndroidConfig(prev => ({
|
|
540
|
-
...prev,
|
|
541
|
-
fields: {
|
|
542
|
-
...prev.fields,
|
|
543
|
-
[section]: prev.fields[section].map((item, i) =>
|
|
544
|
-
i === index ? { ...item, [field]: value } : item
|
|
545
|
-
),
|
|
546
|
-
},
|
|
547
|
-
}));
|
|
548
|
-
};
|
|
549
|
-
|
|
550
|
-
const updateAndroidConfigAppearanceSettings = (field, value) => {
|
|
551
|
-
setAndroidConfig(prev => ({
|
|
552
|
-
...prev,
|
|
553
|
-
appearanceSettings: {
|
|
554
|
-
...prev.appearanceSettings,
|
|
555
|
-
[field]: value,
|
|
556
|
-
},
|
|
557
|
-
}));
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
const updateThemeConfiguration = (field, value) => {
|
|
561
|
-
setThemeConfiguration(prev => ({
|
|
562
|
-
...prev,
|
|
563
|
-
[field]: value,
|
|
564
|
-
}));
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
const updateGrailPayParams = (field, value) => {
|
|
568
|
-
setGrailPayParams(prev => ({
|
|
569
|
-
...prev,
|
|
570
|
-
[field]: value,
|
|
571
|
-
}));
|
|
572
|
-
};
|
|
573
|
-
|
|
574
|
-
const updateRecurringData = (field, value) => {
|
|
575
|
-
setRecurringData(prev => ({
|
|
576
|
-
...prev,
|
|
577
|
-
[field]: value,
|
|
578
|
-
}));
|
|
579
|
-
};
|
|
580
|
-
|
|
581
|
-
const togglePaymentMethod = (method) => {
|
|
582
|
-
console.log('Toggling payment method:', method);
|
|
583
|
-
setAndroidConfig(prev => {
|
|
584
|
-
const currentMethods = prev.paymentMethod;
|
|
585
|
-
console.log('Current payment methods before toggle:', currentMethods);
|
|
586
|
-
const isCurrentlySelected = currentMethods.includes(method);
|
|
587
|
-
console.log('Is currently selected:', isCurrentlySelected);
|
|
588
|
-
|
|
589
|
-
let newMethods;
|
|
590
|
-
if (isCurrentlySelected) {
|
|
591
|
-
// If deselecting and it's the only method, don't allow deselection
|
|
592
|
-
if (currentMethods.length === 1) {
|
|
593
|
-
console.log('Cannot deselect last payment method, keeping current state');
|
|
594
|
-
return prev; // Keep the current state
|
|
595
|
-
}
|
|
596
|
-
// Remove the method
|
|
597
|
-
newMethods = currentMethods.filter(m => m !== method);
|
|
598
|
-
console.log('Removing method, new methods:', newMethods);
|
|
599
|
-
} else {
|
|
600
|
-
// Add the method
|
|
601
|
-
newMethods = [...currentMethods, method];
|
|
602
|
-
console.log('Adding method, new methods:', newMethods);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
const updatedConfig = {
|
|
606
|
-
...prev,
|
|
607
|
-
paymentMethod: newMethods,
|
|
608
|
-
};
|
|
609
|
-
console.log('Updated android config payment methods:', updatedConfig.paymentMethod);
|
|
610
|
-
return updatedConfig;
|
|
611
|
-
});
|
|
612
|
-
};
|
|
613
|
-
|
|
614
|
-
const toggleInterval = (interval) => {
|
|
615
|
-
setRecurringData(prev => ({
|
|
616
|
-
...prev,
|
|
617
|
-
intervals: prev.intervals.includes(interval)
|
|
618
|
-
? prev.intervals.filter(i => i !== interval)
|
|
619
|
-
: [...prev.intervals, interval],
|
|
620
|
-
}));
|
|
621
|
-
};
|
|
622
|
-
|
|
623
|
-
const handlePayment = async () => {
|
|
624
|
-
if (!amount || isNaN(parseFloat(amount)) || parseFloat(amount) <= 0) {
|
|
625
|
-
return Alert.alert('Error', 'Please enter a valid amount');
|
|
626
|
-
}
|
|
627
|
-
|
|
628
|
-
// Validate that at least one interval is selected when recurring payment is enabled
|
|
629
|
-
if (isRecurring && (!recurringData.intervals || recurringData.intervals.length === 0)) {
|
|
630
|
-
return Alert.alert('Error', 'Please select at least one interval for recurring payment');
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
setLoading(true);
|
|
634
|
-
|
|
635
|
-
// Add a timeout to ensure loading state is reset even if SDK blocks execution
|
|
636
|
-
const timeoutId = setTimeout(() => {
|
|
637
|
-
setLoading(false);
|
|
638
|
-
}, 3000); // 3 second timeout
|
|
639
|
-
|
|
640
|
-
try {
|
|
641
|
-
if (Platform.OS === 'android') {
|
|
642
|
-
await handleAndroidBilling();
|
|
643
|
-
} else {
|
|
644
|
-
await handleIosBilling();
|
|
645
|
-
}
|
|
646
|
-
} finally {
|
|
647
|
-
clearTimeout(timeoutId);
|
|
648
|
-
setLoading(false);
|
|
649
|
-
}
|
|
650
|
-
};
|
|
651
|
-
|
|
652
|
-
const handleAndroidBilling = async () => {
|
|
653
|
-
|
|
654
|
-
const { apiKey, secretKey } = apiKeys[environment];
|
|
655
|
-
|
|
656
|
-
console.log('Selected payment methods for Android:', androidConfig.paymentMethod);
|
|
657
|
-
console.log('Full androidConfig.paymentMethod:', JSON.stringify(androidConfig.paymentMethod));
|
|
658
|
-
|
|
659
|
-
// Create a fresh copy of payment methods to ensure no reference issues
|
|
660
|
-
const selectedPaymentMethods = [...androidConfig.paymentMethod];
|
|
661
|
-
console.log('Fresh copy of payment methods:', selectedPaymentMethods);
|
|
662
|
-
console.log('Payment method contains "ach":', selectedPaymentMethods.includes('ach'));
|
|
663
|
-
console.log('Payment method contains "card":', selectedPaymentMethods.includes('card'));
|
|
664
|
-
|
|
665
|
-
// Log ACH-specific configurations when ACH is selected
|
|
666
|
-
if (selectedPaymentMethods.includes('ach')) {
|
|
667
|
-
console.log('=== ACH CONFIGURATION DEBUG ===');
|
|
668
|
-
console.log('authenticatedACH setting:', isAuthenticatedACH);
|
|
669
|
-
console.log('secureAuthentication setting:', isSecureAuthentication);
|
|
670
|
-
console.log('saveAccount setting:', androidConfig.saveAccount);
|
|
671
|
-
}
|
|
672
|
-
|
|
673
|
-
// Try different payment method format for ACH-only scenario
|
|
674
|
-
let finalPaymentMethods = selectedPaymentMethods;
|
|
675
|
-
if (selectedPaymentMethods.length === 1 && selectedPaymentMethods.includes('ach')) {
|
|
676
|
-
// Try using a different format for ACH-only
|
|
677
|
-
finalPaymentMethods = ['ach'];
|
|
678
|
-
console.log('Using ACH-only format:', finalPaymentMethods);
|
|
679
|
-
}
|
|
680
|
-
|
|
681
|
-
const config = {
|
|
682
|
-
amount,
|
|
683
|
-
apiKey: apiKey,
|
|
684
|
-
secretKey: secretKey,
|
|
685
|
-
jsonConfig: {
|
|
686
|
-
environment,
|
|
687
|
-
amount,
|
|
688
|
-
tokenOnly: false,
|
|
689
|
-
currency: androidConfig.currency,
|
|
690
|
-
saveCard: androidConfig.saveCard,
|
|
691
|
-
saveAccount: androidConfig.saveAccount,
|
|
692
|
-
authenticatedACH: isAuthenticatedACH,
|
|
693
|
-
secureAuthentication: isSecureAuthentication,
|
|
694
|
-
|
|
695
|
-
showReceipt: androidConfig.showReceipt,
|
|
696
|
-
showDonate: androidConfig.showDonate,
|
|
697
|
-
showTotal: androidConfig.showTotal,
|
|
698
|
-
showSubmitButton: androidConfig.showSubmitButton,
|
|
699
|
-
paymentMethod: finalPaymentMethods,
|
|
700
|
-
// Try different configuration approaches for ACH-only
|
|
701
|
-
...(finalPaymentMethods.length === 1 && finalPaymentMethods.includes('ach') && {
|
|
702
|
-
paymentMethods: ['ach'],
|
|
703
|
-
allowedPaymentMethods: ['ach'],
|
|
704
|
-
disableCard: true,
|
|
705
|
-
}),
|
|
706
|
-
|
|
707
|
-
emailEditable,
|
|
708
|
-
email,
|
|
709
|
-
name: name,
|
|
710
|
-
fields: {
|
|
711
|
-
...androidConfig.fields,
|
|
712
|
-
visibility: {
|
|
713
|
-
billing: isBillingVisible,
|
|
714
|
-
additional: isAdditionalVisible,
|
|
715
|
-
},
|
|
716
|
-
},
|
|
717
|
-
|
|
718
|
-
metadata,
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
...(isRecurring && {
|
|
722
|
-
recurring: {
|
|
723
|
-
enableRecurring: true,
|
|
724
|
-
recurringData,
|
|
725
|
-
},
|
|
726
|
-
}),
|
|
727
|
-
grailPayParams,
|
|
728
|
-
appearanceSettings: androidConfig.appearanceSettings,
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
},
|
|
732
|
-
};
|
|
733
|
-
|
|
734
|
-
console.log('ENV API Keys =>', {
|
|
735
|
-
env: environment,
|
|
736
|
-
apiKeyFromEnv: apiKey,
|
|
737
|
-
secretKeyFromEnv: secretKey,
|
|
738
|
-
});
|
|
739
|
-
|
|
740
|
-
console.log('Config API Key =>', config.apiKey);
|
|
741
|
-
console.log('Config Secret Key =>', config.secretKey);
|
|
742
|
-
console.log('Full config being sent to Android SDK:', JSON.stringify(config, null, 2));
|
|
743
|
-
console.log('=== THEME CONFIGURATION DEBUG ===');
|
|
744
|
-
console.log('Android appearanceSettings:', JSON.stringify(androidConfig.appearanceSettings, null, 2));
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
try {
|
|
749
|
-
const response = await RNEasymerchantsdk.makePayment(config);
|
|
750
|
-
console.log('Full payment response:', response);
|
|
751
|
-
|
|
752
|
-
const parsedResponse = {
|
|
753
|
-
...response,
|
|
754
|
-
billingInfo: safeParseMaybeJSON(response.billingInfo),
|
|
755
|
-
additional_info: safeParseMaybeJSON(response.additional_info),
|
|
756
|
-
};
|
|
757
|
-
|
|
758
|
-
console.log('Parsed safe response:', parsedResponse);
|
|
759
|
-
|
|
760
|
-
setResult(JSON.stringify(parsedResponse, null, 2));
|
|
761
|
-
} catch (error) {
|
|
762
|
-
setResult(`Error: ${error.message}`);
|
|
763
|
-
Alert.alert('Payment Error', error.message);
|
|
764
|
-
} finally {
|
|
765
|
-
setLoading(false);
|
|
766
|
-
}
|
|
767
|
-
};
|
|
768
|
-
|
|
769
|
-
const handleIosBilling = async () => {
|
|
770
|
-
|
|
771
|
-
console.log('Selected payment methods for iOS:', androidConfig.paymentMethod);
|
|
772
|
-
console.log('Full androidConfig.paymentMethod for iOS:', JSON.stringify(androidConfig.paymentMethod));
|
|
773
|
-
|
|
774
|
-
// Create a fresh copy of payment methods for iOS and convert to iOS format
|
|
775
|
-
const selectedPaymentMethodsIOS = [...androidConfig.paymentMethod];
|
|
776
|
-
console.log('Fresh copy of payment methods for iOS:', selectedPaymentMethodsIOS);
|
|
777
|
-
console.log('Payment method contains "ach" (iOS):', selectedPaymentMethodsIOS.includes('ach'));
|
|
778
|
-
console.log('Payment method contains "card" (iOS):', selectedPaymentMethodsIOS.includes('card'));
|
|
779
|
-
|
|
780
|
-
// Convert Android payment method names to iOS format
|
|
781
|
-
let finalPaymentMethodsIOS = selectedPaymentMethodsIOS.map(method => {
|
|
782
|
-
if (method === 'card') return 'Card';
|
|
783
|
-
if (method === 'ach') return 'Bank';
|
|
784
|
-
return method;
|
|
785
|
-
});
|
|
786
|
-
|
|
787
|
-
console.log('Converted payment methods for iOS:', finalPaymentMethodsIOS);
|
|
788
|
-
console.log('=== iOS THEME CONFIGURATION DEBUG ===');
|
|
789
|
-
console.log('iOS themeConfiguration:', JSON.stringify(themeConfiguration, null, 2));
|
|
790
|
-
|
|
791
|
-
try {
|
|
792
|
-
const result = await EasyMerchantSdk.billing(
|
|
793
|
-
amount,
|
|
794
|
-
androidConfig.currency || 'usd',
|
|
795
|
-
billingInfo,
|
|
796
|
-
finalPaymentMethodsIOS,
|
|
797
|
-
themeConfiguration,
|
|
798
|
-
false, // tokenOnly
|
|
799
|
-
androidConfig.saveCard,
|
|
800
|
-
androidConfig.saveAccount,
|
|
801
|
-
isAuthenticatedACH,
|
|
802
|
-
grailPayParams,
|
|
803
|
-
'Submit',
|
|
804
|
-
isRecurring,
|
|
805
|
-
isRecurring ? recurringData.allowCycles : 0,
|
|
806
|
-
isRecurring ? recurringData.intervals : [],
|
|
807
|
-
isRecurring ? recurringData.recurringStartType : '',
|
|
808
|
-
isRecurring ? recurringData.recurringStartDate : '',
|
|
809
|
-
isSecureAuthentication,
|
|
810
|
-
androidConfig.showReceipt,
|
|
811
|
-
androidConfig.showTotal,
|
|
812
|
-
androidConfig.showSubmitButton,
|
|
813
|
-
isEmail,
|
|
814
|
-
email,
|
|
815
|
-
name,
|
|
816
|
-
metadata
|
|
817
|
-
);
|
|
818
|
-
|
|
819
|
-
const refToken = result?.additionalInfo?.threeDSecureStatus?.data?.ref_token;
|
|
820
|
-
if (refToken) setReferenceToken(refToken);
|
|
821
|
-
setResult(JSON.stringify(result, null, 2));
|
|
822
|
-
} catch (error) {
|
|
823
|
-
console.error('Billing Error:', error);
|
|
824
|
-
setResult(`Billing Error: ${error.message || JSON.stringify(error)}`);
|
|
825
|
-
} finally {
|
|
826
|
-
setLoading(false);
|
|
827
|
-
}
|
|
828
|
-
};
|
|
829
|
-
|
|
830
|
-
const handleCheckStatus = async () => {
|
|
831
|
-
setLoading(true);
|
|
832
|
-
try {
|
|
833
|
-
const response = await RNEasymerchantsdk.checkPaymentStatus();
|
|
834
|
-
console.log('Full payment response:', response);
|
|
835
|
-
setResult(JSON.stringify(response, null, 2));
|
|
836
|
-
} catch (error) {
|
|
837
|
-
setResult(`Error: ${error.message}`);
|
|
838
|
-
Alert.alert('Status Check Error', error.message);
|
|
839
|
-
} finally {
|
|
840
|
-
setLoading(false);
|
|
841
|
-
}
|
|
842
|
-
};
|
|
843
|
-
|
|
844
|
-
const handlePaymentReference = async () => {
|
|
845
|
-
if (Platform.OS === 'android') {
|
|
846
|
-
setResult('Payment Reference not supported on Android');
|
|
847
|
-
return;
|
|
848
|
-
}
|
|
849
|
-
try {
|
|
850
|
-
const response = await EasyMerchantSdk.paymentReference(referenceToken);
|
|
851
|
-
setResult(`Payment Reference:\n${JSON.stringify(response, null, 2)}`);
|
|
852
|
-
} catch (error) {
|
|
853
|
-
setResult(`Payment Reference Error: ${error.message || JSON.stringify(error)}`);
|
|
854
|
-
} finally {
|
|
855
|
-
setLoading(false);
|
|
856
|
-
}
|
|
857
|
-
};
|
|
858
|
-
|
|
859
|
-
return (
|
|
860
|
-
<KeyboardAvoidingView
|
|
861
|
-
style={styles.container}
|
|
862
|
-
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
|
|
863
|
-
keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : 20}
|
|
864
|
-
>
|
|
865
|
-
<ScrollView
|
|
866
|
-
contentContainerStyle={styles.scrollContent}
|
|
867
|
-
keyboardShouldPersistTaps="handled"
|
|
868
|
-
showsVerticalScrollIndicator={false}
|
|
869
|
-
>
|
|
870
|
-
<Text style={styles.title}>EasyMerchant SDK</Text>
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
<Text style={styles.sectionTitle}>Basic Info</Text>
|
|
875
|
-
<Text style={styles.label}>Amount</Text>
|
|
876
|
-
<TextInput
|
|
877
|
-
style={styles.input}
|
|
878
|
-
placeholder="Enter amount (e.g., 10.00)"
|
|
879
|
-
placeholderTextColor="#999999"
|
|
880
|
-
keyboardType="decimal-pad"
|
|
881
|
-
value={amount}
|
|
882
|
-
onChangeText={setAmount}
|
|
883
|
-
/>
|
|
884
|
-
<Text style={styles.label}>Email</Text>
|
|
885
|
-
<TextInput
|
|
886
|
-
style={styles.input}
|
|
887
|
-
placeholder="Enter email"
|
|
888
|
-
placeholderTextColor="#999999"
|
|
889
|
-
keyboardType="email-address"
|
|
890
|
-
value={email}
|
|
891
|
-
onChangeText={setEmail}
|
|
892
|
-
/>
|
|
893
|
-
<Text style={styles.label}>Name</Text>
|
|
894
|
-
<TextInput
|
|
895
|
-
style={styles.input}
|
|
896
|
-
placeholder="Enter name"
|
|
897
|
-
placeholderTextColor="#999999"
|
|
898
|
-
value={name}
|
|
899
|
-
onChangeText={setName}
|
|
900
|
-
/>
|
|
901
|
-
|
|
902
|
-
<View style={styles.buttonGroup}>
|
|
903
|
-
<FilledButton
|
|
904
|
-
title="Pay"
|
|
905
|
-
onPress={handlePayment}
|
|
906
|
-
disabled={loading}
|
|
907
|
-
/>
|
|
908
|
-
{Platform.OS === 'ios' && (
|
|
909
|
-
<FilledButton
|
|
910
|
-
title="Payment Ref"
|
|
911
|
-
onPress={handlePaymentReference}
|
|
912
|
-
disabled={loading}
|
|
913
|
-
/>
|
|
914
|
-
)}
|
|
915
|
-
</View>
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
<View style={styles.toggleContainer}>
|
|
922
|
-
<Text style={styles.label}>Show Configurations</Text>
|
|
923
|
-
<Switch
|
|
924
|
-
value={showConfig}
|
|
925
|
-
onValueChange={setShowConfig}
|
|
926
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
927
|
-
thumbColor={showConfig ? '#fff' : '#f4f3f4'}
|
|
928
|
-
/>
|
|
929
|
-
</View>
|
|
930
|
-
|
|
931
|
-
{showConfig && (
|
|
932
|
-
<>
|
|
933
|
-
<Text style={styles.sectionTitle}>Environment</Text>
|
|
934
|
-
<View style={styles.pickerContainer}>
|
|
935
|
-
<Text style={styles.label}>Select Environment</Text>
|
|
936
|
-
<View style={styles.buttonGroup}>
|
|
937
|
-
<TouchableOpacity
|
|
938
|
-
style={[
|
|
939
|
-
styles.environmentButton,
|
|
940
|
-
{ backgroundColor: environment === 'sandbox' ? '#2563EB' : '#ccc' },
|
|
941
|
-
]}
|
|
942
|
-
onPress={() => {
|
|
943
|
-
console.log('Sandbox tapped, setting environment to sandbox');
|
|
944
|
-
setEnvironment('sandbox');
|
|
945
|
-
}}
|
|
946
|
-
disabled={isEnvironmentLoading || environment === 'sandbox'}
|
|
947
|
-
>
|
|
948
|
-
<Text style={styles.buttonText}>Sandbox</Text>
|
|
949
|
-
</TouchableOpacity>
|
|
950
|
-
<TouchableOpacity
|
|
951
|
-
style={[
|
|
952
|
-
styles.environmentButton,
|
|
953
|
-
{ backgroundColor: environment === 'staging' ? '#2563EB' : '#ccc' },
|
|
954
|
-
]}
|
|
955
|
-
onPress={() => {
|
|
956
|
-
console.log('Staging tapped, setting environment to staging');
|
|
957
|
-
setEnvironment('staging');
|
|
958
|
-
}}
|
|
959
|
-
disabled={isEnvironmentLoading || environment === 'staging'}
|
|
960
|
-
>
|
|
961
|
-
<Text style={styles.buttonText}>Staging</Text>
|
|
962
|
-
</TouchableOpacity>
|
|
963
|
-
</View>
|
|
964
|
-
</View>
|
|
965
|
-
|
|
966
|
-
<Text style={styles.sectionTitle}>{environment === 'sandbox' ? 'Sandbox' : 'Staging'} API Credentials</Text>
|
|
967
|
-
<Text style={styles.label}>API Key</Text>
|
|
968
|
-
<TextInput
|
|
969
|
-
style={styles.input}
|
|
970
|
-
value={apiKeys[environment].apiKey}
|
|
971
|
-
onChangeText={value =>
|
|
972
|
-
setApiKeys(prev => ({
|
|
973
|
-
...prev,
|
|
974
|
-
[environment]: { ...prev[environment], apiKey: value },
|
|
975
|
-
}))
|
|
976
|
-
}
|
|
977
|
-
placeholder={`Enter ${environment === 'sandbox' ? 'Sandbox' : 'Staging'} API Key`}
|
|
978
|
-
placeholderTextColor="#999999"
|
|
979
|
-
/>
|
|
980
|
-
<Text style={styles.label}>Secret Key</Text>
|
|
981
|
-
<View style={styles.inputContainer}>
|
|
982
|
-
<TextInput
|
|
983
|
-
style={[styles.input, { flex: 1 }]}
|
|
984
|
-
value={apiKeys[environment].secretKey}
|
|
985
|
-
onChangeText={value =>
|
|
986
|
-
setApiKeys(prev => ({
|
|
987
|
-
...prev,
|
|
988
|
-
[environment]: { ...prev[environment], secretKey: value },
|
|
989
|
-
}))
|
|
990
|
-
}
|
|
991
|
-
placeholder={`Enter ${environment === 'sandbox' ? 'Sandbox' : 'Staging'} Secret Key`}
|
|
992
|
-
placeholderTextColor="#999999"
|
|
993
|
-
secureTextEntry={!showSecretKey}
|
|
994
|
-
/>
|
|
995
|
-
<TouchableOpacity
|
|
996
|
-
style={styles.eyeButton}
|
|
997
|
-
onPress={() => setShowSecretKey(prev => !prev)}
|
|
998
|
-
>
|
|
999
|
-
<Text style={styles.eyeIcon}>{showSecretKey ? '👁️' : '👁️🗨️'}</Text>
|
|
1000
|
-
</TouchableOpacity>
|
|
1001
|
-
</View>
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
<Text style={styles.sectionTitle}>Payment Options</Text>
|
|
1008
|
-
<View style={styles.toggleContainer}>
|
|
1009
|
-
<Text style={styles.label}>Recurring Payment</Text>
|
|
1010
|
-
<Switch
|
|
1011
|
-
value={isRecurring}
|
|
1012
|
-
onValueChange={setIsRecurring}
|
|
1013
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1014
|
-
thumbColor={isRecurring ? '#fff' : '#f4f3f4'}
|
|
1015
|
-
/>
|
|
1016
|
-
</View>
|
|
1017
|
-
<View style={styles.toggleContainer}>
|
|
1018
|
-
<Text style={styles.label}>Authenticated ACH</Text>
|
|
1019
|
-
<Switch
|
|
1020
|
-
value={isAuthenticatedACH}
|
|
1021
|
-
onValueChange={setAuthenticatedACH}
|
|
1022
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1023
|
-
thumbColor={isAuthenticatedACH ? '#fff' : '#f4f3f4'}
|
|
1024
|
-
/>
|
|
1025
|
-
</View>
|
|
1026
|
-
<View style={styles.toggleContainer}>
|
|
1027
|
-
<Text style={styles.label}>3DS</Text>
|
|
1028
|
-
<Switch
|
|
1029
|
-
value={isSecureAuthentication}
|
|
1030
|
-
onValueChange={setSecureAuthentication}
|
|
1031
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1032
|
-
thumbColor={isSecureAuthentication ? '#fff' : '#f4f3f4'}
|
|
1033
|
-
/>
|
|
1034
|
-
</View>
|
|
1035
|
-
<View style={styles.toggleContainer}>
|
|
1036
|
-
<Text style={styles.label}>Billing Visible</Text>
|
|
1037
|
-
<Switch
|
|
1038
|
-
value={isBillingVisible}
|
|
1039
|
-
onValueChange={setBillingVisible}
|
|
1040
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1041
|
-
thumbColor={isBillingVisible ? '#fff' : '#f4f3f4'}
|
|
1042
|
-
/>
|
|
1043
|
-
</View>
|
|
1044
|
-
<View style={styles.toggleContainer}>
|
|
1045
|
-
<Text style={styles.label}>Additional Info Visible</Text>
|
|
1046
|
-
<Switch
|
|
1047
|
-
value={isAdditionalVisible}
|
|
1048
|
-
onValueChange={setAdditionalVisible}
|
|
1049
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1050
|
-
thumbColor={isAdditionalVisible ? '#fff' : '#f4f3f4'}
|
|
1051
|
-
/>
|
|
1052
|
-
</View>
|
|
1053
|
-
<Text style={styles.label}>Payment Methods (Shared)</Text>
|
|
1054
|
-
<Text style={styles.debugText}>
|
|
1055
|
-
Selected: {androidConfig.paymentMethod.join(', ') || 'None'}
|
|
1056
|
-
</Text>
|
|
1057
|
-
<View style={styles.buttonGroup}>
|
|
1058
|
-
<FilledButton
|
|
1059
|
-
title="Card"
|
|
1060
|
-
onPress={() => togglePaymentMethod('card')}
|
|
1061
|
-
disabled={loading}
|
|
1062
|
-
style={[
|
|
1063
|
-
{ flex: 1 },
|
|
1064
|
-
androidConfig.paymentMethod.includes('card')
|
|
1065
|
-
? { backgroundColor: '#2563EB' }
|
|
1066
|
-
: { backgroundColor: '#E5E7EB' }
|
|
1067
|
-
]}
|
|
1068
|
-
textStyle={androidConfig.paymentMethod.includes('card')
|
|
1069
|
-
? { color: '#fff' }
|
|
1070
|
-
: { color: '#374151' }
|
|
1071
|
-
}
|
|
1072
|
-
/>
|
|
1073
|
-
<FilledButton
|
|
1074
|
-
title="ACH"
|
|
1075
|
-
onPress={() => togglePaymentMethod('ach')}
|
|
1076
|
-
disabled={loading}
|
|
1077
|
-
style={[
|
|
1078
|
-
{ flex: 1 },
|
|
1079
|
-
androidConfig.paymentMethod.includes('ach')
|
|
1080
|
-
? { backgroundColor: '#2563EB' }
|
|
1081
|
-
: { backgroundColor: '#E5E7EB' }
|
|
1082
|
-
]}
|
|
1083
|
-
textStyle={androidConfig.paymentMethod.includes('ach')
|
|
1084
|
-
? { color: '#fff' }
|
|
1085
|
-
: { color: '#374151' }
|
|
1086
|
-
}
|
|
1087
|
-
/>
|
|
1088
|
-
</View>
|
|
1089
|
-
{Platform.OS === 'android' && (
|
|
1090
|
-
<View style={styles.toggleContainer}>
|
|
1091
|
-
<Text style={styles.label}>Email Editable</Text>
|
|
1092
|
-
<Switch
|
|
1093
|
-
value={emailEditable}
|
|
1094
|
-
onValueChange={setEmailEditable}
|
|
1095
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1096
|
-
thumbColor={emailEditable ? '#fff' : '#f4f3f4'}
|
|
1097
|
-
/>
|
|
1098
|
-
</View>
|
|
1099
|
-
)}
|
|
1100
|
-
{Platform.OS === 'ios' && (
|
|
1101
|
-
<View style={styles.toggleContainer}>
|
|
1102
|
-
<Text style={styles.label}>Allow Email Editable</Text>
|
|
1103
|
-
<Switch
|
|
1104
|
-
value={isEmail}
|
|
1105
|
-
onValueChange={setIsEmail}
|
|
1106
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1107
|
-
thumbColor={isEmail ? '#fff' : '#f4f3f4'}
|
|
1108
|
-
/>
|
|
1109
|
-
</View>
|
|
1110
|
-
)}
|
|
1111
|
-
|
|
1112
|
-
<Text style={styles.sectionTitle}>Billing Info</Text>
|
|
1113
|
-
|
|
1114
|
-
{/* Billing Required Switches */}
|
|
1115
|
-
<Text style={styles.subsectionTitle}>Billing Required Fields</Text>
|
|
1116
|
-
<Text style={styles.label}>Billing Required: Address</Text>
|
|
1117
|
-
<Switch
|
|
1118
|
-
value={billingInfo.billingRequired.address}
|
|
1119
|
-
onValueChange={value => updateBillingInfo('billingRequired', 'address', value)}
|
|
1120
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1121
|
-
thumbColor={billingInfo.billingRequired.address ? '#fff' : '#f4f3f4'}
|
|
1122
|
-
/>
|
|
1123
|
-
<Text style={styles.label}>Billing Required: Country</Text>
|
|
1124
|
-
<Switch
|
|
1125
|
-
value={billingInfo.billingRequired.country}
|
|
1126
|
-
onValueChange={value => updateBillingInfo('billingRequired', 'country', value)}
|
|
1127
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1128
|
-
thumbColor={billingInfo.billingRequired.country ? '#fff' : '#f4f3f4'}
|
|
1129
|
-
/>
|
|
1130
|
-
<Text style={styles.label}>Billing Required: State</Text>
|
|
1131
|
-
<Switch
|
|
1132
|
-
value={billingInfo.billingRequired.state}
|
|
1133
|
-
onValueChange={value => updateBillingInfo('billingRequired', 'state', value)}
|
|
1134
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1135
|
-
thumbColor={billingInfo.billingRequired.state ? '#fff' : '#f4f3f4'}
|
|
1136
|
-
/>
|
|
1137
|
-
<Text style={styles.label}>Billing Required: City</Text>
|
|
1138
|
-
<Switch
|
|
1139
|
-
value={billingInfo.billingRequired.city}
|
|
1140
|
-
onValueChange={value => updateBillingInfo('billingRequired', 'city', value)}
|
|
1141
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1142
|
-
thumbColor={billingInfo.billingRequired.city ? '#fff' : '#f4f3f4'}
|
|
1143
|
-
/>
|
|
1144
|
-
<Text style={styles.label}>Billing Required: Postal Code</Text>
|
|
1145
|
-
<Switch
|
|
1146
|
-
value={billingInfo.billingRequired.postal_code}
|
|
1147
|
-
onValueChange={value => updateBillingInfo('billingRequired', 'postal_code', value)}
|
|
1148
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1149
|
-
thumbColor={billingInfo.billingRequired.postal_code ? '#fff' : '#f4f3f4'}
|
|
1150
|
-
/>
|
|
1151
|
-
|
|
1152
|
-
{/* Billing Fields Section */}
|
|
1153
|
-
<Text style={styles.subsectionTitle}>Billing Fields</Text>
|
|
1154
|
-
{billingInfo.billingRequired.address && (
|
|
1155
|
-
<>
|
|
1156
|
-
<Text style={styles.label}>Billing Address</Text>
|
|
1157
|
-
<TextInput
|
|
1158
|
-
style={styles.input}
|
|
1159
|
-
value={billingInfo.billing.address}
|
|
1160
|
-
onChangeText={value => updateBillingInfo('billing', 'address', value)}
|
|
1161
|
-
placeholder="Enter billing address"
|
|
1162
|
-
placeholderTextColor="#999999"
|
|
1163
|
-
/>
|
|
1164
|
-
</>
|
|
1165
|
-
)}
|
|
1166
|
-
{billingInfo.billingRequired.country && (
|
|
1167
|
-
<>
|
|
1168
|
-
<Text style={styles.label}>Billing Country</Text>
|
|
1169
|
-
<Dropdown
|
|
1170
|
-
value={billingInfo.billing.country}
|
|
1171
|
-
onValueChange={value => updateBillingInfo('billing', 'country', value)}
|
|
1172
|
-
options={[
|
|
1173
|
-
"Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
|
|
1174
|
-
"Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
|
|
1175
|
-
"Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
|
|
1176
|
-
"Bahamas", "Bahrain", "Bangladesh", "Barbados", "Belarus",
|
|
1177
|
-
"Belgium", "Belize", "Benin", "Bermuda", "Bhutan",
|
|
1178
|
-
"Bolivia", "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil",
|
|
1179
|
-
"British Indian Ocean Territory", "Brunei Darussalam", "Bulgaria", "Burkina Faso", "Burundi",
|
|
1180
|
-
"Cabo Verde", "Cambodia", "Cameroon", "Canada", "Cayman Islands",
|
|
1181
|
-
"Central African Republic", "Chad", "Chile", "China", "Christmas Island",
|
|
1182
|
-
"Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo", "Congo, Democratic Republic of the",
|
|
1183
|
-
"Cook Islands", "Costa Rica", "Croatia", "Cuba", "Curaçao",
|
|
1184
|
-
"Cyprus", "Czech Republic", "Côte d'Ivoire", "Denmark", "Djibouti",
|
|
1185
|
-
"Dominica", "Dominican Republic", "Ecuador", "Egypt", "El Salvador",
|
|
1186
|
-
"Equatorial Guinea", "Eritrea", "Estonia", "Eswatini", "Ethiopia",
|
|
1187
|
-
"Falkland Islands (Malvinas)", "Faroe Islands", "Fiji", "Finland", "France",
|
|
1188
|
-
"French Guiana", "French Polynesia", "French Southern Territories", "Gabon", "Gambia",
|
|
1189
|
-
"Georgia", "Germany", "Ghana", "Gibraltar", "Greece",
|
|
1190
|
-
"Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala",
|
|
1191
|
-
"Guernsey", "Guinea", "Guinea-Bissau", "Guyana", "Haiti",
|
|
1192
|
-
"Heard Island and McDonald Islands", "Holy See", "Honduras", "Hong Kong", "Hungary",
|
|
1193
|
-
"Iceland", "India", "Indonesia", "Iran", "Iraq",
|
|
1194
|
-
"Ireland", "Isle of Man", "Israel", "Italy", "Jamaica",
|
|
1195
|
-
"Japan", "Jersey", "Jordan", "Kazakhstan", "Kenya",
|
|
1196
|
-
"Kiribati", "Korea (Democratic People's Republic of)", "Korea, Republic of", "Kuwait", "Kyrgyzstan",
|
|
1197
|
-
"Lao People's Democratic Republic", "Latvia", "Lebanon", "Lesotho", "Liberia",
|
|
1198
|
-
"Libya", "Liechtenstein", "Lithuania", "Luxembourg", "Macao",
|
|
1199
|
-
"Madagascar", "Malawi", "Malaysia", "Maldives", "Mali",
|
|
1200
|
-
"Malta", "Marshall Islands", "Martinique", "Mauritania", "Mauritius",
|
|
1201
|
-
"Mayotte", "Mexico", "Micronesia (Federated States of)", "Moldova", "Monaco",
|
|
1202
|
-
"Mongolia", "Montenegro", "Montserrat", "Morocco", "Mozambique",
|
|
1203
|
-
"Myanmar", "Namibia", "Nauru", "Nepal", "Netherlands",
|
|
1204
|
-
"New Caledonia", "New Zealand", "Nicaragua", "Niger", "Nigeria",
|
|
1205
|
-
"Niue", "Norfolk Island", "North Macedonia", "Northern Mariana Islands", "Norway",
|
|
1206
|
-
"Oman", "Pakistan", "Palau", "Palestine, State of", "Panama",
|
|
1207
|
-
"Papua New Guinea", "Paraguay", "Peru", "Philippines", "Pitcairn",
|
|
1208
|
-
"Poland", "Portugal", "Puerto Rico", "Qatar", "Romania",
|
|
1209
|
-
"Russian Federation", "Rwanda", "Réunion", "Saint Barthélemy", "Saint Helena, Ascension and Tristan da Cunha",
|
|
1210
|
-
"Saint Kitts and Nevis", "Saint Lucia", "Saint Martin (French part)", "Saint Pierre and Miquelon", "Saint Vincent and the Grenadines",
|
|
1211
|
-
"Samoa", "San Marino", "Sao Tome and Principe", "Saudi Arabia", "Senegal",
|
|
1212
|
-
"Serbia", "Seychelles", "Sierra Leone", "Singapore", "Sint Maarten (Dutch part)",
|
|
1213
|
-
"Slovakia", "Slovenia", "Solomon Islands", "Somalia", "South Africa",
|
|
1214
|
-
"South Georgia and the South Sandwich Islands", "South Sudan", "Spain", "Sri Lanka", "Sudan",
|
|
1215
|
-
"Suriname", "Svalbard and Jan Mayen", "Sweden", "Switzerland", "Syrian Arab Republic",
|
|
1216
|
-
"Taiwan, Province of China", "Tajikistan", "Tanzania", "Thailand", "Timor-Leste",
|
|
1217
|
-
"Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia",
|
|
1218
|
-
"Turkey", "Turkmenistan", "Tuvalu", "Uganda", "Ukraine",
|
|
1219
|
-
"United Arab Emirates", "United Kingdom", "United States", "Uruguay", "Uzbekistan",
|
|
1220
|
-
"Vanuatu", "Venezuela", "Viet Nam", "Western Sahara", "Yemen",
|
|
1221
|
-
"Zambia", "Zimbabwe", "Åland Islands"
|
|
1222
|
-
]}
|
|
1223
|
-
placeholder="Select country"
|
|
1224
|
-
/>
|
|
1225
|
-
</>
|
|
1226
|
-
)}
|
|
1227
|
-
{billingInfo.billingRequired.state && (
|
|
1228
|
-
<>
|
|
1229
|
-
<Text style={styles.label}>Billing State</Text>
|
|
1230
|
-
<TextInput
|
|
1231
|
-
style={styles.input}
|
|
1232
|
-
value={billingInfo.billing.state}
|
|
1233
|
-
onChangeText={value => updateBillingInfo('billing', 'state', value)}
|
|
1234
|
-
placeholder="Enter state"
|
|
1235
|
-
placeholderTextColor="#999999"
|
|
1236
|
-
/>
|
|
1237
|
-
</>
|
|
1238
|
-
)}
|
|
1239
|
-
{billingInfo.billingRequired.city && (
|
|
1240
|
-
<>
|
|
1241
|
-
<Text style={styles.label}>Billing City</Text>
|
|
1242
|
-
<TextInput
|
|
1243
|
-
style={styles.input}
|
|
1244
|
-
value={billingInfo.billing.city}
|
|
1245
|
-
onChangeText={value => updateBillingInfo('billing', 'city', value)}
|
|
1246
|
-
placeholder="Enter city"
|
|
1247
|
-
placeholderTextColor="#999999"
|
|
1248
|
-
/>
|
|
1249
|
-
</>
|
|
1250
|
-
)}
|
|
1251
|
-
{billingInfo.billingRequired.postal_code && (
|
|
1252
|
-
<>
|
|
1253
|
-
<Text style={styles.label}>Billing Postal Code</Text>
|
|
1254
|
-
<TextInput
|
|
1255
|
-
style={styles.input}
|
|
1256
|
-
value={billingInfo.billing.postal_code}
|
|
1257
|
-
onChangeText={value => updateBillingInfo('billing', 'postal_code', value)}
|
|
1258
|
-
placeholder="Enter postal code"
|
|
1259
|
-
placeholderTextColor="#999999"
|
|
1260
|
-
/>
|
|
1261
|
-
</>
|
|
1262
|
-
)}
|
|
1263
|
-
|
|
1264
|
-
<Text style={styles.sectionTitle}>Additional Info</Text>
|
|
1265
|
-
|
|
1266
|
-
{/* Additional Required Switches */}
|
|
1267
|
-
<Text style={styles.subsectionTitle}>Additional Required Fields</Text>
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
<Text style={styles.label}>Additional Required: Phone Number</Text>
|
|
1271
|
-
<Switch
|
|
1272
|
-
value={billingInfo.additionalRequired.phone_number}
|
|
1273
|
-
onValueChange={value => updateBillingInfo('additionalRequired', 'phone_number', value)}
|
|
1274
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1275
|
-
thumbColor={billingInfo.additionalRequired.phone_number ? '#fff' : '#f4f3f4'}
|
|
1276
|
-
/>
|
|
1277
|
-
<Text style={styles.label}>Additional Required: Description</Text>
|
|
1278
|
-
<Switch
|
|
1279
|
-
value={billingInfo.additionalRequired.description}
|
|
1280
|
-
onValueChange={value => updateBillingInfo('additionalRequired', 'description', value)}
|
|
1281
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1282
|
-
thumbColor={billingInfo.additionalRequired.description ? '#fff' : '#f4f3f4'}
|
|
1283
|
-
/>
|
|
1284
|
-
|
|
1285
|
-
{/* Additional Fields Section */}
|
|
1286
|
-
<Text style={styles.subsectionTitle}>Additional Fields</Text>
|
|
1287
|
-
|
|
1288
|
-
{billingInfo.additionalRequired.phone_number && (
|
|
1289
|
-
<>
|
|
1290
|
-
<Text style={styles.label}>Additional: Phone Number</Text>
|
|
1291
|
-
<View style={styles.phoneRow}>
|
|
1292
|
-
<TextInput
|
|
1293
|
-
style={styles.countryCodeInput}
|
|
1294
|
-
value={billingInfo.additional.country_code || '+1'}
|
|
1295
|
-
onChangeText={value => {
|
|
1296
|
-
// Only allow a '+' at the start, followed by up to 4 digits
|
|
1297
|
-
let filtered = value.replace(/[^+0-9]/g, '');
|
|
1298
|
-
if (!filtered.startsWith('+')) filtered = '+' + filtered.replace(/\+/g, '');
|
|
1299
|
-
filtered = filtered.slice(0, 5);
|
|
1300
|
-
// Update country code and combined phone number
|
|
1301
|
-
const phone = billingInfo.additional.phone_number || '';
|
|
1302
|
-
const phoneOnly = phone.slice((billingInfo.additional.country_code || '+1').replace('+', '').length);
|
|
1303
|
-
const combined = filtered.replace('+', '') + phoneOnly;
|
|
1304
|
-
updateBillingInfo('additional', 'country_code', filtered);
|
|
1305
|
-
updateBillingInfo('additional', 'phone_number', combined);
|
|
1306
|
-
}}
|
|
1307
|
-
placeholder="+1"
|
|
1308
|
-
placeholderTextColor="#999999"
|
|
1309
|
-
keyboardType="phone-pad"
|
|
1310
|
-
maxLength={5}
|
|
1311
|
-
/>
|
|
1312
|
-
<TextInput
|
|
1313
|
-
style={[styles.input, { flex: 1, marginBottom: 0 }]}
|
|
1314
|
-
value={(billingInfo.additional.phone_number || '').slice((billingInfo.additional.country_code || '+1').replace('+', '').length)}
|
|
1315
|
-
onChangeText={value => {
|
|
1316
|
-
// Only allow digits and limit to 10 characters
|
|
1317
|
-
const numericValue = value.replace(/[^0-9]/g, '').slice(0, 10);
|
|
1318
|
-
const code = (billingInfo.additional.country_code || '+1').replace('+', '');
|
|
1319
|
-
updateBillingInfo('additional', 'phone_number', code + numericValue);
|
|
1320
|
-
}}
|
|
1321
|
-
placeholder="Enter phone number"
|
|
1322
|
-
placeholderTextColor="#999999"
|
|
1323
|
-
keyboardType="phone-pad"
|
|
1324
|
-
maxLength={10}
|
|
1325
|
-
/>
|
|
1326
|
-
</View>
|
|
1327
|
-
</>
|
|
1328
|
-
)}
|
|
1329
|
-
{billingInfo.additionalRequired.description && (
|
|
1330
|
-
<>
|
|
1331
|
-
<Text style={styles.label}>Additional: Description</Text>
|
|
1332
|
-
<TextInput
|
|
1333
|
-
style={styles.input}
|
|
1334
|
-
value={billingInfo.additional.description}
|
|
1335
|
-
onChangeText={value => updateBillingInfo('additional', 'description', value)}
|
|
1336
|
-
placeholder="Enter description"
|
|
1337
|
-
placeholderTextColor="#999999"
|
|
1338
|
-
/>
|
|
1339
|
-
</>
|
|
1340
|
-
)}
|
|
1341
|
-
|
|
1342
|
-
{/* Android Appearance Settings */}
|
|
1343
|
-
{Platform.OS === 'android' && (
|
|
1344
|
-
<>
|
|
1345
|
-
<Text style={styles.sectionTitle}>Android Appearance Settings</Text>
|
|
1346
|
-
<Text style={styles.label}>Body Background Color</Text>
|
|
1347
|
-
<View style={styles.colorInputContainer}>
|
|
1348
|
-
<TextInput
|
|
1349
|
-
style={[styles.input, { flex: 1 }]}
|
|
1350
|
-
value={androidConfig.appearanceSettings.bodyBackgroundColor}
|
|
1351
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('bodyBackgroundColor', value)}
|
|
1352
|
-
placeholder="Enter body background color"
|
|
1353
|
-
placeholderTextColor="#999999"
|
|
1354
|
-
/>
|
|
1355
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.bodyBackgroundColor }]} />
|
|
1356
|
-
</View>
|
|
1357
|
-
<Text style={styles.label}>Container Background Color</Text>
|
|
1358
|
-
<View style={styles.colorInputContainer}>
|
|
1359
|
-
<TextInput
|
|
1360
|
-
style={[styles.input, { flex: 1 }]}
|
|
1361
|
-
value={androidConfig.appearanceSettings.containerBackgroundColor}
|
|
1362
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('containerBackgroundColor', value)}
|
|
1363
|
-
placeholder="Enter container background color"
|
|
1364
|
-
placeholderTextColor="#999999"
|
|
1365
|
-
/>
|
|
1366
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.containerBackgroundColor }]} />
|
|
1367
|
-
</View>
|
|
1368
|
-
<Text style={styles.label}>Primary Font Color</Text>
|
|
1369
|
-
<View style={styles.colorInputContainer}>
|
|
1370
|
-
<TextInput
|
|
1371
|
-
style={[styles.input, { flex: 1 }]}
|
|
1372
|
-
value={androidConfig.appearanceSettings.primaryFontColor}
|
|
1373
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('primaryFontColor', value)}
|
|
1374
|
-
placeholder="Enter primary font color"
|
|
1375
|
-
placeholderTextColor="#999999"
|
|
1376
|
-
/>
|
|
1377
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.primaryFontColor }]} />
|
|
1378
|
-
</View>
|
|
1379
|
-
<Text style={styles.label}>Secondary Font Color</Text>
|
|
1380
|
-
<View style={styles.colorInputContainer}>
|
|
1381
|
-
<TextInput
|
|
1382
|
-
style={[styles.input, { flex: 1 }]}
|
|
1383
|
-
value={androidConfig.appearanceSettings.secondaryFontColor}
|
|
1384
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('secondaryFontColor', value)}
|
|
1385
|
-
placeholder="Enter secondary font color"
|
|
1386
|
-
placeholderTextColor="#999999"
|
|
1387
|
-
/>
|
|
1388
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.secondaryFontColor }]} />
|
|
1389
|
-
</View>
|
|
1390
|
-
<Text style={styles.label}>Primary Button Background Color</Text>
|
|
1391
|
-
<View style={styles.colorInputContainer}>
|
|
1392
|
-
<TextInput
|
|
1393
|
-
style={[styles.input, { flex: 1 }]}
|
|
1394
|
-
value={androidConfig.appearanceSettings.primaryButtonBackgroundColor}
|
|
1395
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('primaryButtonBackgroundColor', value)}
|
|
1396
|
-
placeholder="Enter primary button background color"
|
|
1397
|
-
placeholderTextColor="#999999"
|
|
1398
|
-
/>
|
|
1399
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.primaryButtonBackgroundColor }]} />
|
|
1400
|
-
</View>
|
|
1401
|
-
<Text style={styles.label}>Primary Button Hover Color</Text>
|
|
1402
|
-
<View style={styles.colorInputContainer}>
|
|
1403
|
-
<TextInput
|
|
1404
|
-
style={[styles.input, { flex: 1 }]}
|
|
1405
|
-
value={androidConfig.appearanceSettings.primaryButtonHoverColor}
|
|
1406
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('primaryButtonHoverColor', value)}
|
|
1407
|
-
placeholder="Enter primary button hover color"
|
|
1408
|
-
placeholderTextColor="#999999"
|
|
1409
|
-
/>
|
|
1410
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.primaryButtonHoverColor }]} />
|
|
1411
|
-
</View>
|
|
1412
|
-
<Text style={styles.label}>Primary Button Font Color</Text>
|
|
1413
|
-
<View style={styles.colorInputContainer}>
|
|
1414
|
-
<TextInput
|
|
1415
|
-
style={[styles.input, { flex: 1 }]}
|
|
1416
|
-
value={androidConfig.appearanceSettings.primaryButtonFontColor}
|
|
1417
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('primaryButtonFontColor', value)}
|
|
1418
|
-
placeholder="Enter primary button font color"
|
|
1419
|
-
placeholderTextColor="#999999"
|
|
1420
|
-
/>
|
|
1421
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.primaryButtonFontColor }]} />
|
|
1422
|
-
</View>
|
|
1423
|
-
<Text style={styles.label}>Secondary Button Background Color</Text>
|
|
1424
|
-
<View style={styles.colorInputContainer}>
|
|
1425
|
-
<TextInput
|
|
1426
|
-
style={[styles.input, { flex: 1 }]}
|
|
1427
|
-
value={androidConfig.appearanceSettings.secondaryButtonBackgroundColor}
|
|
1428
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('secondaryButtonBackgroundColor', value)}
|
|
1429
|
-
placeholder="Enter secondary button background color"
|
|
1430
|
-
placeholderTextColor="#999999"
|
|
1431
|
-
/>
|
|
1432
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.secondaryButtonBackgroundColor }]} />
|
|
1433
|
-
</View>
|
|
1434
|
-
<Text style={styles.label}>Secondary Button Hover Color</Text>
|
|
1435
|
-
<View style={styles.colorInputContainer}>
|
|
1436
|
-
<TextInput
|
|
1437
|
-
style={[styles.input, { flex: 1 }]}
|
|
1438
|
-
value={androidConfig.appearanceSettings.secondaryButtonHoverColor}
|
|
1439
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('secondaryButtonHoverColor', value)}
|
|
1440
|
-
placeholder="Enter secondary button hover color"
|
|
1441
|
-
placeholderTextColor="#999999"
|
|
1442
|
-
/>
|
|
1443
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.secondaryButtonHoverColor }]} />
|
|
1444
|
-
</View>
|
|
1445
|
-
<Text style={styles.label}>Secondary Button Font Color</Text>
|
|
1446
|
-
<View style={styles.colorInputContainer}>
|
|
1447
|
-
<TextInput
|
|
1448
|
-
style={[styles.input, { flex: 1 }]}
|
|
1449
|
-
value={androidConfig.appearanceSettings.secondaryButtonFontColor}
|
|
1450
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('secondaryButtonFontColor', value)}
|
|
1451
|
-
placeholder="Enter secondary button font color"
|
|
1452
|
-
placeholderTextColor="#999999"
|
|
1453
|
-
/>
|
|
1454
|
-
<View style={[styles.colorPreview, { backgroundColor: androidConfig.appearanceSettings.secondaryButtonFontColor }]} />
|
|
1455
|
-
</View>
|
|
1456
|
-
<Text style={styles.label}>Border Radius</Text>
|
|
1457
|
-
<TextInput
|
|
1458
|
-
style={styles.input}
|
|
1459
|
-
value={androidConfig.appearanceSettings.borderRadius}
|
|
1460
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('borderRadius', value)}
|
|
1461
|
-
placeholder="Enter border radius"
|
|
1462
|
-
placeholderTextColor="#999999"
|
|
1463
|
-
/>
|
|
1464
|
-
<Text style={styles.label}>Font Size</Text>
|
|
1465
|
-
<TextInput
|
|
1466
|
-
style={styles.input}
|
|
1467
|
-
value={androidConfig.appearanceSettings.fontSize}
|
|
1468
|
-
onChangeText={value => updateAndroidConfigAppearanceSettings('fontSize', value)}
|
|
1469
|
-
placeholder="Enter font size"
|
|
1470
|
-
placeholderTextColor="#999999"
|
|
1471
|
-
/>
|
|
1472
|
-
|
|
1473
|
-
</>
|
|
1474
|
-
)}
|
|
1475
|
-
|
|
1476
|
-
{/* iOS Theme Configuration */}
|
|
1477
|
-
{Platform.OS === 'ios' && (
|
|
1478
|
-
<>
|
|
1479
|
-
<Text style={styles.sectionTitle}>Theme Configuration (iOS)</Text>
|
|
1480
|
-
<Text style={styles.label}>Body Background Color</Text>
|
|
1481
|
-
<View style={styles.colorInputContainer}>
|
|
1482
|
-
<TextInput
|
|
1483
|
-
style={[styles.input, { flex: 1 }]}
|
|
1484
|
-
value={themeConfiguration.bodyBackgroundColor}
|
|
1485
|
-
onChangeText={value => updateThemeConfiguration('bodyBackgroundColor', value)}
|
|
1486
|
-
placeholder="Enter body background color"
|
|
1487
|
-
placeholderTextColor="#999999"
|
|
1488
|
-
/>
|
|
1489
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.bodyBackgroundColor }]} />
|
|
1490
|
-
</View>
|
|
1491
|
-
<Text style={styles.label}>Container Background Color</Text>
|
|
1492
|
-
<View style={styles.colorInputContainer}>
|
|
1493
|
-
<TextInput
|
|
1494
|
-
style={[styles.input, { flex: 1 }]}
|
|
1495
|
-
value={themeConfiguration.containerBackgroundColor}
|
|
1496
|
-
onChangeText={value => updateThemeConfiguration('containerBackgroundColor', value)}
|
|
1497
|
-
placeholder="Enter container background color"
|
|
1498
|
-
placeholderTextColor="#999999"
|
|
1499
|
-
/>
|
|
1500
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.containerBackgroundColor }]} />
|
|
1501
|
-
</View>
|
|
1502
|
-
<Text style={styles.label}>Primary Font Color</Text>
|
|
1503
|
-
<View style={styles.colorInputContainer}>
|
|
1504
|
-
<TextInput
|
|
1505
|
-
style={[styles.input, { flex: 1 }]}
|
|
1506
|
-
value={themeConfiguration.primaryFontColor}
|
|
1507
|
-
onChangeText={value => updateThemeConfiguration('primaryFontColor', value)}
|
|
1508
|
-
placeholder="Enter primary font color"
|
|
1509
|
-
placeholderTextColor="#999999"
|
|
1510
|
-
/>
|
|
1511
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.primaryFontColor }]} />
|
|
1512
|
-
</View>
|
|
1513
|
-
<Text style={styles.label}>Secondary Font Color</Text>
|
|
1514
|
-
<View style={styles.colorInputContainer}>
|
|
1515
|
-
<TextInput
|
|
1516
|
-
style={[styles.input, { flex: 1 }]}
|
|
1517
|
-
value={themeConfiguration.secondaryFontColor}
|
|
1518
|
-
onChangeText={value => updateThemeConfiguration('secondaryFontColor', value)}
|
|
1519
|
-
placeholder="Enter secondary font color"
|
|
1520
|
-
placeholderTextColor="#999999"
|
|
1521
|
-
/>
|
|
1522
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.secondaryFontColor }]} />
|
|
1523
|
-
</View>
|
|
1524
|
-
<Text style={styles.label}>Primary Button Background Color</Text>
|
|
1525
|
-
<View style={styles.colorInputContainer}>
|
|
1526
|
-
<TextInput
|
|
1527
|
-
style={[styles.input, { flex: 1 }]}
|
|
1528
|
-
value={themeConfiguration.primaryButtonBackgroundColor}
|
|
1529
|
-
onChangeText={value => updateThemeConfiguration('primaryButtonBackgroundColor', value)}
|
|
1530
|
-
placeholder="Enter primary button background color"
|
|
1531
|
-
placeholderTextColor="#999999"
|
|
1532
|
-
/>
|
|
1533
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.primaryButtonBackgroundColor }]} />
|
|
1534
|
-
</View>
|
|
1535
|
-
<Text style={styles.label}>Primary Button Hover Color</Text>
|
|
1536
|
-
<View style={styles.colorInputContainer}>
|
|
1537
|
-
<TextInput
|
|
1538
|
-
style={[styles.input, { flex: 1 }]}
|
|
1539
|
-
value={themeConfiguration.primaryButtonHoverColor}
|
|
1540
|
-
onChangeText={value => updateThemeConfiguration('primaryButtonHoverColor', value)}
|
|
1541
|
-
placeholder="Enter primary button hover color"
|
|
1542
|
-
placeholderTextColor="#999999"
|
|
1543
|
-
/>
|
|
1544
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.primaryButtonHoverColor }]} />
|
|
1545
|
-
</View>
|
|
1546
|
-
<Text style={styles.label}>Primary Button Font Color</Text>
|
|
1547
|
-
<View style={styles.colorInputContainer}>
|
|
1548
|
-
<TextInput
|
|
1549
|
-
style={[styles.input, { flex: 1 }]}
|
|
1550
|
-
value={themeConfiguration.primaryButtonFontColor}
|
|
1551
|
-
onChangeText={value => updateThemeConfiguration('primaryButtonFontColor', value)}
|
|
1552
|
-
placeholder="Enter primary button font color"
|
|
1553
|
-
placeholderTextColor="#999999"
|
|
1554
|
-
/>
|
|
1555
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.primaryButtonFontColor }]} />
|
|
1556
|
-
</View>
|
|
1557
|
-
<Text style={styles.label}>Secondary Button Background Color</Text>
|
|
1558
|
-
<View style={styles.colorInputContainer}>
|
|
1559
|
-
<TextInput
|
|
1560
|
-
style={[styles.input, { flex: 1 }]}
|
|
1561
|
-
value={themeConfiguration.secondaryButtonBackgroundColor}
|
|
1562
|
-
onChangeText={value => updateThemeConfiguration('secondaryButtonBackgroundColor', value)}
|
|
1563
|
-
placeholder="Enter secondary button background color"
|
|
1564
|
-
placeholderTextColor="#999999"
|
|
1565
|
-
/>
|
|
1566
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.secondaryButtonBackgroundColor }]} />
|
|
1567
|
-
</View>
|
|
1568
|
-
<Text style={styles.label}>Secondary Button Hover Color</Text>
|
|
1569
|
-
<View style={styles.colorInputContainer}>
|
|
1570
|
-
<TextInput
|
|
1571
|
-
style={[styles.input, { flex: 1 }]}
|
|
1572
|
-
value={themeConfiguration.secondaryButtonHoverColor}
|
|
1573
|
-
onChangeText={value => updateThemeConfiguration('secondaryButtonHoverColor', value)}
|
|
1574
|
-
placeholder="Enter secondary button hover color"
|
|
1575
|
-
placeholderTextColor="#999999"
|
|
1576
|
-
/>
|
|
1577
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.secondaryButtonHoverColor }]} />
|
|
1578
|
-
</View>
|
|
1579
|
-
<Text style={styles.label}>Secondary Button Font Color</Text>
|
|
1580
|
-
<View style={styles.colorInputContainer}>
|
|
1581
|
-
<TextInput
|
|
1582
|
-
style={[styles.input, { flex: 1 }]}
|
|
1583
|
-
value={themeConfiguration.secondaryButtonFontColor}
|
|
1584
|
-
onChangeText={value => updateThemeConfiguration('secondaryButtonFontColor', value)}
|
|
1585
|
-
placeholder="Enter secondary button font color"
|
|
1586
|
-
placeholderTextColor="#999999"
|
|
1587
|
-
/>
|
|
1588
|
-
<View style={[styles.colorPreview, { backgroundColor: themeConfiguration.secondaryButtonFontColor }]} />
|
|
1589
|
-
</View>
|
|
1590
|
-
<Text style={styles.label}>Border Radius</Text>
|
|
1591
|
-
<TextInput
|
|
1592
|
-
style={styles.input}
|
|
1593
|
-
value={themeConfiguration.borderRadius}
|
|
1594
|
-
onChangeText={value => updateThemeConfiguration('borderRadius', value)}
|
|
1595
|
-
placeholder="Enter border radius"
|
|
1596
|
-
placeholderTextColor="#999999"
|
|
1597
|
-
/>
|
|
1598
|
-
<Text style={styles.label}>Font Size</Text>
|
|
1599
|
-
<TextInput
|
|
1600
|
-
style={styles.input}
|
|
1601
|
-
value={themeConfiguration.fontSize}
|
|
1602
|
-
onChangeText={value => updateThemeConfiguration('fontSize', value)}
|
|
1603
|
-
placeholder="Enter font size"
|
|
1604
|
-
placeholderTextColor="#999999"
|
|
1605
|
-
/>
|
|
1606
|
-
|
|
1607
|
-
</>
|
|
1608
|
-
)}
|
|
1609
|
-
|
|
1610
|
-
{/* GrailPay Parameters */}
|
|
1611
|
-
<Text style={styles.sectionTitle}>GrailPay Parameters</Text>
|
|
1612
|
-
<Text style={styles.label}>Role</Text>
|
|
1613
|
-
<TextInput
|
|
1614
|
-
style={styles.input}
|
|
1615
|
-
value={grailPayParams.role}
|
|
1616
|
-
onChangeText={value => updateGrailPayParams('role', value)}
|
|
1617
|
-
placeholder="Enter role"
|
|
1618
|
-
placeholderTextColor="#999999"
|
|
1619
|
-
/>
|
|
1620
|
-
<Text style={styles.label}>Timeout</Text>
|
|
1621
|
-
<TextInput
|
|
1622
|
-
style={styles.input}
|
|
1623
|
-
value={String(grailPayParams.timeout)}
|
|
1624
|
-
onChangeText={value => updateGrailPayParams('timeout', parseInt(value) || 10)}
|
|
1625
|
-
placeholder="Enter timeout"
|
|
1626
|
-
placeholderTextColor="#999999"
|
|
1627
|
-
/>
|
|
1628
|
-
<Text style={styles.label}>Is Sandbox</Text>
|
|
1629
|
-
<Switch
|
|
1630
|
-
value={grailPayParams.isSandbox}
|
|
1631
|
-
onValueChange={value => updateGrailPayParams('isSandbox', value)}
|
|
1632
|
-
trackColor={{ false: '#ccc', true: '#2563EB' }}
|
|
1633
|
-
thumbColor={grailPayParams.isSandbox ? '#fff' : '#f4f3f4'}
|
|
1634
|
-
/>
|
|
1635
|
-
<Text style={styles.label}>Branding Name</Text>
|
|
1636
|
-
<TextInput
|
|
1637
|
-
style={styles.input}
|
|
1638
|
-
value={grailPayParams.brandingName}
|
|
1639
|
-
onChangeText={value => updateGrailPayParams('brandingName', value)}
|
|
1640
|
-
placeholder="Enter branding name"
|
|
1641
|
-
placeholderTextColor="#999999"
|
|
1642
|
-
/>
|
|
1643
|
-
<Text style={styles.label}>Finder Subtitle</Text>
|
|
1644
|
-
<TextInput
|
|
1645
|
-
style={styles.input}
|
|
1646
|
-
value={grailPayParams.finderSubtitle}
|
|
1647
|
-
onChangeText={value => updateGrailPayParams('finderSubtitle', value)}
|
|
1648
|
-
placeholder="Enter finder subtitle"
|
|
1649
|
-
placeholderTextColor="#999999"
|
|
1650
|
-
/>
|
|
1651
|
-
<Text style={styles.label}>Search Placeholder</Text>
|
|
1652
|
-
<TextInput
|
|
1653
|
-
style={styles.input}
|
|
1654
|
-
value={grailPayParams.searchPlaceholder}
|
|
1655
|
-
onChangeText={value => updateGrailPayParams('searchPlaceholder', value)}
|
|
1656
|
-
placeholder="Enter search placeholder"
|
|
1657
|
-
placeholderTextColor="#999999"
|
|
1658
|
-
/>
|
|
1659
|
-
|
|
1660
|
-
{/* Recurring Data */}
|
|
1661
|
-
<Text style={styles.sectionTitle}>Recurring Data</Text>
|
|
1662
|
-
<Text style={styles.label}>Allow Cycles (Minimum 2)</Text>
|
|
1663
|
-
<TextInput
|
|
1664
|
-
style={styles.input}
|
|
1665
|
-
value={String(recurringData.allowCycles)}
|
|
1666
|
-
onChangeText={value => updateRecurringData('allowCycles', parseInt(value) || 2)}
|
|
1667
|
-
placeholder="Enter allowed cycles"
|
|
1668
|
-
placeholderTextColor="#999999"
|
|
1669
|
-
/>
|
|
1670
|
-
<Text style={styles.label}>Intervals</Text>
|
|
1671
|
-
<View style={styles.buttonGroup}>
|
|
1672
|
-
<FilledButton
|
|
1673
|
-
title="Daily"
|
|
1674
|
-
onPress={() => toggleInterval('daily')}
|
|
1675
|
-
disabled={loading}
|
|
1676
|
-
style={[
|
|
1677
|
-
{ flex: 1 },
|
|
1678
|
-
recurringData.intervals.includes('daily')
|
|
1679
|
-
? { backgroundColor: '#2563EB' }
|
|
1680
|
-
: { backgroundColor: '#E5E7EB' }
|
|
1681
|
-
]}
|
|
1682
|
-
textStyle={[
|
|
1683
|
-
{ fontSize: 14 },
|
|
1684
|
-
recurringData.intervals.includes('daily')
|
|
1685
|
-
? { color: '#fff' }
|
|
1686
|
-
: { color: '#374151' }
|
|
1687
|
-
]}
|
|
1688
|
-
/>
|
|
1689
|
-
<FilledButton
|
|
1690
|
-
title="Weekly"
|
|
1691
|
-
onPress={() => toggleInterval('weekly')}
|
|
1692
|
-
disabled={loading}
|
|
1693
|
-
style={[
|
|
1694
|
-
{ flex: 1 },
|
|
1695
|
-
recurringData.intervals.includes('weekly')
|
|
1696
|
-
? { backgroundColor: '#2563EB' }
|
|
1697
|
-
: { backgroundColor: '#E5E7EB' }
|
|
1698
|
-
]}
|
|
1699
|
-
textStyle={[
|
|
1700
|
-
{ fontSize: 14 },
|
|
1701
|
-
recurringData.intervals.includes('weekly')
|
|
1702
|
-
? { color: '#fff' }
|
|
1703
|
-
: { color: '#374151' }
|
|
1704
|
-
]}
|
|
1705
|
-
/>
|
|
1706
|
-
<FilledButton
|
|
1707
|
-
title="Monthly"
|
|
1708
|
-
onPress={() => toggleInterval('monthly')}
|
|
1709
|
-
disabled={loading}
|
|
1710
|
-
style={[
|
|
1711
|
-
{ flex: 1 },
|
|
1712
|
-
recurringData.intervals.includes('monthly')
|
|
1713
|
-
? { backgroundColor: '#2563EB' }
|
|
1714
|
-
: { backgroundColor: '#E5E7EB' }
|
|
1715
|
-
]}
|
|
1716
|
-
textStyle={[
|
|
1717
|
-
{ fontSize: 14 },
|
|
1718
|
-
recurringData.intervals.includes('monthly')
|
|
1719
|
-
? { color: '#fff' }
|
|
1720
|
-
: { color: '#374151' }
|
|
1721
|
-
]}
|
|
1722
|
-
/>
|
|
1723
|
-
</View>
|
|
1724
|
-
<Text style={styles.label}>Recurring Start Type</Text>
|
|
1725
|
-
<Dropdown
|
|
1726
|
-
value={recurringData.recurringStartType}
|
|
1727
|
-
onValueChange={value => updateRecurringData('recurringStartType', value)}
|
|
1728
|
-
options={Platform.OS === 'android' ? ['Custom', 'Fixed'] : ['custom', 'fixed']}
|
|
1729
|
-
placeholder="Select start type"
|
|
1730
|
-
/>
|
|
1731
|
-
<Text style={styles.label}>Recurring Start Date</Text>
|
|
1732
|
-
<TextInput
|
|
1733
|
-
style={[styles.input, styles.dateInput]}
|
|
1734
|
-
value={recurringData.recurringStartDate}
|
|
1735
|
-
onChangeText={value => updateRecurringData('recurringStartDate', value)}
|
|
1736
|
-
placeholder="MM/DD/YYYY"
|
|
1737
|
-
placeholderTextColor="#999999"
|
|
1738
|
-
returnKeyType="done"
|
|
1739
|
-
onSubmitEditing={() => Keyboard.dismiss()}
|
|
1740
|
-
/>
|
|
1741
|
-
</>
|
|
1742
|
-
)}
|
|
1743
|
-
|
|
1744
|
-
<Text style={styles.sectionTitle}>SDK Response</Text>
|
|
1745
|
-
<Text selectable style={styles.result}>{result || 'No response yet'}</Text>
|
|
1746
|
-
</ScrollView>
|
|
1747
|
-
</KeyboardAvoidingView>
|
|
1748
|
-
);
|
|
1749
|
-
|
|
1750
|
-
};
|
|
1751
|
-
|
|
1752
|
-
export default App;
|
|
1753
|
-
|
|
1754
|
-
const styles = StyleSheet.create({
|
|
1755
|
-
container: { flex: 1, backgroundColor: '#F9FAFB' },
|
|
1756
|
-
scrollContent: { flexGrow: 1, padding: 20 },
|
|
1757
|
-
title: {
|
|
1758
|
-
fontSize: 24,
|
|
1759
|
-
fontWeight: 'bold',
|
|
1760
|
-
marginBottom: 16,
|
|
1761
|
-
marginTop: 50,
|
|
1762
|
-
textAlign: 'center',
|
|
1763
|
-
},
|
|
1764
|
-
sectionTitle: {
|
|
1765
|
-
fontSize: 20,
|
|
1766
|
-
fontWeight: 'bold',
|
|
1767
|
-
marginTop: 20,
|
|
1768
|
-
marginBottom: 10,
|
|
1769
|
-
},
|
|
1770
|
-
subsectionTitle: {
|
|
1771
|
-
fontSize: 16,
|
|
1772
|
-
fontWeight: '600',
|
|
1773
|
-
marginTop: 15,
|
|
1774
|
-
marginBottom: 8,
|
|
1775
|
-
color: '#374151',
|
|
1776
|
-
},
|
|
1777
|
-
input: {
|
|
1778
|
-
height: 40,
|
|
1779
|
-
borderColor: '#ccc',
|
|
1780
|
-
borderWidth: 1,
|
|
1781
|
-
borderRadius: 5,
|
|
1782
|
-
paddingHorizontal: 10,
|
|
1783
|
-
marginBottom: 10,
|
|
1784
|
-
backgroundColor: '#FFFFFF',
|
|
1785
|
-
color: '#000000',
|
|
1786
|
-
},
|
|
1787
|
-
dateInput: {
|
|
1788
|
-
backgroundColor: '#fff',
|
|
1789
|
-
shadowColor: '#000',
|
|
1790
|
-
shadowOffset: {
|
|
1791
|
-
width: 0,
|
|
1792
|
-
height: 1,
|
|
1793
|
-
},
|
|
1794
|
-
shadowOpacity: 0.1,
|
|
1795
|
-
shadowRadius: 2,
|
|
1796
|
-
elevation: 2,
|
|
1797
|
-
},
|
|
1798
|
-
pickerContainer: {
|
|
1799
|
-
marginBottom: 20,
|
|
1800
|
-
},
|
|
1801
|
-
toggleContainer: {
|
|
1802
|
-
flexDirection: 'row',
|
|
1803
|
-
justifyContent: 'space-between',
|
|
1804
|
-
alignItems: 'center',
|
|
1805
|
-
marginBottom: 10,
|
|
1806
|
-
},
|
|
1807
|
-
label: {
|
|
1808
|
-
fontSize: 16,
|
|
1809
|
-
fontWeight: '500',
|
|
1810
|
-
marginBottom: 5,
|
|
1811
|
-
},
|
|
1812
|
-
buttonGroup: {
|
|
1813
|
-
flexDirection: 'row',
|
|
1814
|
-
justifyContent: 'space-between',
|
|
1815
|
-
marginBottom: 20,
|
|
1816
|
-
marginTop: 20,
|
|
1817
|
-
gap: 10,
|
|
1818
|
-
|
|
1819
|
-
},
|
|
1820
|
-
result: {
|
|
1821
|
-
fontSize: 14,
|
|
1822
|
-
fontFamily: 'monospace',
|
|
1823
|
-
color: '#333',
|
|
1824
|
-
marginTop: 20,
|
|
1825
|
-
},
|
|
1826
|
-
environmentButton: {
|
|
1827
|
-
flex: 1,
|
|
1828
|
-
paddingVertical: 10,
|
|
1829
|
-
paddingHorizontal: 20,
|
|
1830
|
-
borderRadius: 5,
|
|
1831
|
-
marginHorizontal: 5,
|
|
1832
|
-
alignItems: 'center',
|
|
1833
|
-
justifyContent: 'center',
|
|
1834
|
-
},
|
|
1835
|
-
buttonText: {
|
|
1836
|
-
color: '#fff',
|
|
1837
|
-
fontSize: 16,
|
|
1838
|
-
fontWeight: '500',
|
|
1839
|
-
},
|
|
1840
|
-
inputContainer: {
|
|
1841
|
-
flexDirection: 'row',
|
|
1842
|
-
alignItems: 'center',
|
|
1843
|
-
borderColor: '#ccc',
|
|
1844
|
-
borderWidth: 1,
|
|
1845
|
-
borderRadius: 5,
|
|
1846
|
-
marginBottom: 10,
|
|
1847
|
-
},
|
|
1848
|
-
eyeButton: {
|
|
1849
|
-
padding: 10,
|
|
1850
|
-
},
|
|
1851
|
-
eyeIcon: {
|
|
1852
|
-
fontSize: 20,
|
|
1853
|
-
color: '#333',
|
|
1854
|
-
},
|
|
1855
|
-
// New styles for FilledButton
|
|
1856
|
-
filledButton: {
|
|
1857
|
-
flex: 1,
|
|
1858
|
-
paddingVertical: 10,
|
|
1859
|
-
paddingHorizontal: 20,
|
|
1860
|
-
borderRadius: 5,
|
|
1861
|
-
marginHorizontal: 5,
|
|
1862
|
-
alignItems: 'center',
|
|
1863
|
-
justifyContent: 'center',
|
|
1864
|
-
backgroundColor: '#2563EB', // Primary color for filled buttons
|
|
1865
|
-
},
|
|
1866
|
-
filledButtonDisabled: {
|
|
1867
|
-
backgroundColor: '#ccc',
|
|
1868
|
-
opacity: 0.7,
|
|
1869
|
-
},
|
|
1870
|
-
filledButtonText: {
|
|
1871
|
-
color: '#fff',
|
|
1872
|
-
fontSize: 16,
|
|
1873
|
-
fontWeight: '500',
|
|
1874
|
-
},
|
|
1875
|
-
filledButtonTextDisabled: {
|
|
1876
|
-
color: '#888',
|
|
1877
|
-
},
|
|
1878
|
-
debugText: {
|
|
1879
|
-
fontSize: 12,
|
|
1880
|
-
color: '#666',
|
|
1881
|
-
fontStyle: 'italic',
|
|
1882
|
-
marginBottom: 5,
|
|
1883
|
-
},
|
|
1884
|
-
// Dropdown Styles
|
|
1885
|
-
dropdownContainer: {
|
|
1886
|
-
position: 'relative',
|
|
1887
|
-
marginBottom: 20,
|
|
1888
|
-
zIndex: 9998,
|
|
1889
|
-
},
|
|
1890
|
-
dropdownButton: {
|
|
1891
|
-
height: 40,
|
|
1892
|
-
borderColor: '#ccc',
|
|
1893
|
-
borderWidth: 1,
|
|
1894
|
-
borderRadius: 5,
|
|
1895
|
-
paddingHorizontal: 10,
|
|
1896
|
-
flexDirection: 'row',
|
|
1897
|
-
justifyContent: 'space-between',
|
|
1898
|
-
alignItems: 'center',
|
|
1899
|
-
backgroundColor: '#fff',
|
|
1900
|
-
},
|
|
1901
|
-
dropdownButtonText: {
|
|
1902
|
-
fontSize: 16,
|
|
1903
|
-
color: '#333',
|
|
1904
|
-
},
|
|
1905
|
-
dropdownArrow: {
|
|
1906
|
-
fontSize: 12,
|
|
1907
|
-
color: '#666',
|
|
1908
|
-
},
|
|
1909
|
-
dropdownOptions: {
|
|
1910
|
-
position: 'absolute',
|
|
1911
|
-
top: 45,
|
|
1912
|
-
left: 0,
|
|
1913
|
-
right: 0,
|
|
1914
|
-
backgroundColor: '#fff',
|
|
1915
|
-
borderColor: '#ccc',
|
|
1916
|
-
borderWidth: 1,
|
|
1917
|
-
borderRadius: 5,
|
|
1918
|
-
zIndex: 9999,
|
|
1919
|
-
maxHeight: 200,
|
|
1920
|
-
elevation: 5,
|
|
1921
|
-
shadowColor: '#000',
|
|
1922
|
-
shadowOffset: {
|
|
1923
|
-
width: 0,
|
|
1924
|
-
height: 2,
|
|
1925
|
-
},
|
|
1926
|
-
shadowOpacity: 0.25,
|
|
1927
|
-
shadowRadius: 3.84,
|
|
1928
|
-
},
|
|
1929
|
-
dropdownScrollView: {
|
|
1930
|
-
maxHeight: 180,
|
|
1931
|
-
},
|
|
1932
|
-
dropdownOption: {
|
|
1933
|
-
paddingVertical: 12,
|
|
1934
|
-
paddingHorizontal: 15,
|
|
1935
|
-
borderBottomWidth: 1,
|
|
1936
|
-
borderBottomColor: '#f0f0f0',
|
|
1937
|
-
backgroundColor: '#fff',
|
|
1938
|
-
},
|
|
1939
|
-
dropdownOptionText: {
|
|
1940
|
-
fontSize: 16,
|
|
1941
|
-
color: '#333',
|
|
1942
|
-
},
|
|
1943
|
-
// Color preview styles
|
|
1944
|
-
colorInputContainer: {
|
|
1945
|
-
flexDirection: 'row',
|
|
1946
|
-
alignItems: 'center',
|
|
1947
|
-
marginBottom: 10,
|
|
1948
|
-
gap: 10,
|
|
1949
|
-
},
|
|
1950
|
-
colorPreview: {
|
|
1951
|
-
width: 30,
|
|
1952
|
-
height: 30,
|
|
1953
|
-
borderRadius: 4,
|
|
1954
|
-
borderWidth: 1,
|
|
1955
|
-
borderColor: '#ccc',
|
|
1956
|
-
},
|
|
1957
|
-
phoneRow: {
|
|
1958
|
-
flexDirection: 'row',
|
|
1959
|
-
alignItems: 'center',
|
|
1960
|
-
marginBottom: 10,
|
|
1961
|
-
gap: 8,
|
|
1962
|
-
},
|
|
1963
|
-
countryCodeInput: {
|
|
1964
|
-
width: 70,
|
|
1965
|
-
height: 40,
|
|
1966
|
-
borderColor: '#ccc',
|
|
1967
|
-
borderWidth: 1,
|
|
1968
|
-
borderRadius: 5,
|
|
1969
|
-
paddingHorizontal: 10,
|
|
1970
|
-
backgroundColor: '#FFFFFF',
|
|
1971
|
-
color: '#000000',
|
|
1972
|
-
textAlign: 'center',
|
|
1973
|
-
alignSelf: 'stretch',
|
|
1974
|
-
marginBottom: 0,
|
|
1975
|
-
},
|
|
1976
|
-
});
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
```
|
|
325
|
+
## Notes
|
|
1982
326
|
|
|
1983
|
-
You can send `null`
|
|
327
|
+
- **Billing Info**: You can send `null` for billing info if it is not available.
|
|
328
|
+
- **Environment Configuration**: The SDK supports `sandbox` and `staging` environments. Ensure you configure the correct API keys for each environment.
|
|
329
|
+
- **Payment Methods**: The SDK supports `card` and `ach` payment methods, with options to toggle them in the UI.
|
|
330
|
+
- **Recurring Payments**: Ensure at least one interval (`daily`, `weekly`, `monthly`) is selected when enabling recurring payments.
|
|
331
|
+
- **Theming**: Customize the appearance using `themeConfiguration` (iOS) or `androidConfig.appearanceSettings` (Android) to match your app's branding.
|
|
1984
332
|
|
|
333
|
+
## Troubleshooting
|
|
1985
334
|
|
|
1986
|
-
|
|
335
|
+
- **iOS Bridge Initialization**: If you see "Failed to retrieve EasyMerchantSdkPlugin instance" in the console, ensure the `easymerchantsdk` pod is correctly installed and linked.
|
|
336
|
+
- **Android Payment Issues**: Verify that `paymentMethod` is correctly formatted (`['card', 'ach']`) and that API keys are valid.
|
|
337
|
+
- **Pod Installation**: If `pod install` fails, ensure Ruby 3.2.8 is installed and run `pod install --repo-update`.
|