react-amwal-pay 0.1.13 → 0.1.15
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 +46 -5
- package/ios/ReactAmwalPay.m +3 -5
- package/ios/ReactAmwalPay.swift +307 -34
- package/lib/module/AmwalPaySDK.js +16 -2
- package/lib/module/AmwalPaySDK.js.map +1 -1
- package/lib/module/NativeReactAmwalPay.js +6 -1
- package/lib/module/NativeReactAmwalPay.js.map +1 -1
- package/lib/typescript/src/AmwalPaySDK.d.ts.map +1 -1
- package/lib/typescript/src/NativeReactAmwalPay.d.ts +41 -0
- package/lib/typescript/src/NativeReactAmwalPay.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/AmwalPaySDK.ts +18 -2
- package/src/NativeReactAmwalPay.ts +43 -3
package/README.md
CHANGED
|
@@ -170,7 +170,10 @@ const config: AmwalPayConfig = {
|
|
|
170
170
|
merchantReference: 'optional-merchant-reference', // optional: merchant reference for transaction tracking
|
|
171
171
|
additionValues: { // optional: custom key-value pairs for SDK configuration
|
|
172
172
|
merchantIdentifier: 'merchant.applepay.amwalpay', // for Apple Pay configuration
|
|
173
|
-
|
|
173
|
+
useBottomSheetDesign: 'true', // use bottom sheet design (v2)
|
|
174
|
+
primaryColor: '#FF5733', // custom primary color
|
|
175
|
+
secondaryColor: '#33FF57', // custom secondary color
|
|
176
|
+
ignoreReceipt: 'false' // show receipt after transaction
|
|
174
177
|
},
|
|
175
178
|
onCustomerId(customerId) {
|
|
176
179
|
console.log('Customer ID:', customerId);
|
|
@@ -236,7 +239,32 @@ The SDK supports `additionValues` parameter for passing custom key-value pairs t
|
|
|
236
239
|
The SDK automatically provides default values:
|
|
237
240
|
- `merchantIdentifier`: "merchant.applepay.amwalpay" (used for Apple Pay configuration)
|
|
238
241
|
|
|
239
|
-
###
|
|
242
|
+
### Available Configuration Options
|
|
243
|
+
|
|
244
|
+
You can customize the SDK behavior using the following `additionValues` keys:
|
|
245
|
+
|
|
246
|
+
#### UI Customization
|
|
247
|
+
- **`useBottomSheetDesign`**: `'true'` | `'false'` (default: `'false'`)
|
|
248
|
+
- Controls the payment screen design
|
|
249
|
+
- `'true'`: Uses the newer bottom sheet design (v2)
|
|
250
|
+
- `'false'`: Uses the original full-screen design
|
|
251
|
+
|
|
252
|
+
- **`primaryColor`**: Hex color string (e.g., `'#FF5733'`)
|
|
253
|
+
- Sets the primary theme color for the SDK UI
|
|
254
|
+
|
|
255
|
+
- **`secondaryColor`**: Hex color string (e.g., `'#33FF57'`)
|
|
256
|
+
- Sets the secondary theme color for the SDK UI
|
|
257
|
+
|
|
258
|
+
#### Payment Flow
|
|
259
|
+
- **`ignoreReceipt`**: `'true'` | `'false'` (default: `'false'`)
|
|
260
|
+
- Controls whether to show the receipt screen after transaction
|
|
261
|
+
- `'true'`: Skips the receipt display
|
|
262
|
+
- `'false'`: Shows the receipt screen
|
|
263
|
+
|
|
264
|
+
- **`merchantIdentifier`**: String (default: `'merchant.applepay.amwalpay'`)
|
|
265
|
+
- Apple Pay merchant identifier for iOS
|
|
266
|
+
|
|
267
|
+
### Usage Examples
|
|
240
268
|
|
|
241
269
|
```js
|
|
242
270
|
// Using default additionValues (automatically applied)
|
|
@@ -245,18 +273,31 @@ const config = {
|
|
|
245
273
|
// additionValues will automatically include merchantIdentifier
|
|
246
274
|
};
|
|
247
275
|
|
|
248
|
-
// Using custom additionValues
|
|
276
|
+
// Using custom additionValues with UI customization
|
|
249
277
|
const customConfig = {
|
|
250
278
|
// ... other configuration
|
|
251
279
|
additionValues: {
|
|
252
|
-
|
|
253
|
-
|
|
280
|
+
useBottomSheetDesign: 'true',
|
|
281
|
+
primaryColor: '#FF5733',
|
|
282
|
+
secondaryColor: '#33FF57',
|
|
283
|
+
ignoreReceipt: 'false',
|
|
284
|
+
merchantIdentifier: 'merchant.custom.identifier'
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
// Minimal configuration with bottom sheet design
|
|
289
|
+
const minimalConfig = {
|
|
290
|
+
// ... other configuration
|
|
291
|
+
additionValues: {
|
|
292
|
+
useBottomSheetDesign: 'true'
|
|
254
293
|
}
|
|
255
294
|
};
|
|
256
295
|
```
|
|
257
296
|
|
|
258
297
|
Custom `additionValues` will be merged with defaults, with custom values taking precedence.
|
|
259
298
|
|
|
299
|
+
**Note:** All boolean values should be passed as strings (`'true'` or `'false'`).
|
|
300
|
+
|
|
260
301
|
## Configuration
|
|
261
302
|
|
|
262
303
|
The `AmwalPayConfig` interface includes the following properties:
|
package/ios/ReactAmwalPay.m
CHANGED
|
@@ -3,12 +3,10 @@
|
|
|
3
3
|
|
|
4
4
|
@interface RCT_EXTERN_MODULE(ReactAmwalPay, RCTEventEmitter)
|
|
5
5
|
|
|
6
|
-
RCT_EXTERN_METHOD(initiate:(NSDictionary *)config
|
|
7
|
-
resolver:(RCTPromiseResolveBlock)resolve
|
|
8
|
-
rejecter:(RCTPromiseRejectBlock)reject)
|
|
6
|
+
RCT_EXTERN_METHOD(initiate:(NSDictionary *)config)
|
|
9
7
|
|
|
10
|
-
RCT_EXTERN_METHOD(
|
|
8
|
+
RCT_EXTERN_METHOD(addListener:(NSString *)eventName)
|
|
11
9
|
|
|
12
|
-
RCT_EXTERN_METHOD(
|
|
10
|
+
RCT_EXTERN_METHOD(removeListeners:(double)count)
|
|
13
11
|
|
|
14
12
|
@end
|
package/ios/ReactAmwalPay.swift
CHANGED
|
@@ -1,11 +1,208 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import amwalsdk
|
|
3
3
|
import React
|
|
4
|
+
import UIKit
|
|
5
|
+
|
|
6
|
+
// MARK: - Container view controller that keeps SDK alive during 3DS presentation
|
|
7
|
+
/// This container wraps the SDK view controller as a child
|
|
8
|
+
/// When 3DS opens its WebView, it can present on top without dismissing the SDK
|
|
9
|
+
class ShareableContainerViewController: UIViewController {
|
|
10
|
+
private let sdkViewController: UIViewController
|
|
11
|
+
|
|
12
|
+
init(sdkViewController: UIViewController) {
|
|
13
|
+
self.sdkViewController = sdkViewController
|
|
14
|
+
super.init(nibName: nil, bundle: nil)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
required init?(coder: NSCoder) {
|
|
18
|
+
fatalError("init(coder:) has not been implemented")
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
override func viewDidLoad() {
|
|
22
|
+
super.viewDidLoad()
|
|
23
|
+
|
|
24
|
+
// Add SDK view controller as child - this keeps it alive during 3DS presentation
|
|
25
|
+
addChild(sdkViewController)
|
|
26
|
+
view.addSubview(sdkViewController.view)
|
|
27
|
+
sdkViewController.view.frame = view.bounds
|
|
28
|
+
sdkViewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
|
|
29
|
+
sdkViewController.didMove(toParent: self)
|
|
30
|
+
|
|
31
|
+
view.backgroundColor = .clear
|
|
32
|
+
sdkViewController.view.backgroundColor = .clear
|
|
33
|
+
|
|
34
|
+
// Enable presentation context to handle 3DS WebView presentation
|
|
35
|
+
// This is critical: allows 3DS WebView to present on top without dismissing the SDK
|
|
36
|
+
definesPresentationContext = true
|
|
37
|
+
providesPresentationContextTransitionStyle = true
|
|
38
|
+
|
|
39
|
+
// Ensure the SDK view controller also allows nested presentations
|
|
40
|
+
// This prevents it from being dismissed when 3DS presents its WebView
|
|
41
|
+
sdkViewController.definesPresentationContext = true
|
|
42
|
+
sdkViewController.providesPresentationContextTransitionStyle = true
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
override func viewDidAppear(_ animated: Bool) {
|
|
46
|
+
super.viewDidAppear(animated)
|
|
47
|
+
// Ensure container is ready for nested presentations
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private func topmostPresentedViewController() -> UIViewController {
|
|
51
|
+
var topController: UIViewController = self
|
|
52
|
+
while let presented = topController.presentedViewController {
|
|
53
|
+
topController = presented
|
|
54
|
+
}
|
|
55
|
+
return topController
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
|
|
59
|
+
// If already presenting, present from the topmost controller
|
|
60
|
+
// This allows 3DS WebView to present on top without dismissing the SDK
|
|
61
|
+
if let presented = presentedViewController {
|
|
62
|
+
let topmost = topmostPresentedViewController()
|
|
63
|
+
topmost.present(viewControllerToPresent, animated: flag, completion: completion)
|
|
64
|
+
} else {
|
|
65
|
+
super.present(viewControllerToPresent, animated: flag, completion: completion)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// MARK: - Fix UIViewController presentation for share sheets
|
|
71
|
+
public extension UIViewController {
|
|
72
|
+
static let swizzlePresentOnce: Void = {
|
|
73
|
+
let originalSelector = #selector(UIViewController.present(_:animated:completion:))
|
|
74
|
+
let swizzledSelector = #selector(UIViewController.swizzled_present(_:animated:completion:))
|
|
75
|
+
|
|
76
|
+
guard let originalMethod = class_getInstanceMethod(UIViewController.self, originalSelector),
|
|
77
|
+
let swizzledMethod = class_getInstanceMethod(UIViewController.self, swizzledSelector) else {
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
method_exchangeImplementations(originalMethod, swizzledMethod)
|
|
82
|
+
}()
|
|
83
|
+
|
|
84
|
+
@objc dynamic func swizzled_present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
|
|
85
|
+
// Check if this view controller's view is in the window hierarchy
|
|
86
|
+
if self.view.window == nil {
|
|
87
|
+
print("⚠️ Attempting to present on VC not in hierarchy, finding correct presenter...")
|
|
88
|
+
// Find the correct view controller to present from
|
|
89
|
+
if let topVC = UIViewController.getTopMostViewController() {
|
|
90
|
+
topVC.swizzled_present(viewControllerToPresent, animated: flag, completion: completion)
|
|
91
|
+
return
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Special handling for ShareableContainerViewController and its children
|
|
96
|
+
// If presenting from a child of ShareableContainerViewController, forward to container
|
|
97
|
+
if let container = findShareableContainer() {
|
|
98
|
+
if container != self {
|
|
99
|
+
// We're a child of the container, forward to container
|
|
100
|
+
container.swizzled_present(viewControllerToPresent, animated: flag, completion: completion)
|
|
101
|
+
return
|
|
102
|
+
}
|
|
103
|
+
// We ARE the container - allow nested presentations
|
|
104
|
+
// Don't auto-dismiss, just present on top
|
|
105
|
+
} else if self.presentedViewController != nil && !self.definesPresentationContext {
|
|
106
|
+
// Not a container, and already presenting - auto-dismiss
|
|
107
|
+
print("⚠️ Already presenting, dismissing first...")
|
|
108
|
+
self.dismiss(animated: false) { [weak self] in
|
|
109
|
+
self?.swizzled_present(viewControllerToPresent, animated: flag, completion: completion)
|
|
110
|
+
}
|
|
111
|
+
return
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Call original implementation
|
|
115
|
+
self.swizzled_present(viewControllerToPresent, animated: flag, completion: completion)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Helper to find ShareableContainerViewController in parent hierarchy
|
|
119
|
+
private func findShareableContainer() -> ShareableContainerViewController? {
|
|
120
|
+
var current: UIViewController? = self
|
|
121
|
+
while let parent = current?.parent {
|
|
122
|
+
if let container = parent as? ShareableContainerViewController {
|
|
123
|
+
return container
|
|
124
|
+
}
|
|
125
|
+
current = parent
|
|
126
|
+
}
|
|
127
|
+
if let container = self as? ShareableContainerViewController {
|
|
128
|
+
return container
|
|
129
|
+
}
|
|
130
|
+
return nil
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
static func getTopMostViewController() -> UIViewController? {
|
|
134
|
+
var topController: UIViewController?
|
|
135
|
+
|
|
136
|
+
if #available(iOS 13.0, *) {
|
|
137
|
+
let keyWindow = UIApplication.shared.connectedScenes
|
|
138
|
+
.compactMap { $0 as? UIWindowScene }
|
|
139
|
+
.flatMap { $0.windows }
|
|
140
|
+
.first { $0.isKeyWindow }
|
|
141
|
+
topController = keyWindow?.rootViewController
|
|
142
|
+
} else {
|
|
143
|
+
topController = UIApplication.shared.keyWindow?.rootViewController
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
while let presented = topController?.presentedViewController {
|
|
147
|
+
topController = presented
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return topController
|
|
151
|
+
}
|
|
152
|
+
}
|
|
4
153
|
|
|
5
154
|
@objc(ReactAmwalPay)
|
|
6
|
-
class ReactAmwalPay: RCTEventEmitter {
|
|
155
|
+
open class ReactAmwalPay: RCTEventEmitter {
|
|
7
156
|
private var hasListeners = false
|
|
157
|
+
private var sdkWindow: UIWindow? // Separate window for SDK to avoid modal dismissal issues
|
|
158
|
+
|
|
159
|
+
// Initialize swizzling when the class is first loaded
|
|
160
|
+
private static let initializeSwizzling: Void = {
|
|
161
|
+
_ = UIViewController.swizzlePresentOnce
|
|
162
|
+
}()
|
|
8
163
|
|
|
164
|
+
// Initialize swizzling when the module is loaded
|
|
165
|
+
public override init() {
|
|
166
|
+
super.init()
|
|
167
|
+
_ = ReactAmwalPay.initializeSwizzling
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
open override func supportedEvents() -> [String]! {
|
|
171
|
+
return ["onResponse", "onCustomerId"]
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
open override func startObserving() {
|
|
175
|
+
print("🔴 startObserving called - setting hasListeners = true")
|
|
176
|
+
hasListeners = true
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
open override func stopObserving() {
|
|
180
|
+
print("🔴 stopObserving called - setting hasListeners = false")
|
|
181
|
+
hasListeners = false
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
private func emitOnResponse(_ params: [String: Any]) {
|
|
185
|
+
print("🔴 emitOnResponse called with params: \(params)")
|
|
186
|
+
print("🔴 hasListeners: \(hasListeners)")
|
|
187
|
+
if hasListeners {
|
|
188
|
+
print("🔴 Sending onResponse event to JS")
|
|
189
|
+
sendEvent(withName: "onResponse", body: params)
|
|
190
|
+
} else {
|
|
191
|
+
print("🔴 NOT sending - no listeners!")
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private func emitOnCustomerId(_ customerId: String?) {
|
|
196
|
+
print("🔴 emitOnCustomerId called with: \(customerId ?? "nil")")
|
|
197
|
+
print("🔴 hasListeners: \(hasListeners)")
|
|
198
|
+
if hasListeners {
|
|
199
|
+
print("🔴 Sending onCustomerId event to JS")
|
|
200
|
+
sendEvent(withName: "onCustomerId", body: customerId)
|
|
201
|
+
} else {
|
|
202
|
+
print("🔴 NOT sending - no listeners!")
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
9
206
|
private func mapEnvironment(environment: String) -> Config.Environment {
|
|
10
207
|
switch environment {
|
|
11
208
|
case "PROD": return .PROD
|
|
@@ -39,8 +236,6 @@ class ReactAmwalPay: RCTEventEmitter {
|
|
|
39
236
|
}
|
|
40
237
|
}
|
|
41
238
|
|
|
42
|
-
private var onResponseCallback: RCTResponseSenderBlock?
|
|
43
|
-
private var onCustomerIdCallback: RCTResponseSenderBlock?
|
|
44
239
|
private func prepareConfig(config: [String: Any]) -> Config {
|
|
45
240
|
// Handle additionValues
|
|
46
241
|
var additionValues: [String: String] = Config.generateDefaultAdditionValues()
|
|
@@ -50,7 +245,7 @@ class ReactAmwalPay: RCTEventEmitter {
|
|
|
50
245
|
additionValues[key] = value
|
|
51
246
|
}
|
|
52
247
|
}
|
|
53
|
-
|
|
248
|
+
|
|
54
249
|
return Config(
|
|
55
250
|
environment: mapEnvironment(environment: config["environment"] as? String ?? "PROD"),
|
|
56
251
|
sessionToken: config["sessionToken"] as? String ?? "",
|
|
@@ -68,56 +263,134 @@ class ReactAmwalPay: RCTEventEmitter {
|
|
|
68
263
|
}
|
|
69
264
|
|
|
70
265
|
@objc
|
|
71
|
-
func initiate(_ config: [String: Any]
|
|
72
|
-
resolver resolve: @escaping RCTPromiseResolveBlock,
|
|
73
|
-
rejecter reject: @escaping RCTPromiseRejectBlock) {
|
|
266
|
+
open func initiate(_ config: [String: Any]) {
|
|
74
267
|
DispatchQueue.main.async {
|
|
75
268
|
do {
|
|
76
269
|
let sdkConfig = self.prepareConfig(config: config)
|
|
77
270
|
let sdk = AmwalSDK()
|
|
78
|
-
|
|
271
|
+
|
|
79
272
|
guard let rootVC = UIApplication.shared.keyWindow?.rootViewController else {
|
|
80
|
-
|
|
273
|
+
let errorData: [String: Any] = [
|
|
274
|
+
"data": [
|
|
275
|
+
"status": "ERROR",
|
|
276
|
+
"message": "No root view controller found"
|
|
277
|
+
]
|
|
278
|
+
]
|
|
279
|
+
self.emitOnResponse(errorData)
|
|
81
280
|
return
|
|
82
281
|
}
|
|
83
|
-
|
|
282
|
+
|
|
84
283
|
let sdkVC = try sdk.createViewController(
|
|
85
284
|
config: sdkConfig,
|
|
86
285
|
onResponse: { [weak self] response in
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
286
|
+
print("🟠 SDK onResponse callback fired!")
|
|
287
|
+
print("🟠 Response type: \(type(of: response))")
|
|
288
|
+
print("🟠 Response value: \(response ?? "nil")")
|
|
289
|
+
|
|
290
|
+
// Dismiss SDK window when payment completes
|
|
291
|
+
DispatchQueue.main.async {
|
|
292
|
+
self?.dismissSDKWindow()
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// The SDK returns a JSON string, we need to parse it
|
|
296
|
+
if let responseString = response as? String,
|
|
297
|
+
let data = responseString.data(using: .utf8),
|
|
298
|
+
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
|
|
299
|
+
print("🟠 Successfully parsed JSON string to dictionary")
|
|
300
|
+
self?.emitOnResponse(json)
|
|
301
|
+
} else if let responseDict = response as? [String: Any] {
|
|
302
|
+
print("🟠 Response is already a dictionary")
|
|
303
|
+
self?.emitOnResponse(responseDict)
|
|
304
|
+
} else {
|
|
305
|
+
print("🟠 Could not parse response, sending as-is")
|
|
306
|
+
let errorData: [String: Any] = [
|
|
307
|
+
"status": "error",
|
|
308
|
+
"message": "Invalid response format",
|
|
309
|
+
"rawResponse": String(describing: response)
|
|
310
|
+
]
|
|
311
|
+
self?.emitOnResponse(errorData)
|
|
312
|
+
}
|
|
313
|
+
},
|
|
93
314
|
onCustomerId: { [weak self] customerId in
|
|
94
|
-
|
|
95
|
-
|
|
315
|
+
print("🟠 SDK onCustomerId callback fired with: \(customerId ?? "nil")")
|
|
316
|
+
self?.emitOnCustomerId(customerId)
|
|
317
|
+
}
|
|
96
318
|
)
|
|
319
|
+
|
|
320
|
+
// Ensure transparency
|
|
321
|
+
sdkVC.view.backgroundColor = .clear
|
|
322
|
+
sdkVC.view.isOpaque = false
|
|
323
|
+
|
|
324
|
+
// Wrap SDK view controller in container
|
|
325
|
+
let containerVC = ShareableContainerViewController(sdkViewController: sdkVC)
|
|
326
|
+
containerVC.view.backgroundColor = .clear
|
|
327
|
+
|
|
328
|
+
print("🟠 SDK ViewController wrapped in container")
|
|
329
|
+
print("🟠 Creating separate window for SDK...")
|
|
330
|
+
|
|
331
|
+
// Create a separate window for the SDK
|
|
332
|
+
// This prevents modal presentation issues - SDK lives in its own window
|
|
333
|
+
// 3DS can present on top without affecting the SDK
|
|
334
|
+
if #available(iOS 13.0, *) {
|
|
335
|
+
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene {
|
|
336
|
+
self.sdkWindow = UIWindow(windowScene: windowScene)
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
self.sdkWindow = UIWindow(frame: UIScreen.main.bounds)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
guard let sdkWindow = self.sdkWindow else {
|
|
343
|
+
print("🟠 Failed to create SDK window, falling back to modal presentation")
|
|
344
|
+
rootVC.present(containerVC, animated: true)
|
|
345
|
+
return
|
|
346
|
+
}
|
|
97
347
|
|
|
98
|
-
|
|
99
|
-
|
|
348
|
+
sdkWindow.rootViewController = containerVC
|
|
349
|
+
sdkWindow.windowLevel = .normal + 1 // Above main window
|
|
350
|
+
sdkWindow.backgroundColor = .clear
|
|
351
|
+
sdkWindow.isOpaque = false
|
|
352
|
+
sdkWindow.makeKeyAndVisible()
|
|
100
353
|
|
|
101
|
-
|
|
354
|
+
print("🟠 SDK window created and made visible")
|
|
102
355
|
} catch {
|
|
103
356
|
print("Presentation failed: \(error.localizedDescription)")
|
|
104
|
-
|
|
357
|
+
let errorData: [String: Any] = [
|
|
358
|
+
"data": [
|
|
359
|
+
"status": "ERROR",
|
|
360
|
+
"message": error.localizedDescription
|
|
361
|
+
]
|
|
362
|
+
]
|
|
363
|
+
self.emitOnResponse(errorData)
|
|
105
364
|
}
|
|
106
365
|
}
|
|
107
366
|
}
|
|
108
367
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
override
|
|
368
|
+
@objc
|
|
369
|
+
open override func addListener(_ eventName: String) {
|
|
370
|
+
super.addListener(eventName)
|
|
371
|
+
print("🔴 addListener called for: \(eventName)")
|
|
372
|
+
if !hasListeners {
|
|
373
|
+
hasListeners = true
|
|
374
|
+
print("🔴 Set hasListeners = true")
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
@objc
|
|
379
|
+
open override func removeListeners(_ count: Double) {
|
|
380
|
+
super.removeListeners(count)
|
|
381
|
+
print("🔴 removeListeners called with count: \(count)")
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
@objc
|
|
385
|
+
public override static func requiresMainQueueSetup() -> Bool {
|
|
121
386
|
return true
|
|
122
387
|
}
|
|
388
|
+
|
|
389
|
+
// Dismiss SDK window when payment completes
|
|
390
|
+
private func dismissSDKWindow() {
|
|
391
|
+
print("🟠 Dismissing SDK window...")
|
|
392
|
+
sdkWindow?.isHidden = true
|
|
393
|
+
sdkWindow?.rootViewController = nil
|
|
394
|
+
sdkWindow = nil
|
|
395
|
+
}
|
|
123
396
|
}
|
|
@@ -61,14 +61,28 @@ class AmwalPaySDK {
|
|
|
61
61
|
setupEventListeners(config) {
|
|
62
62
|
// Remove any existing listeners
|
|
63
63
|
this.removeEventListeners();
|
|
64
|
+
console.log('🟢 Setting up event listeners...');
|
|
65
|
+
console.log('🟢 onResponse callback exists?', typeof config.onResponse === 'function');
|
|
66
|
+
console.log('🟢 onCustomerId callback exists?', typeof config.onCustomerId === 'function');
|
|
64
67
|
this.onResponseSubscription = onResponse(response => {
|
|
68
|
+
console.log('🟢 SDK onResponse listener triggered with:', response);
|
|
65
69
|
console.log('Received AmwalPayResponse:', response);
|
|
66
|
-
config.onResponse
|
|
70
|
+
if (config.onResponse) {
|
|
71
|
+
config.onResponse(response);
|
|
72
|
+
} else {
|
|
73
|
+
console.error('❌ config.onResponse is not a function!');
|
|
74
|
+
}
|
|
67
75
|
});
|
|
68
76
|
this.onCustomerIdSubscription = onCustomerId(customerId => {
|
|
77
|
+
console.log('🟢 SDK onCustomerId listener triggered with:', customerId);
|
|
69
78
|
console.log('Received customerId:', customerId);
|
|
70
|
-
config.onCustomerId
|
|
79
|
+
if (config.onCustomerId) {
|
|
80
|
+
config.onCustomerId(customerId);
|
|
81
|
+
} else {
|
|
82
|
+
console.error('❌ config.onCustomerId is not a function!');
|
|
83
|
+
}
|
|
71
84
|
});
|
|
85
|
+
console.log('🟢 Event listeners set up complete');
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["initiate","onCustomerId","onResponse","NetworkClient","AmwalPaySDK","onResponseSubscription","onCustomerIdSubscription","constructor","getInstance","instance","startPayment","config","setupEventListeners","networkClient","console","log","environment","sessionToken","fetchSessionToken","merchantId","customerId","secureHash","completeConfig","JSON","stringify","error","dispose","removeEventListeners","response","remove"],"sourceRoot":"../../src","sources":["AmwalPaySDK.ts"],"mappings":";;AAAA,SAASA,QAAQ,EAAEC,YAAY,EAAEC,UAAU,QAA6B,YAAS;AACjF,OAAOC,aAAa,MAAM,4BAAyB;AAInD,MAAMC,WAAW,CAAC;EAGRC,sBAAsB,GAA6B,IAAI;EAEvDC,wBAAwB,GAA6B,IAAI;EAEzDC,WAAWA,CAAA,EAAG;IACpB;EAAA;EAIF,OAAOC,WAAWA,CAAA,EAAgB;IAChC,IAAI,CAACJ,WAAW,CAACK,QAAQ,EAAE;MACzBL,WAAW,CAACK,QAAQ,GAAG,IAAIL,WAAW,CAAC,CAAC;IAC1C;IACA,OAAOA,WAAW,CAACK,QAAQ;EAC7B;;EAEA;AACF;AACA;AACA;EACE,MAAMC,YAAYA,CAACC,MAA4C,EAAiB;IAC9E,IAAI;MACF;MACA,IAAI,CAACC,mBAAmB,CAACD,MAAM,CAAC;;MAEhC;MACA,MAAME,aAAa,GAAGV,aAAa,CAACK,WAAW,CAAC,CAAC;;MAEjD;MACAM,OAAO,CAACC,GAAG,CAAC,yCAAyC,EAAEJ,MAAM,CAACK,WAAW,CAAC;MAC1E,MAAMC,YAAY,GAAG,MAAMJ,aAAa,CAACK,iBAAiB,CACxDP,MAAM,CAACK,WAAW,EAClBL,MAAM,CAACQ,UAAU,EACjBR,MAAM,CAACS,UAAU,EACjBT,MAAM,CAACU,UACT,CAAC;MAEDP,OAAO,CAACC,GAAG,CAAC,uBAAuB,EAAEE,YAAY,GAAG,SAAS,GAAG,QAAQ,CAAC;MAEzE,IAAI,CAACA,YAAY,EAAE;QACjB;QACA;MACF;;MAEA;MACA,MAAMK,cAA8B,GAAG;QACrC,GAAGX,MAAM;QACTM;MACF,CAAC;;MAED;MACAH,OAAO,CAACC,GAAG,CAAC,wCAAwC,EAAEQ,IAAI,CAACC,SAAS,CAACF,cAAc,CAAC,CAAC;MACrFtB,QAAQ,CAACsB,cAAc,CAAC;IAC1B,CAAC,CAAC,OAAOG,KAAK,EAAE;MACdX,OAAO,CAACW,KAAK,CAAC,yBAAyB,EAAEA,KAAK,CAAC;IACjD;EACF;EAEAC,OAAOA,CAAA,EAAS;IACd;IACA,IAAI,CAACC,oBAAoB,CAAC,CAAC;EAC7B;;EAEA;AACF;AACA;AACA;EACUf,mBAAmBA,CAACD,MAA4C,EAAQ;IAC9E;IACA,IAAI,CAACgB,oBAAoB,CAAC,CAAC;
|
|
1
|
+
{"version":3,"names":["initiate","onCustomerId","onResponse","NetworkClient","AmwalPaySDK","onResponseSubscription","onCustomerIdSubscription","constructor","getInstance","instance","startPayment","config","setupEventListeners","networkClient","console","log","environment","sessionToken","fetchSessionToken","merchantId","customerId","secureHash","completeConfig","JSON","stringify","error","dispose","removeEventListeners","response","remove"],"sourceRoot":"../../src","sources":["AmwalPaySDK.ts"],"mappings":"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","ignoreList":[]}
|
|
@@ -18,7 +18,12 @@ export let TransactionType = /*#__PURE__*/function (TransactionType) {
|
|
|
18
18
|
return TransactionType;
|
|
19
19
|
}({});
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
/**
|
|
22
|
+
* Configuration interface for Amwal Pay SDK
|
|
23
|
+
*
|
|
24
|
+
* @interface AmwalPayConfig
|
|
25
|
+
* @description Complete configuration for initializing and starting a payment session
|
|
26
|
+
*/
|
|
22
27
|
|
|
23
28
|
// This is the configuration that will be passed to the native module
|
|
24
29
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["TurboModuleRegistry","Environment","Currency","TransactionType","getEnforcing"],"sourceRoot":"../../src","sources":["NativeReactAmwalPay.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAElD,WAAYC,WAAW,0BAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAA,OAAXA,WAAW;AAAA;AAMvB,WAAYC,QAAQ,0BAARA,QAAQ;EAARA,QAAQ;EAAA,OAARA,QAAQ;AAAA;AAIpB,WAAYC,eAAe,0BAAfA,eAAe;EAAfA,eAAe;EAAfA,eAAe;EAAfA,eAAe;EAAA,OAAfA,eAAe;AAAA;;AAY3B;;
|
|
1
|
+
{"version":3,"names":["TurboModuleRegistry","Environment","Currency","TransactionType","getEnforcing"],"sourceRoot":"../../src","sources":["NativeReactAmwalPay.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAElD,WAAYC,WAAW,0BAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAXA,WAAW;EAAA,OAAXA,WAAW;AAAA;AAMvB,WAAYC,QAAQ,0BAARA,QAAQ;EAARA,QAAQ;EAAA,OAARA,QAAQ;AAAA;AAIpB,WAAYC,eAAe,0BAAfA,eAAe;EAAfA,eAAe;EAAfA,eAAe;EAAfA,eAAe;EAAA,OAAfA,eAAe;AAAA;;AAY3B;AACA;AACA;AACA;AACA;AACA;;AAsDA;;AAwBA,eAAeH,mBAAmB,CAACI,YAAY,CAAO,eAAe,CAAC","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AmwalPaySDK.d.ts","sourceRoot":"","sources":["../../../src/AmwalPaySDK.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAKlF,cAAM,WAAW;IACf,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAc;IAErC,OAAO,CAAC,sBAAsB,CAAkC;IAEhE,OAAO,CAAC,wBAAwB,CAAkC;IAElE,OAAO;IAKP,MAAM,CAAC,WAAW,IAAI,WAAW;IAOjC;;;OAGG;IACG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC/E,OAAO,IAAI,IAAI;IAKf;;;OAGG;IACH,OAAO,CAAC,mBAAmB;
|
|
1
|
+
{"version":3,"file":"AmwalPaySDK.d.ts","sourceRoot":"","sources":["../../../src/AmwalPaySDK.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsC,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AAKlF,cAAM,WAAW;IACf,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAc;IAErC,OAAO,CAAC,sBAAsB,CAAkC;IAEhE,OAAO,CAAC,wBAAwB,CAAkC;IAElE,OAAO;IAKP,MAAM,CAAC,WAAW,IAAI,WAAW;IAOjC;;;OAGG;IACG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,cAAc,EAAE,cAAc,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAsC/E,OAAO,IAAI,IAAI;IAKf;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA+B3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAM7B;AAED,eAAe,WAAW,CAAC"}
|
|
@@ -17,23 +17,64 @@ export interface AmwalPayResponse {
|
|
|
17
17
|
message: string;
|
|
18
18
|
data?: Object;
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Configuration interface for Amwal Pay SDK
|
|
22
|
+
*
|
|
23
|
+
* @interface AmwalPayConfig
|
|
24
|
+
* @description Complete configuration for initializing and starting a payment session
|
|
25
|
+
*/
|
|
20
26
|
export interface AmwalPayConfig {
|
|
27
|
+
/** Target environment (SIT, UAT, or PROD) */
|
|
21
28
|
environment: Environment;
|
|
29
|
+
/** Secure hash for authentication */
|
|
22
30
|
secureHash: string;
|
|
31
|
+
/** Transaction currency */
|
|
23
32
|
currency: Currency;
|
|
33
|
+
/** Transaction amount as string (e.g., "100.000") */
|
|
24
34
|
amount: string;
|
|
35
|
+
/** Merchant identifier */
|
|
25
36
|
merchantId: string;
|
|
37
|
+
/** Terminal identifier */
|
|
26
38
|
terminalId: string;
|
|
39
|
+
/** Locale for UI language ('en' or 'ar') */
|
|
27
40
|
locale: string;
|
|
41
|
+
/** Optional customer identifier */
|
|
28
42
|
customerId: string | null;
|
|
43
|
+
/** Type of transaction (NFC, CARD_WALLET, APPLE_PAY) */
|
|
29
44
|
transactionType: TransactionType;
|
|
45
|
+
/** Optional session token (auto-fetched if not provided) */
|
|
30
46
|
sessionToken?: string;
|
|
47
|
+
/** Optional transaction ID (auto-generated if not provided) */
|
|
31
48
|
transactionId?: string;
|
|
49
|
+
/**
|
|
50
|
+
* Optional additional configuration values
|
|
51
|
+
*
|
|
52
|
+
* Supported keys:
|
|
53
|
+
* - `useBottomSheetDesign`: 'true' | 'false' - Use bottom sheet design (v2) instead of full screen
|
|
54
|
+
* - `ignoreReceipt`: 'true' | 'false' - Skip receipt display after transaction
|
|
55
|
+
* - `primaryColor`: Hex color string (e.g., '#FF5733') - Primary theme color
|
|
56
|
+
* - `secondaryColor`: Hex color string (e.g., '#33FF57') - Secondary theme color
|
|
57
|
+
* - `merchantIdentifier`: String - Apple Pay merchant identifier (default: 'merchant.applepay.amwalpay')
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* additionValues: {
|
|
62
|
+
* useBottomSheetDesign: 'true',
|
|
63
|
+
* primaryColor: '#1E88E5',
|
|
64
|
+
* secondaryColor: '#FFC107',
|
|
65
|
+
* ignoreReceipt: 'false',
|
|
66
|
+
* merchantIdentifier: 'merchant.applepay.amwalpay'
|
|
67
|
+
* }
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
32
70
|
additionValues?: {
|
|
33
71
|
[key: string]: string;
|
|
34
72
|
};
|
|
73
|
+
/** Optional merchant reference for transaction tracking */
|
|
35
74
|
merchantReference?: string;
|
|
75
|
+
/** Callback for payment response */
|
|
36
76
|
onResponse: (response: AmwalPayResponse) => void;
|
|
77
|
+
/** Callback for customer ID updates */
|
|
37
78
|
onCustomerId: (customerId: string) => void;
|
|
38
79
|
}
|
|
39
80
|
export interface AmwalPayNativeConfig {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NativeReactAmwalPay.d.ts","sourceRoot":"","sources":["../../../src/NativeReactAmwalPay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,oBAAY,WAAW;IACrB,GAAG,QAAQ;IACX,GAAG,QAAQ;IACX,IAAI,SAAS;CACd;AAED,oBAAY,QAAQ;IAClB,GAAG,QAAQ;CACZ;AAED,oBAAY,eAAe;IACzB,GAAG,QAAQ;IACX,WAAW,gBAAgB;IAC3B,SAAS,cAAc;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"NativeReactAmwalPay.d.ts","sourceRoot":"","sources":["../../../src/NativeReactAmwalPay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,oBAAY,WAAW;IACrB,GAAG,QAAQ;IACX,GAAG,QAAQ;IACX,IAAI,SAAS;CACd;AAED,oBAAY,QAAQ;IAClB,GAAG,QAAQ;CACZ;AAED,oBAAY,eAAe;IACzB,GAAG,QAAQ;IACX,WAAW,gBAAgB;IAC3B,SAAS,cAAc;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,6CAA6C;IAC7C,WAAW,EAAE,WAAW,CAAC;IACzB,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,2BAA2B;IAC3B,QAAQ,EAAE,QAAQ,CAAC;IACnB,qDAAqD;IACrD,MAAM,EAAE,MAAM,CAAC;IACf,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,0BAA0B;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,mCAAmC;IACnC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,wDAAwD;IACxD,eAAe,EAAE,eAAe,CAAC;IACjC,4DAA4D;IAC5D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;;;;;;;;;;;;;OAoBG;IACH,cAAc,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAC3C,2DAA2D;IAC3D,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oCAAoC;IACpC,UAAU,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACjD,uCAAuC;IACvC,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;CAC5C;AAGD,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,cAAc,CAAC,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAC3C,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IAEvC,QAAQ,CAAC,MAAM,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAC7C,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtC;;AAED,wBAAuE"}
|
package/package.json
CHANGED
package/src/AmwalPaySDK.ts
CHANGED
|
@@ -77,15 +77,31 @@ class AmwalPaySDK {
|
|
|
77
77
|
// Remove any existing listeners
|
|
78
78
|
this.removeEventListeners();
|
|
79
79
|
|
|
80
|
+
console.log('🟢 Setting up event listeners...');
|
|
81
|
+
console.log('🟢 onResponse callback exists?', typeof config.onResponse === 'function');
|
|
82
|
+
console.log('🟢 onCustomerId callback exists?', typeof config.onCustomerId === 'function');
|
|
83
|
+
|
|
80
84
|
this.onResponseSubscription = onResponse((response) => {
|
|
85
|
+
console.log('🟢 SDK onResponse listener triggered with:', response);
|
|
81
86
|
console.log('Received AmwalPayResponse:', response);
|
|
82
|
-
config.onResponse
|
|
87
|
+
if (config.onResponse) {
|
|
88
|
+
config.onResponse(response);
|
|
89
|
+
} else {
|
|
90
|
+
console.error('❌ config.onResponse is not a function!');
|
|
91
|
+
}
|
|
83
92
|
});
|
|
84
93
|
|
|
85
94
|
this.onCustomerIdSubscription = onCustomerId((customerId) => {
|
|
95
|
+
console.log('🟢 SDK onCustomerId listener triggered with:', customerId);
|
|
86
96
|
console.log('Received customerId:', customerId);
|
|
87
|
-
config.onCustomerId
|
|
97
|
+
if (config.onCustomerId) {
|
|
98
|
+
config.onCustomerId(customerId);
|
|
99
|
+
} else {
|
|
100
|
+
console.error('❌ config.onCustomerId is not a function!');
|
|
101
|
+
}
|
|
88
102
|
});
|
|
103
|
+
|
|
104
|
+
console.log('🟢 Event listeners set up complete');
|
|
89
105
|
}
|
|
90
106
|
|
|
91
107
|
/**
|
|
@@ -4,7 +4,7 @@ import { TurboModuleRegistry } from 'react-native';
|
|
|
4
4
|
export enum Environment {
|
|
5
5
|
SIT = 'SIT',
|
|
6
6
|
UAT = 'UAT',
|
|
7
|
-
PROD = 'PROD'
|
|
7
|
+
PROD = 'PROD',
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export enum Currency {
|
|
@@ -14,7 +14,7 @@ export enum Currency {
|
|
|
14
14
|
export enum TransactionType {
|
|
15
15
|
NFC = 'NFC',
|
|
16
16
|
CARD_WALLET = 'CARD_WALLET',
|
|
17
|
-
APPLE_PAY = 'APPLE_PAY'
|
|
17
|
+
APPLE_PAY = 'APPLE_PAY',
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export interface AmwalPayResponse {
|
|
@@ -23,22 +23,62 @@ export interface AmwalPayResponse {
|
|
|
23
23
|
data?: Object; // Changed from 'any' to 'Object'
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Configuration interface for Amwal Pay SDK
|
|
28
|
+
*
|
|
29
|
+
* @interface AmwalPayConfig
|
|
30
|
+
* @description Complete configuration for initializing and starting a payment session
|
|
31
|
+
*/
|
|
27
32
|
export interface AmwalPayConfig {
|
|
33
|
+
/** Target environment (SIT, UAT, or PROD) */
|
|
28
34
|
environment: Environment;
|
|
35
|
+
/** Secure hash for authentication */
|
|
29
36
|
secureHash: string;
|
|
37
|
+
/** Transaction currency */
|
|
30
38
|
currency: Currency;
|
|
39
|
+
/** Transaction amount as string (e.g., "100.000") */
|
|
31
40
|
amount: string;
|
|
41
|
+
/** Merchant identifier */
|
|
32
42
|
merchantId: string;
|
|
43
|
+
/** Terminal identifier */
|
|
33
44
|
terminalId: string;
|
|
45
|
+
/** Locale for UI language ('en' or 'ar') */
|
|
34
46
|
locale: string;
|
|
47
|
+
/** Optional customer identifier */
|
|
35
48
|
customerId: string | null;
|
|
49
|
+
/** Type of transaction (NFC, CARD_WALLET, APPLE_PAY) */
|
|
36
50
|
transactionType: TransactionType;
|
|
51
|
+
/** Optional session token (auto-fetched if not provided) */
|
|
37
52
|
sessionToken?: string;
|
|
53
|
+
/** Optional transaction ID (auto-generated if not provided) */
|
|
38
54
|
transactionId?: string;
|
|
55
|
+
/**
|
|
56
|
+
* Optional additional configuration values
|
|
57
|
+
*
|
|
58
|
+
* Supported keys:
|
|
59
|
+
* - `useBottomSheetDesign`: 'true' | 'false' - Use bottom sheet design (v2) instead of full screen
|
|
60
|
+
* - `ignoreReceipt`: 'true' | 'false' - Skip receipt display after transaction
|
|
61
|
+
* - `primaryColor`: Hex color string (e.g., '#FF5733') - Primary theme color
|
|
62
|
+
* - `secondaryColor`: Hex color string (e.g., '#33FF57') - Secondary theme color
|
|
63
|
+
* - `merchantIdentifier`: String - Apple Pay merchant identifier (default: 'merchant.applepay.amwalpay')
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```typescript
|
|
67
|
+
* additionValues: {
|
|
68
|
+
* useBottomSheetDesign: 'true',
|
|
69
|
+
* primaryColor: '#1E88E5',
|
|
70
|
+
* secondaryColor: '#FFC107',
|
|
71
|
+
* ignoreReceipt: 'false',
|
|
72
|
+
* merchantIdentifier: 'merchant.applepay.amwalpay'
|
|
73
|
+
* }
|
|
74
|
+
* ```
|
|
75
|
+
*/
|
|
39
76
|
additionValues?: { [key: string]: string };
|
|
77
|
+
/** Optional merchant reference for transaction tracking */
|
|
40
78
|
merchantReference?: string;
|
|
79
|
+
/** Callback for payment response */
|
|
41
80
|
onResponse: (response: AmwalPayResponse) => void;
|
|
81
|
+
/** Callback for customer ID updates */
|
|
42
82
|
onCustomerId: (customerId: string) => void;
|
|
43
83
|
}
|
|
44
84
|
|