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