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 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
- customKey: 'customValue' // add more as needed
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
- ### Usage
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
- merchantIdentifier: 'merchant.custom.identifier',
253
- customKey: 'customValue'
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:
@@ -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(onResponse:(RCTResponseSenderBlock)callback)
8
+ RCT_EXTERN_METHOD(addListener:(NSString *)eventName)
11
9
 
12
- RCT_EXTERN_METHOD(onCustomerId:(RCTResponseSenderBlock)callback)
10
+ RCT_EXTERN_METHOD(removeListeners:(double)count)
13
11
 
14
12
  @end
@@ -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
- reject("NO_ROOT_VC", "No root view controller found", nil)
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
- self?.onResponseCallback?([[
88
- "status": response != nil ? "success" : "error",
89
- "message": response != nil ? "Transaction completed" : "Transaction failed",
90
- "data": response ?? ""
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
- self?.onCustomerIdCallback?([customerId])
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
- // Present modally (critical missing piece)
99
- rootVC.present(sdkVC, animated: true)
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
- resolve(true)
354
+ print("🟠 SDK window created and made visible")
102
355
  } catch {
103
356
  print("Presentation failed: \(error.localizedDescription)")
104
- reject("PRESENTATION_ERROR", error.localizedDescription, error)
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
- @objc
110
- func onResponse(_ callback: @escaping RCTResponseSenderBlock) {
111
- onResponseCallback = callback
112
- }
113
-
114
- @objc
115
- func onCustomerId(_ callback: @escaping RCTResponseSenderBlock) {
116
- onCustomerIdCallback = callback
117
- }
118
-
119
-
120
- override static func requiresMainQueueSetup() -> Bool {
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(response);
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(customerId);
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;IAE3B,IAAI,CAACtB,sBAAsB,GAAGH,UAAU,CAAE0B,QAAQ,IAAK;MACrDd,OAAO,CAACC,GAAG,CAAC,4BAA4B,EAAEa,QAAQ,CAAC;MACnDjB,MAAM,CAACT,UAAU,CAAC0B,QAAQ,CAAC;IAC7B,CAAC,CAAC;IAEF,IAAI,CAACtB,wBAAwB,GAAGL,YAAY,CAAEmB,UAAU,IAAK;MAC3DN,OAAO,CAACC,GAAG,CAAC,sBAAsB,EAAEK,UAAU,CAAC;MAC/CT,MAAM,CAACV,YAAY,CAACmB,UAAU,CAAC;IACjC,CAAC,CAAC;EACJ;;EAEA;AACF;AACA;EACUO,oBAAoBA,CAAA,EAAS;IACnC,IAAI,CAACtB,sBAAsB,EAAEwB,MAAM,CAAC,CAAC;IACrC,IAAI,CAACvB,wBAAwB,EAAEuB,MAAM,CAAC,CAAC;IACvC,IAAI,CAACxB,sBAAsB,GAAG,IAAI;IAClC,IAAI,CAACC,wBAAwB,GAAG,IAAI;EACtC;AACF;AAEA,eAAeF,WAAW","ignoreList":[]}
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
- // This interface is for JavaScript side only, not for the native module spec
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;;AAmBA;;AAwBA,eAAeH,mBAAmB,CAACI,YAAY,CAAO,eAAe,CAAC","ignoreList":[]}
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;IAe3B;;OAEG;IACH,OAAO,CAAC,oBAAoB;CAM7B;AAED,eAAe,WAAW,CAAC"}
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;AAGD,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,WAAW,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,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,eAAe,CAAC;IACjC,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;IAC3B,UAAU,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACjD,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"}
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-amwal-pay",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "amwal pay",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
@@ -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(response);
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(customerId);
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
- // This interface is for JavaScript side only, not for the native module spec
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