@jimrising/easymerchantsdk-react-native 1.3.9 → 1.4.2
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/.idea/caches/deviceStreaming.xml +77 -0
- package/README.md +140 -81
- package/android/.gradle/8.10/checksums/checksums.lock +0 -0
- package/android/.gradle/8.10/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.10/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/8.10/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.9/checksums/checksums.lock +0 -0
- package/android/.gradle/8.9/checksums/md5-checksums.bin +0 -0
- package/android/.gradle/8.9/checksums/sha1-checksums.bin +0 -0
- package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
- package/android/.gradle/buildOutputCleanup/cache.properties +1 -1
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/results.bin +1 -0
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/BuildConfig.dex +0 -0
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$1.dex +0 -0
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule$2.dex +0 -0
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkModule.dex +0 -0
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/bundleLibRuntimeToDirDebug_dex/com/reactlibrary/RNEasymerchantsdkPackage.dex +0 -0
- package/android/build/.transforms/20e1216b87bd06eaab3c9e5c68d4267a/transformed/bundleLibRuntimeToDirDebug/desugar_graph.bin +0 -0
- package/android/build/.transforms/e9a664a11ce12edf79cd87b1e07aa243/results.bin +1 -0
- package/android/build/.transforms/e9a664a11ce12edf79cd87b1e07aa243/transformed/classes/classes_dex/classes.dex +0 -0
- package/android/build/generated/source/buildConfig/debug/com/reactlibrary/BuildConfig.java +10 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +7 -0
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +18 -0
- package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +6 -0
- package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +1 -0
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
- package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +1 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +2 -0
- package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +2 -0
- package/android/build/intermediates/incremental/packageDebugAssets/merger.xml +2 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/BuildConfig.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/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
- package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +2 -0
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +7 -0
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +7 -0
- package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +1 -0
- package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +1 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/BuildConfig.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/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +1 -0
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +17 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$1.class.uniqueId2 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule$2.class.uniqueId0 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkModule.class.uniqueId3 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir/RNEasymerchantsdkPackage.class.uniqueId1 +0 -0
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/android/build.gradle +4 -1
- package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkModule.java +158 -36
- package/android/src/main/java/com/reactlibrary/RNEasymerchantsdkPackage.java +45 -13
- package/ios/Classes/EasyMerchantSdk.m +106 -55
- package/ios/Classes/EasyMerchantSdk.swift +199 -77
- package/ios/Classes/EasyPayViewController.swift +1 -1
- package/ios/CustomComponents/DatePickerHandler.swift +15 -4
- package/ios/EnvironmentConfig.swift +32 -30
- package/ios/Models/Request.swift +176 -14
- package/ios/Models/Result.swift +12 -5
- package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +855 -366
- package/ios/Pods/ViewControllers/BaseVC.swift +51 -36
- package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +1985 -178
- package/ios/Pods/ViewControllers/CountryListVC.swift +20 -1
- package/ios/Pods/ViewControllers/CustomOverlay.swift +199 -0
- package/ios/Pods/ViewControllers/EmailVerificationVC.swift +74 -5
- package/ios/Pods/ViewControllers/GrailPayVC.swift +131 -107
- package/ios/Pods/ViewControllers/OTPVerificationVC.swift +296 -106
- package/ios/Pods/ViewControllers/PaymentDoneVC.swift +35 -26
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +1276 -545
- package/ios/Pods/ViewControllers/ThreeDSecurePaymentDoneVC.swift +607 -24
- package/ios/easymerchantsdk.podspec +1 -1
- package/ios/easymerchantsdk.storyboard +1388 -1165
- package/package.json +1 -1
|
@@ -1,11 +1,7 @@
|
|
|
1
|
-
//
|
|
2
|
-
// EasyMerchantSdkPlugin.swift
|
|
3
|
-
// EasyMerchantSdk
|
|
4
|
-
//
|
|
5
|
-
|
|
6
1
|
import Foundation
|
|
7
2
|
import UIKit
|
|
8
3
|
import React
|
|
4
|
+
//import EasyPay // Import the EasyPay module
|
|
9
5
|
|
|
10
6
|
@objc(EasyMerchantSdkPlugin)
|
|
11
7
|
public class EasyMerchantSdkPlugin: NSObject, RCTBridgeModule {
|
|
@@ -14,6 +10,7 @@ public class EasyMerchantSdkPlugin: NSObject, RCTBridgeModule {
|
|
|
14
10
|
public static func moduleName() -> String! {
|
|
15
11
|
return "EasyMerchantSdk"
|
|
16
12
|
}
|
|
13
|
+
|
|
17
14
|
public static func requiresMainQueueSetup() -> Bool {
|
|
18
15
|
return true
|
|
19
16
|
}
|
|
@@ -23,6 +20,8 @@ public class EasyMerchantSdkPlugin: NSObject, RCTBridgeModule {
|
|
|
23
20
|
// MARK: - Stored Promise Callbacks
|
|
24
21
|
private var billingResolver: RCTPromiseResolveBlock?
|
|
25
22
|
private var billingRejecter: RCTPromiseRejectBlock?
|
|
23
|
+
private var paymentReferenceResolver: RCTPromiseResolveBlock?
|
|
24
|
+
private var paymentReferenceRejecter: RCTPromiseRejectBlock?
|
|
26
25
|
|
|
27
26
|
// MARK: - View Controller Reference
|
|
28
27
|
private let viewControllerQueue = DispatchQueue(label: "com.easymerchantsdk.viewController")
|
|
@@ -46,12 +45,23 @@ public class EasyMerchantSdkPlugin: NSObject, RCTBridgeModule {
|
|
|
46
45
|
}
|
|
47
46
|
}
|
|
48
47
|
|
|
48
|
+
// MARK: - configureEnvironment(...) Exposed to RN
|
|
49
|
+
@objc public func configureEnvironment(_ env: String, apiKey: String, apiSecret: String) {
|
|
50
|
+
switch env.lowercased() {
|
|
51
|
+
case "production": EnvironmentConfig.setEnvironment(.production)
|
|
52
|
+
case "sandbox": EnvironmentConfig.setEnvironment(.sandbox)
|
|
53
|
+
default: EnvironmentConfig.setEnvironment(.staging)
|
|
54
|
+
}
|
|
55
|
+
EnvironmentConfig.configure(apiKey: apiKey, apiSecret: apiSecret)
|
|
56
|
+
}
|
|
57
|
+
|
|
49
58
|
// MARK: - billing(...) Exposed to RN
|
|
50
59
|
@objc public func billing(
|
|
51
60
|
_ amount: String,
|
|
52
|
-
|
|
61
|
+
currency: String?,
|
|
62
|
+
billingInfo: [String: Any]?,
|
|
53
63
|
paymentMethods: [String],
|
|
54
|
-
themeConfiguration: [String: Any]
|
|
64
|
+
themeConfiguration: [String: Any]?,
|
|
55
65
|
tokenOnly: Bool,
|
|
56
66
|
saveCard: Bool,
|
|
57
67
|
saveAccount: Bool,
|
|
@@ -62,22 +72,66 @@ public class EasyMerchantSdkPlugin: NSObject, RCTBridgeModule {
|
|
|
62
72
|
recurringIntervals: [String]?,
|
|
63
73
|
recurringStartDateType: String?,
|
|
64
74
|
recurringStartDate: String?,
|
|
75
|
+
secureAuthentication: Bool,
|
|
76
|
+
showReceipt: Bool,
|
|
77
|
+
showTotal: Bool,
|
|
78
|
+
showSubmitButton: Bool,
|
|
65
79
|
enable3DS: Bool,
|
|
66
80
|
resolver: @escaping RCTPromiseResolveBlock,
|
|
67
81
|
rejecter: @escaping RCTPromiseRejectBlock
|
|
68
82
|
) {
|
|
69
83
|
// 1) Validate amount
|
|
70
|
-
guard let amountValue = Double(amount), amountValue
|
|
71
|
-
rejecter("INVALID_AMOUNT", "Amount must be
|
|
84
|
+
guard let amountValue = Double(amount), amountValue >= 0.50 else {
|
|
85
|
+
rejecter("INVALID_AMOUNT", "Amount must be at least $0.50", nil)
|
|
72
86
|
return
|
|
73
87
|
}
|
|
74
88
|
|
|
75
|
-
// 2)
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
89
|
+
// 2) Process billing info into FieldSection
|
|
90
|
+
var billingInfoData: Data? = nil
|
|
91
|
+
if let billingDict = billingInfo {
|
|
92
|
+
var billingFields: [FieldItem] = []
|
|
93
|
+
var additionalFields: [FieldItem] = []
|
|
94
|
+
var billingVisibility = true
|
|
95
|
+
var additionalVisibility = true
|
|
96
|
+
|
|
97
|
+
// Parse billing fields
|
|
98
|
+
if let billing = billingDict["billing"] as? [String: Any] {
|
|
99
|
+
for (key, value) in billing {
|
|
100
|
+
guard let fieldValue = value as? String else { continue }
|
|
101
|
+
let required = (billingDict["billingRequired"] as? [String: Bool])?[key] ?? false
|
|
102
|
+
if let billingField = BillingFieldName(rawValue: key) {
|
|
103
|
+
billingFields.append(FieldItem(name: billingField, required: required, value: fieldValue))
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Parse additional fields
|
|
109
|
+
if let additional = billingDict["additional"] as? [String: Any] {
|
|
110
|
+
for (key, value) in additional {
|
|
111
|
+
guard let fieldValue = value as? String else { continue }
|
|
112
|
+
let required = (billingDict["additionalRequired"] as? [String: Bool])?[key] ?? false
|
|
113
|
+
if let additionalField = AdditionalFieldName(rawValue: key) {
|
|
114
|
+
additionalFields.append(FieldItem(name: additionalField, required: required, value: fieldValue))
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Parse visibility
|
|
120
|
+
if let visibility = billingDict["visibility"] as? [String: Bool] {
|
|
121
|
+
billingVisibility = visibility["billing"] ?? true
|
|
122
|
+
additionalVisibility = visibility["additional"] ?? true
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let fields = FieldSection(
|
|
126
|
+
visibility: FieldsVisibility(billing: billingVisibility, additional: additionalVisibility),
|
|
127
|
+
billing: billingFields,
|
|
128
|
+
additional: additionalFields
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
do {
|
|
132
|
+
billingInfoData = try JSONEncoder().encode(fields)
|
|
133
|
+
} catch {
|
|
134
|
+
rejecter("INVALID_BILLING_INFO", "Failed to encode billing info: \(error.localizedDescription)", nil)
|
|
81
135
|
return
|
|
82
136
|
}
|
|
83
137
|
}
|
|
@@ -88,6 +142,7 @@ public class EasyMerchantSdkPlugin: NSObject, RCTBridgeModule {
|
|
|
88
142
|
case "card": return .Card
|
|
89
143
|
case "bank": return .Bank
|
|
90
144
|
case "crypto": return .Crypto
|
|
145
|
+
case "wallet": return .Wallet
|
|
91
146
|
default: return nil
|
|
92
147
|
}
|
|
93
148
|
}
|
|
@@ -96,37 +151,39 @@ public class EasyMerchantSdkPlugin: NSObject, RCTBridgeModule {
|
|
|
96
151
|
var grailParams: GrailPayRequest? = nil
|
|
97
152
|
if authenticatedACH, let params = grailPayParams {
|
|
98
153
|
grailParams = GrailPayRequest(
|
|
99
|
-
accessToken:
|
|
100
|
-
vendorId:
|
|
101
|
-
role:
|
|
102
|
-
timeout:
|
|
103
|
-
isSandbox:
|
|
104
|
-
brandingName:
|
|
105
|
-
finderSubtitle:
|
|
106
|
-
searchPlaceholder:
|
|
154
|
+
accessToken: params["accessToken"] as? String ?? "251|uTijpDGfrS88UR2V1cZNMQ8S4hUJA0sVzsnsoUZF",
|
|
155
|
+
vendorId: params["vendorId"] as? String ?? "251",
|
|
156
|
+
role: params["role"] as? String ?? "business",
|
|
157
|
+
timeout: params["timeout"] as? Int ?? 10,
|
|
158
|
+
isSandbox: params["isSandbox"] as? Bool ?? true,
|
|
159
|
+
brandingName: params["brandingName"] as? String ?? "Lyfecycle Payments",
|
|
160
|
+
finderSubtitle: params["finderSubtitle"] as? String ?? "Search for your bank",
|
|
161
|
+
searchPlaceholder: params["searchPlaceholder"] as? String ?? "Enter bank name"
|
|
107
162
|
)
|
|
108
163
|
}
|
|
109
164
|
|
|
110
165
|
// 5) Build theme config
|
|
111
166
|
let themeConfig = ThemeConfiguration(
|
|
112
|
-
bodyBackgroundColor:
|
|
113
|
-
containerBackgroundColor:
|
|
114
|
-
primaryFontColor:
|
|
115
|
-
secondaryFontColor:
|
|
116
|
-
primaryButtonBackgroundColor:
|
|
117
|
-
primaryButtonHoverColor:
|
|
118
|
-
primaryButtonFontColor:
|
|
119
|
-
secondaryButtonBackgroundColor:themeConfiguration["secondaryButtonBackgroundColor"]as? String ?? "#
|
|
120
|
-
secondaryButtonHoverColor:
|
|
121
|
-
secondaryButtonFontColor:
|
|
122
|
-
borderRadius:
|
|
123
|
-
fontSize:
|
|
167
|
+
bodyBackgroundColor: themeConfiguration?["bodyBackgroundColor"] as? String ?? "#121212",
|
|
168
|
+
containerBackgroundColor: themeConfiguration?["containerBackgroundColor"] as? String ?? "#1E1E1E",
|
|
169
|
+
primaryFontColor: themeConfiguration?["primaryFontColor"] as? String ?? "#FFFFFF",
|
|
170
|
+
secondaryFontColor: themeConfiguration?["secondaryFontColor"] as? String ?? "#B0B0B0",
|
|
171
|
+
primaryButtonBackgroundColor: themeConfiguration?["primaryButtonBackgroundColor"] as? String ?? "#2563EB",
|
|
172
|
+
primaryButtonHoverColor: themeConfiguration?["primaryButtonHoverColor"] as? String ?? "#1D4ED8",
|
|
173
|
+
primaryButtonFontColor: themeConfiguration?["primaryButtonFontColor"] as? String ?? "#FFFFFF",
|
|
174
|
+
secondaryButtonBackgroundColor: themeConfiguration?["secondaryButtonBackgroundColor"] as? String ?? "#374151",
|
|
175
|
+
secondaryButtonHoverColor: themeConfiguration?["secondaryButtonHoverColor"] as? String ?? "#4B5563",
|
|
176
|
+
secondaryButtonFontColor: themeConfiguration?["secondaryButtonFontColor"] as? String ?? "#E5E7EB",
|
|
177
|
+
borderRadius: themeConfiguration?["borderRadius"] as? String ?? "8",
|
|
178
|
+
fontSize: themeConfiguration?["fontSize"] as? String ?? "14",
|
|
179
|
+
fontWeight: themeConfiguration?["fontWeight"] as? Int ?? 500,
|
|
180
|
+
fontFamily: themeConfiguration?["fontFamily"] as? String ?? "\"Inter\", sans-serif"
|
|
124
181
|
)
|
|
125
182
|
|
|
126
|
-
// 6) Map recurring intervals
|
|
183
|
+
// 6) Map recurring intervals
|
|
127
184
|
let intervals: [RecurringIntervals] = (recurringIntervals ?? []).compactMap { raw in
|
|
128
185
|
let cleaned = raw.trimmingCharacters(in: .whitespacesAndNewlines).lowercased()
|
|
129
|
-
let noDot
|
|
186
|
+
let noDot = cleaned.hasPrefix(".") ? String(cleaned.dropFirst()) : cleaned
|
|
130
187
|
return RecurringIntervals(rawValue: noDot)
|
|
131
188
|
}
|
|
132
189
|
|
|
@@ -136,61 +193,114 @@ public class EasyMerchantSdkPlugin: NSObject, RCTBridgeModule {
|
|
|
136
193
|
}
|
|
137
194
|
|
|
138
195
|
// 7) Map start date type
|
|
139
|
-
let startType: RecurringStartDateType = {
|
|
196
|
+
let startType: RecurringStartDateType? = {
|
|
140
197
|
switch recurringStartDateType?.lowercased() {
|
|
141
198
|
case "custom": return .custom
|
|
142
199
|
case "fixed": return .fixed
|
|
143
|
-
default: return
|
|
200
|
+
default: return nil
|
|
144
201
|
}
|
|
145
202
|
}()
|
|
146
203
|
|
|
147
204
|
// 8) Build the request object
|
|
148
205
|
let request = Request(
|
|
149
|
-
amount:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
206
|
+
amount: amountValue,
|
|
207
|
+
currency: currency ?? "usd",
|
|
208
|
+
billingInfoData: billingInfoData,
|
|
209
|
+
paymentMethods: methods.isEmpty ? [.Card, .Bank] : methods,
|
|
210
|
+
themeConfiguration: themeConfig,
|
|
211
|
+
tokenOnly: tokenOnly,
|
|
212
|
+
saveCard: saveCard,
|
|
213
|
+
saveAccount: saveAccount,
|
|
214
|
+
submitButtonText: submitButtonText ?? "Submit",
|
|
215
|
+
authenticatedACH: authenticatedACH,
|
|
216
|
+
grailPayParams: grailParams,
|
|
217
|
+
is_recurring: isRecurring,
|
|
218
|
+
recurringIntervals: intervals,
|
|
161
219
|
recurringStartDateType: startType,
|
|
162
|
-
recurringStartDate:
|
|
163
|
-
|
|
220
|
+
recurringStartDate: recurringStartDate,
|
|
221
|
+
secureAuthentication: secureAuthentication,
|
|
222
|
+
showReceipt: showReceipt,
|
|
223
|
+
showTotal: showTotal,
|
|
224
|
+
showSubmitButton: showSubmitButton,
|
|
225
|
+
referenceID: enable3DS,
|
|
226
|
+
referenceToken: nil
|
|
164
227
|
)
|
|
165
228
|
|
|
166
229
|
// Store resolvers
|
|
167
230
|
self.billingResolver = resolver
|
|
168
|
-
self.billingRejecter
|
|
231
|
+
self.billingRejecter = rejecter
|
|
169
232
|
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
233
|
+
// Handle tokenOnly or present EasyPayViewController
|
|
234
|
+
if tokenOnly {
|
|
235
|
+
NotificationCenter.default.addObserver(
|
|
236
|
+
forName: NSNotification.Name("ClientTokenReceived"),
|
|
237
|
+
object: nil,
|
|
238
|
+
queue: .main
|
|
239
|
+
) { [weak self] notification in
|
|
240
|
+
guard let self = self else { return }
|
|
241
|
+
if let clientToken = notification.object as? String {
|
|
242
|
+
self.billingResolver?(["status": "success", "clientToken": clientToken])
|
|
243
|
+
} else {
|
|
244
|
+
self.billingRejecter?("TOKEN_ERROR", "Failed to receive client token.", nil)
|
|
245
|
+
}
|
|
179
246
|
self.clearResolvers()
|
|
180
247
|
}
|
|
248
|
+
} else {
|
|
249
|
+
DispatchQueue.main.async {
|
|
250
|
+
let vc = EasyPayViewController(request: request, delegate: self)
|
|
251
|
+
if let host = self.viewController {
|
|
252
|
+
host.present(vc, animated: true, completion: nil)
|
|
253
|
+
} else if let root = UIApplication.shared.windows.first(where: { $0.isKeyWindow })?.rootViewController {
|
|
254
|
+
root.present(vc, animated: true, completion: nil)
|
|
255
|
+
} else {
|
|
256
|
+
rejecter("NO_VIEW_CONTROLLER", "Cannot find a view controller to present.", nil)
|
|
257
|
+
self.clearResolvers()
|
|
258
|
+
}
|
|
259
|
+
}
|
|
181
260
|
}
|
|
182
261
|
}
|
|
183
262
|
|
|
184
|
-
// MARK: -
|
|
185
|
-
@objc public func
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
263
|
+
// MARK: - paymentReference(...) Exposed to RN
|
|
264
|
+
@objc public func paymentReference(
|
|
265
|
+
_ referenceToken: String,
|
|
266
|
+
resolver: @escaping RCTPromiseResolveBlock,
|
|
267
|
+
rejecter: @escaping RCTPromiseRejectBlock
|
|
268
|
+
) {
|
|
269
|
+
// Validate reference token
|
|
270
|
+
guard !referenceToken.isEmpty else {
|
|
271
|
+
rejecter("INVALID_REFERENCE_TOKEN", "Reference token cannot be empty.", nil)
|
|
272
|
+
return
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Store resolvers
|
|
276
|
+
self.paymentReferenceResolver = resolver
|
|
277
|
+
self.paymentReferenceRejecter = rejecter
|
|
278
|
+
|
|
279
|
+
// Build the request object
|
|
280
|
+
let request = Request(
|
|
281
|
+
referenceID: true,
|
|
282
|
+
referenceToken: referenceToken
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
// Set up notification observer for ReferenceIDResponse
|
|
286
|
+
DispatchQueue.main.async {
|
|
287
|
+
NotificationCenter.default.addObserver(
|
|
288
|
+
forName: NSNotification.Name("ReferenceIDResponse"),
|
|
289
|
+
object: nil,
|
|
290
|
+
queue: .main
|
|
291
|
+
) { [weak self] notification in
|
|
292
|
+
guard let self = self else { return }
|
|
293
|
+
if let data = notification.object as? [String: Any] {
|
|
294
|
+
self.paymentReferenceResolver?(data)
|
|
295
|
+
} else {
|
|
296
|
+
self.paymentReferenceRejecter?("INVALID_RESPONSE", "Invalid response data.", nil)
|
|
297
|
+
}
|
|
298
|
+
self.clearReferenceResolvers()
|
|
299
|
+
}
|
|
190
300
|
}
|
|
191
|
-
EnvironmentConfig.configure(apiKey: apiKey, apiSecret: apiSecret)
|
|
192
301
|
}
|
|
193
302
|
|
|
303
|
+
// MARK: - getPlatformVersion(...) Exposed to RN
|
|
194
304
|
@objc public func getPlatformVersion(
|
|
195
305
|
_ resolver: RCTPromiseResolveBlock,
|
|
196
306
|
rejecter: RCTPromiseRejectBlock
|
|
@@ -198,9 +308,16 @@ public class EasyMerchantSdkPlugin: NSObject, RCTBridgeModule {
|
|
|
198
308
|
resolver("iOS \(UIDevice.current.systemVersion)")
|
|
199
309
|
}
|
|
200
310
|
|
|
311
|
+
// MARK: - Private Helpers
|
|
201
312
|
private func clearResolvers() {
|
|
202
313
|
billingResolver = nil
|
|
203
|
-
billingRejecter
|
|
314
|
+
billingRejecter = nil
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
private func clearReferenceResolvers() {
|
|
318
|
+
paymentReferenceResolver = nil
|
|
319
|
+
paymentReferenceRejecter = nil
|
|
320
|
+
NotificationCenter.default.removeObserver(self, name: NSNotification.Name("ReferenceIDResponse"), object: nil)
|
|
204
321
|
}
|
|
205
322
|
}
|
|
206
323
|
|
|
@@ -213,13 +330,19 @@ extension EasyMerchantSdkPlugin: EasyPayViewControllerDelegate {
|
|
|
213
330
|
self.billingResolver?(["status": "cancelled", "message": "User cancelled"])
|
|
214
331
|
|
|
215
332
|
case .success:
|
|
216
|
-
// Build a single payload for RN
|
|
217
333
|
var payload: [String: Any] = ["status": "success"]
|
|
218
|
-
if let cd = result.chargeData
|
|
219
|
-
if let bi = result.billingInfo
|
|
220
|
-
if let ai = result.additionalInfo{ payload["additionalInfo"] = ai
|
|
334
|
+
if let cd = result.chargeData { payload["chargeData"] = cd }
|
|
335
|
+
if let bi = result.billingInfo { payload["billingInfo"] = bi }
|
|
336
|
+
if let ai = result.additionalInfo { payload["additionalInfo"] = ai }
|
|
337
|
+
|
|
338
|
+
// Extract referenceToken for 3DS
|
|
339
|
+
if let additional = result.additionalInfo,
|
|
340
|
+
let threeDSecureStatus = additional["threeDSecureStatus"] as? [String: Any],
|
|
341
|
+
let data = threeDSecureStatus["data"] as? [String: Any],
|
|
342
|
+
let token = data["ref_token"] as? String {
|
|
343
|
+
payload["referenceToken"] = token
|
|
344
|
+
}
|
|
221
345
|
|
|
222
|
-
// Resolve promise
|
|
223
346
|
self.billingResolver?(payload)
|
|
224
347
|
|
|
225
348
|
case .error:
|
|
@@ -227,7 +350,6 @@ extension EasyMerchantSdkPlugin: EasyPayViewControllerDelegate {
|
|
|
227
350
|
self.billingRejecter?("PAYMENT_ERROR", errMsg, nil)
|
|
228
351
|
}
|
|
229
352
|
|
|
230
|
-
// Cleanup & dismiss
|
|
231
353
|
self.clearResolvers()
|
|
232
354
|
controller.dismiss(animated: true, completion: nil)
|
|
233
355
|
}
|
|
@@ -63,7 +63,7 @@ public final class EasyPayViewController: UINavigationController {
|
|
|
63
63
|
let vc = UIStoryboard(name: "easymerchantsdk", bundle: Bundle.easyPayBundle).instantiateViewController(withIdentifier: "PaymentInfoVC") as! PaymentInfoVC
|
|
64
64
|
vc.modalPresentationStyle = .overFullScreen
|
|
65
65
|
vc.configureWith(request: request, delegate: easyPayDelegate)
|
|
66
|
-
vc.amount = Int(request.amount) // Set the amount here
|
|
66
|
+
vc.amount = Int(request.amount ?? 0.0) // Set the amount here
|
|
67
67
|
self.navigationBar.isHidden = true
|
|
68
68
|
self.setViewControllers([vc], animated: false)
|
|
69
69
|
}
|
|
@@ -19,12 +19,14 @@ class DatePickerHandler: NSObject {
|
|
|
19
19
|
|
|
20
20
|
self.targetTextField = textField
|
|
21
21
|
configureDatePicker()
|
|
22
|
+
setupInputView(for: textField)
|
|
22
23
|
|
|
23
24
|
if let date = initialDate {
|
|
24
25
|
datePicker.date = date
|
|
25
26
|
}
|
|
26
27
|
|
|
27
|
-
|
|
28
|
+
// Add observer for when the user taps the textField
|
|
29
|
+
textField.addTarget(self, action: #selector(textFieldEditingDidBegin), for: .editingDidBegin)
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
private func configureDatePicker() {
|
|
@@ -32,7 +34,7 @@ class DatePickerHandler: NSObject {
|
|
|
32
34
|
datePicker.preferredDatePickerStyle = .inline
|
|
33
35
|
}
|
|
34
36
|
datePicker.datePickerMode = .date
|
|
35
|
-
datePicker.minimumDate = Date()
|
|
37
|
+
datePicker.minimumDate = Calendar.current.startOfDay(for: Date())
|
|
36
38
|
datePicker.addTarget(self, action: #selector(dateChanged(_:)), for: .valueChanged)
|
|
37
39
|
}
|
|
38
40
|
|
|
@@ -49,6 +51,17 @@ class DatePickerHandler: NSObject {
|
|
|
49
51
|
textField.inputAccessoryView = toolbar
|
|
50
52
|
}
|
|
51
53
|
|
|
54
|
+
@objc private func textFieldEditingDidBegin() {
|
|
55
|
+
// When the textField is tapped, if it has a date, set it back on the date picker
|
|
56
|
+
if let text = targetTextField?.text, !text.isEmpty {
|
|
57
|
+
let formatter = DateFormatter()
|
|
58
|
+
formatter.dateFormat = "dd/MM/yyyy"
|
|
59
|
+
if let selectedDate = formatter.date(from: text) {
|
|
60
|
+
datePicker.setDate(selectedDate, animated: true)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
52
65
|
@objc private func dateChanged(_ sender: UIDatePicker) {
|
|
53
66
|
let formatter = DateFormatter()
|
|
54
67
|
formatter.dateFormat = "dd/MM/yyyy"
|
|
@@ -66,6 +79,4 @@ class DatePickerHandler: NSObject {
|
|
|
66
79
|
}
|
|
67
80
|
targetTextField?.resignFirstResponder()
|
|
68
81
|
}
|
|
69
|
-
|
|
70
82
|
}
|
|
71
|
-
|
|
@@ -39,34 +39,36 @@ public class EnvironmentConfig {
|
|
|
39
39
|
self.currentEnvironment = environment
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
42
|
+
public enum Endpoints {
|
|
43
|
+
case paymentIntent
|
|
44
|
+
case hostedCheckouts
|
|
45
|
+
case emailVerification
|
|
46
|
+
case verifyOtp
|
|
47
|
+
case getCards
|
|
48
|
+
case creditCharges
|
|
49
|
+
case account
|
|
50
|
+
case achCharge
|
|
51
|
+
case charges
|
|
52
|
+
case accountConnect
|
|
53
|
+
case threeDSecure
|
|
54
|
+
case threeDSecureStatus(String)
|
|
55
|
+
|
|
56
|
+
func path() -> String {
|
|
57
|
+
switch self {
|
|
58
|
+
case .paymentIntent: return "/api/v1/paymentintent"
|
|
59
|
+
case .hostedCheckouts: return "/api/v1/hostedcheckouts"
|
|
60
|
+
case .emailVerification: return "/api/v1/customer/send_otp"
|
|
61
|
+
case .verifyOtp: return "/api/v1/customer/verify_otp"
|
|
62
|
+
// case .getCards: return "/api/v1/customer/card"
|
|
63
|
+
case .getCards: return "/api/v1/card"
|
|
64
|
+
case .creditCharges: return "/api/v1/customer/charges"
|
|
65
|
+
case .account: return "/api/v1/ach/account"
|
|
66
|
+
case .achCharge: return "/api/v1/ach/charge"
|
|
67
|
+
case .charges: return "/api/v1/charges"
|
|
68
|
+
case .accountConnect: return "/api/v1/ach/account/connect"
|
|
69
|
+
case .threeDSecure: return "/api/v1/3dsecure"
|
|
70
|
+
case .threeDSecureStatus(let token): return "/api/v1/3dsecure/\(token)/status"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
72
74
|
}
|