@yuno-payments/yuno-sdk-react-native 1.0.16

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.
Files changed (92) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +621 -0
  3. package/android/build.gradle +131 -0
  4. package/android/gradle.properties +5 -0
  5. package/android/src/main/AndroidManifest.xml +4 -0
  6. package/android/src/main/java/com/yunosdkreactnative/YunoPaymentMethodsViewManager.kt +194 -0
  7. package/android/src/main/java/com/yunosdkreactnative/YunoSdkModule.kt +777 -0
  8. package/android/src/main/java/com/yunosdkreactnative/YunoSdkPackage.kt +24 -0
  9. package/ios/YunoSdk.m +65 -0
  10. package/ios/YunoSdk.podspec +48 -0
  11. package/ios/YunoSdk.swift +442 -0
  12. package/lib/commonjs/YunoPaymentMethods.js +145 -0
  13. package/lib/commonjs/YunoPaymentMethods.js.map +1 -0
  14. package/lib/commonjs/YunoSdk.js +455 -0
  15. package/lib/commonjs/YunoSdk.js.map +1 -0
  16. package/lib/commonjs/core/enums/CardFlow.js +26 -0
  17. package/lib/commonjs/core/enums/CardFlow.js.map +1 -0
  18. package/lib/commonjs/core/enums/YunoLanguage.js +58 -0
  19. package/lib/commonjs/core/enums/YunoLanguage.js.map +1 -0
  20. package/lib/commonjs/core/enums/YunoStatus.js +40 -0
  21. package/lib/commonjs/core/enums/YunoStatus.js.map +1 -0
  22. package/lib/commonjs/core/enums/index.js +27 -0
  23. package/lib/commonjs/core/enums/index.js.map +1 -0
  24. package/lib/commonjs/core/index.js +28 -0
  25. package/lib/commonjs/core/index.js.map +1 -0
  26. package/lib/commonjs/core/types/AndroidConfig.js +2 -0
  27. package/lib/commonjs/core/types/AndroidConfig.js.map +1 -0
  28. package/lib/commonjs/core/types/EnrollmentArguments.js +2 -0
  29. package/lib/commonjs/core/types/EnrollmentArguments.js.map +1 -0
  30. package/lib/commonjs/core/types/IosConfig.js +2 -0
  31. package/lib/commonjs/core/types/IosConfig.js.map +1 -0
  32. package/lib/commonjs/core/types/OneTimeTokenInfo.js +2 -0
  33. package/lib/commonjs/core/types/OneTimeTokenInfo.js.map +1 -0
  34. package/lib/commonjs/core/types/SeamlessArguments.js +6 -0
  35. package/lib/commonjs/core/types/SeamlessArguments.js.map +1 -0
  36. package/lib/commonjs/core/types/StartPayment.js +2 -0
  37. package/lib/commonjs/core/types/StartPayment.js.map +1 -0
  38. package/lib/commonjs/core/types/YunoConfig.js +6 -0
  39. package/lib/commonjs/core/types/YunoConfig.js.map +1 -0
  40. package/lib/commonjs/core/types/index.js +2 -0
  41. package/lib/commonjs/core/types/index.js.map +1 -0
  42. package/lib/commonjs/index.js +36 -0
  43. package/lib/commonjs/index.js.map +1 -0
  44. package/lib/module/YunoPaymentMethods.js +138 -0
  45. package/lib/module/YunoPaymentMethods.js.map +1 -0
  46. package/lib/module/YunoSdk.js +448 -0
  47. package/lib/module/YunoSdk.js.map +1 -0
  48. package/lib/module/core/enums/CardFlow.js +20 -0
  49. package/lib/module/core/enums/CardFlow.js.map +1 -0
  50. package/lib/module/core/enums/YunoLanguage.js +52 -0
  51. package/lib/module/core/enums/YunoLanguage.js.map +1 -0
  52. package/lib/module/core/enums/YunoStatus.js +34 -0
  53. package/lib/module/core/enums/YunoStatus.js.map +1 -0
  54. package/lib/module/core/enums/index.js +4 -0
  55. package/lib/module/core/enums/index.js.map +1 -0
  56. package/lib/module/core/index.js +3 -0
  57. package/lib/module/core/index.js.map +1 -0
  58. package/lib/module/core/types/AndroidConfig.js +2 -0
  59. package/lib/module/core/types/AndroidConfig.js.map +1 -0
  60. package/lib/module/core/types/EnrollmentArguments.js +2 -0
  61. package/lib/module/core/types/EnrollmentArguments.js.map +1 -0
  62. package/lib/module/core/types/IosConfig.js +2 -0
  63. package/lib/module/core/types/IosConfig.js.map +1 -0
  64. package/lib/module/core/types/OneTimeTokenInfo.js +2 -0
  65. package/lib/module/core/types/OneTimeTokenInfo.js.map +1 -0
  66. package/lib/module/core/types/SeamlessArguments.js +2 -0
  67. package/lib/module/core/types/SeamlessArguments.js.map +1 -0
  68. package/lib/module/core/types/StartPayment.js +2 -0
  69. package/lib/module/core/types/StartPayment.js.map +1 -0
  70. package/lib/module/core/types/YunoConfig.js +2 -0
  71. package/lib/module/core/types/YunoConfig.js.map +1 -0
  72. package/lib/module/core/types/index.js +2 -0
  73. package/lib/module/core/types/index.js.map +1 -0
  74. package/lib/module/index.js +4 -0
  75. package/lib/module/index.js.map +1 -0
  76. package/package.json +142 -0
  77. package/src/YunoPaymentMethods.tsx +196 -0
  78. package/src/YunoSdk.ts +518 -0
  79. package/src/core/enums/CardFlow.ts +18 -0
  80. package/src/core/enums/YunoLanguage.ts +50 -0
  81. package/src/core/enums/YunoStatus.ts +32 -0
  82. package/src/core/enums/index.ts +3 -0
  83. package/src/core/index.ts +2 -0
  84. package/src/core/types/AndroidConfig.ts +17 -0
  85. package/src/core/types/EnrollmentArguments.ts +32 -0
  86. package/src/core/types/IosConfig.ts +17 -0
  87. package/src/core/types/OneTimeTokenInfo.ts +207 -0
  88. package/src/core/types/SeamlessArguments.ts +42 -0
  89. package/src/core/types/StartPayment.ts +59 -0
  90. package/src/core/types/YunoConfig.ts +55 -0
  91. package/src/core/types/index.ts +7 -0
  92. package/src/index.ts +17 -0
@@ -0,0 +1,24 @@
1
+ package com.yunosdkreactnative
2
+
3
+ import com.facebook.react.ReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.uimanager.ViewManager
7
+
8
+ /**
9
+ * Yuno SDK React Native Package.
10
+ *
11
+ * This class registers the Yuno SDK module with React Native.
12
+ */
13
+ class YunoSdkPackage : ReactPackage {
14
+ override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
15
+ return listOf(YunoSdkModule(reactContext))
16
+ }
17
+
18
+ override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
19
+ return listOf(
20
+ YunoPaymentMethodsViewManager(reactContext)
21
+ )
22
+ }
23
+ }
24
+
package/ios/YunoSdk.m ADDED
@@ -0,0 +1,65 @@
1
+ #import <React/RCTBridgeModule.h>
2
+ #import <React/RCTEventEmitter.h>
3
+
4
+ @interface RCT_EXTERN_MODULE(YunoSdk, RCTEventEmitter)
5
+
6
+ RCT_EXTERN_METHOD(
7
+ initialize:(NSString *)apiKey
8
+ countryCode:(NSString *)countryCode
9
+ yunoConfig:(NSDictionary *)yunoConfig
10
+ iosConfig:(NSDictionary *)iosConfig
11
+ androidConfig:(NSDictionary *)androidConfig
12
+ resolver:(RCTPromiseResolveBlock)resolver
13
+ rejecter:(RCTPromiseRejectBlock)rejecter
14
+ )
15
+
16
+ RCT_EXTERN_METHOD(
17
+ enrollmentPayment:(NSDictionary *)arguments
18
+ resolver:(RCTPromiseResolveBlock)resolver
19
+ rejecter:(RCTPromiseRejectBlock)rejecter
20
+ )
21
+
22
+ RCT_EXTERN_METHOD(
23
+ startPaymentLite:(NSDictionary *)arguments
24
+ countryCode:(NSString *)countryCode
25
+ resolver:(RCTPromiseResolveBlock)resolver
26
+ rejecter:(RCTPromiseRejectBlock)rejecter
27
+ )
28
+
29
+ RCT_EXTERN_METHOD(
30
+ startPayment:(BOOL)showPaymentStatus
31
+ resolver:(RCTPromiseResolveBlock)resolver
32
+ rejecter:(RCTPromiseRejectBlock)rejecter
33
+ )
34
+
35
+ RCT_EXTERN_METHOD(
36
+ continuePayment:(BOOL)showPaymentStatus
37
+ resolver:(RCTPromiseResolveBlock)resolver
38
+ rejecter:(RCTPromiseRejectBlock)rejecter
39
+ )
40
+
41
+ RCT_EXTERN_METHOD(
42
+ startPaymentSeamlessLite:(NSDictionary *)arguments
43
+ language:(NSString *)language
44
+ resolver:(RCTPromiseResolveBlock)resolver
45
+ rejecter:(RCTPromiseRejectBlock)rejecter
46
+ )
47
+
48
+ RCT_EXTERN_METHOD(
49
+ hideLoader:(RCTPromiseResolveBlock)resolver
50
+ rejecter:(RCTPromiseRejectBlock)rejecter
51
+ )
52
+
53
+ RCT_EXTERN_METHOD(
54
+ receiveDeeplink:(NSString *)url
55
+ resolver:(RCTPromiseResolveBlock)resolver
56
+ rejecter:(RCTPromiseRejectBlock)rejecter
57
+ )
58
+
59
+ + (BOOL)requiresMainQueueSetup
60
+ {
61
+ return YES;
62
+ }
63
+
64
+ @end
65
+
@@ -0,0 +1,48 @@
1
+ require "json"
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, "../package.json")))
4
+ folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
5
+
6
+ Pod::Spec.new do |s|
7
+ s.name = "YunoSdk"
8
+ s.version = package["version"]
9
+ s.summary = package["description"]
10
+ s.homepage = package["homepage"]
11
+ s.license = package["license"]
12
+ s.authors = package["author"]
13
+
14
+ s.platforms = { :ios => "14.0" }
15
+ s.source = { :git => "https://github.com/yuno-payments/yuno-sdk-react-native.git", :tag => "#{s.version}" }
16
+
17
+ s.source_files = "*.{h,m,mm,swift}"
18
+
19
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
20
+ # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
21
+ if respond_to?(:install_modules_dependencies, true)
22
+ install_modules_dependencies(s)
23
+ else
24
+ s.dependency "React-Core"
25
+
26
+ # Don't install the dependencies when we run `pod install` in the old architecture.
27
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
28
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
29
+ s.pod_target_xcconfig = {
30
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
31
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
32
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
33
+ }
34
+ s.dependency "React-Codegen"
35
+ s.dependency "RCT-Folly"
36
+ s.dependency "RCTRequired"
37
+ s.dependency "RCTTypeSafety"
38
+ s.dependency "ReactCommon/turbomodule/core"
39
+ end
40
+ end
41
+
42
+ # Yuno iOS SDK
43
+ s.dependency "YunoSDK", "2.7.1"
44
+
45
+ s.swift_version = '5.0'
46
+ s.static_framework = true
47
+ end
48
+
@@ -0,0 +1,442 @@
1
+ import Foundation
2
+ import YunoSDK
3
+
4
+ /**
5
+ * Yuno SDK React Native Module for iOS.
6
+ *
7
+ * This module provides a bridge between React Native JavaScript code and the native Yuno iOS SDK.
8
+ */
9
+ @objc(YunoSdk)
10
+ class YunoSdk: RCTEventEmitter {
11
+
12
+ private var isInitialized = false
13
+ private var currentCountryCode: String?
14
+ private var currentLanguage: String?
15
+ private var customerSession: String = ""
16
+ private var checkoutSession: String = ""
17
+
18
+ override init() {
19
+ super.init()
20
+ }
21
+
22
+ override static func requiresMainQueueSetup() -> Bool {
23
+ return true
24
+ }
25
+
26
+ override func supportedEvents() -> [String]! {
27
+ return [
28
+ "YunoPaymentStatus",
29
+ "YunoEnrollmentStatus",
30
+ "YunoOneTimeToken"
31
+ ]
32
+ }
33
+
34
+ /**
35
+ * Initialize the Yuno SDK with configuration.
36
+ */
37
+ @objc
38
+ func initialize(
39
+ _ apiKey: String,
40
+ countryCode: String,
41
+ yunoConfig: NSDictionary,
42
+ iosConfig: NSDictionary?,
43
+ androidConfig: NSDictionary?,
44
+ resolver: @escaping RCTPromiseResolveBlock,
45
+ rejecter: @escaping RCTPromiseRejectBlock
46
+ ) {
47
+ DispatchQueue.main.async { [weak self] in
48
+ guard let self = self else { return }
49
+
50
+ do {
51
+ self.currentCountryCode = countryCode
52
+
53
+ // Parse language
54
+ if let lang = yunoConfig["lang"] as? String {
55
+ self.currentLanguage = lang
56
+ }
57
+
58
+ // Parse card flow
59
+ var cardFlow: YunoCardFlow = .oneStep
60
+ if let flow = yunoConfig["cardFlow"] as? String {
61
+ cardFlow = self.mapToCardFlow(flow)
62
+ }
63
+
64
+ // Parse other config options
65
+ let saveCardEnabled = yunoConfig["saveCardEnabled"] as? Bool ?? false
66
+ let keepLoader = yunoConfig["keepLoader"] as? Bool ?? false
67
+
68
+ // Initialize Yuno SDK
69
+ Yuno.initialize(
70
+ apiKey: apiKey,
71
+ config: YunoConfig(
72
+ cardFlow: cardFlow,
73
+ saveCardEnabled: saveCardEnabled,
74
+ keepLoader: keepLoader
75
+ )
76
+ )
77
+
78
+ self.isInitialized = true
79
+ resolver(nil)
80
+ } catch {
81
+ rejecter("INITIALIZATION_ERROR", "Failed to initialize Yuno SDK: \(error.localizedDescription)", error)
82
+ }
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Start enrollment payment flow.
88
+ */
89
+ @objc
90
+ func enrollmentPayment(
91
+ _ arguments: NSDictionary,
92
+ resolver: @escaping RCTPromiseResolveBlock,
93
+ rejecter: @escaping RCTPromiseRejectBlock
94
+ ) {
95
+ guard isInitialized else {
96
+ rejecter("NOT_INITIALIZED", "Yuno SDK is not initialized", nil)
97
+ return
98
+ }
99
+
100
+ DispatchQueue.main.async { [weak self] in
101
+ guard let self = self else { return }
102
+
103
+ do {
104
+ guard let customerSession = arguments["customerSession"] as? String, !customerSession.isEmpty else {
105
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "customerSession is required"])
106
+ }
107
+
108
+ let showPaymentStatus = arguments["showPaymentStatus"] as? Bool ?? true
109
+
110
+ var countryCode = arguments["countryCode"] as? String
111
+ if countryCode == nil || countryCode!.isEmpty {
112
+ countryCode = self.currentCountryCode
113
+ }
114
+
115
+ guard let safeCountryCode = countryCode, !safeCountryCode.isEmpty else {
116
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "countryCode is required"])
117
+ }
118
+
119
+ self.customerSession = customerSession
120
+ self.currentCountryCode = safeCountryCode
121
+
122
+ Yuno.enrollPayment(with: self, showPaymentStatus: showPaymentStatus)
123
+
124
+ resolver(nil)
125
+ } catch {
126
+ rejecter("ENROLLMENT_ERROR", "Failed to start enrollment: \(error.localizedDescription)", error)
127
+ }
128
+ }
129
+ }
130
+
131
+ /**
132
+ * Start payment lite flow.
133
+ */
134
+ @objc
135
+ func startPaymentLite(
136
+ _ arguments: NSDictionary,
137
+ countryCode: String,
138
+ resolver: @escaping RCTPromiseResolveBlock,
139
+ rejecter: @escaping RCTPromiseRejectBlock
140
+ ) {
141
+ guard isInitialized else {
142
+ rejecter("NOT_INITIALIZED", "Yuno SDK is not initialized", nil)
143
+ return
144
+ }
145
+
146
+ DispatchQueue.main.async { [weak self] in
147
+ guard let self = self else { return }
148
+
149
+ do {
150
+ guard let checkoutSession = arguments["checkoutSession"] as? String, !checkoutSession.isEmpty else {
151
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "checkoutSession is required"])
152
+ }
153
+
154
+ guard let methodSelected = arguments["methodSelected"] as? NSDictionary else {
155
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "methodSelected is required"])
156
+ }
157
+
158
+ guard let vaultedToken = methodSelected["vaultedToken"] as? String, !vaultedToken.isEmpty else {
159
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "vaultedToken is required"])
160
+ }
161
+
162
+ guard let paymentMethodType = methodSelected["paymentMethodType"] as? String, !paymentMethodType.isEmpty else {
163
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "paymentMethodType is required"])
164
+ }
165
+
166
+ let showPaymentStatus = arguments["showPaymentStatus"] as? Bool ?? true
167
+
168
+ self.checkoutSession = checkoutSession
169
+ self.currentCountryCode = countryCode
170
+
171
+ let paymentSelected = Yuno.PaymentSelected(
172
+ paymentMethodType: paymentMethodType,
173
+ vaultedToken: vaultedToken
174
+ )
175
+
176
+ Yuno.startPaymentLite(
177
+ with: self,
178
+ paymentSelected: paymentSelected,
179
+ showPaymentStatus: showPaymentStatus
180
+ )
181
+
182
+ resolver(nil)
183
+ } catch {
184
+ rejecter("PAYMENT_LITE_ERROR", "Failed to start payment lite: \(error.localizedDescription)", error)
185
+ }
186
+ }
187
+ }
188
+
189
+ /**
190
+ * Start full payment flow.
191
+ */
192
+ @objc
193
+ func startPayment(
194
+ _ showPaymentStatus: Bool,
195
+ resolver: @escaping RCTPromiseResolveBlock,
196
+ rejecter: @escaping RCTPromiseRejectBlock
197
+ ) {
198
+ guard isInitialized else {
199
+ rejecter("NOT_INITIALIZED", "Yuno SDK is not initialized", nil)
200
+ return
201
+ }
202
+
203
+ DispatchQueue.main.async {
204
+ do {
205
+ Yuno.startPayment(showPaymentStatus: showPaymentStatus)
206
+ resolver(nil)
207
+ } catch {
208
+ rejecter("PAYMENT_ERROR", "Failed to start payment: \(error.localizedDescription)", error)
209
+ }
210
+ }
211
+ }
212
+
213
+ /**
214
+ * Continue payment flow.
215
+ */
216
+ @objc
217
+ func continuePayment(
218
+ _ showPaymentStatus: Bool,
219
+ resolver: @escaping RCTPromiseResolveBlock,
220
+ rejecter: @escaping RCTPromiseRejectBlock
221
+ ) {
222
+ guard isInitialized else {
223
+ rejecter("NOT_INITIALIZED", "Yuno SDK is not initialized", nil)
224
+ return
225
+ }
226
+
227
+ DispatchQueue.main.async {
228
+ do {
229
+ Yuno.continuePayment()
230
+ resolver(nil)
231
+ } catch {
232
+ rejecter("CONTINUE_PAYMENT_ERROR", "Failed to continue payment: \(error.localizedDescription)", error)
233
+ }
234
+ }
235
+ }
236
+
237
+ /**
238
+ * Start seamless payment lite flow.
239
+ */
240
+ @objc
241
+ func startPaymentSeamlessLite(
242
+ _ arguments: NSDictionary,
243
+ language: String,
244
+ resolver: @escaping RCTPromiseResolveBlock,
245
+ rejecter: @escaping RCTPromiseRejectBlock
246
+ ) {
247
+ guard isInitialized else {
248
+ rejecter("NOT_INITIALIZED", "Yuno SDK is not initialized", nil)
249
+ return
250
+ }
251
+
252
+ DispatchQueue.main.async { [weak self] in
253
+ guard let self = self else { return }
254
+
255
+ do {
256
+ guard let checkoutSession = arguments["checkoutSession"] as? String, !checkoutSession.isEmpty else {
257
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "checkoutSession is required"])
258
+ }
259
+
260
+ guard let methodSelected = arguments["methodSelected"] as? NSDictionary else {
261
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "methodSelected is required"])
262
+ }
263
+
264
+ guard let vaultedToken = methodSelected["vaultedToken"] as? String, !vaultedToken.isEmpty else {
265
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "vaultedToken is required"])
266
+ }
267
+
268
+ guard let paymentMethodType = methodSelected["paymentMethodType"] as? String, !paymentMethodType.isEmpty else {
269
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "paymentMethodType is required"])
270
+ }
271
+
272
+ let showPaymentStatus = arguments["showPaymentStatus"] as? Bool ?? true
273
+
274
+ var countryCode = arguments["countryCode"] as? String
275
+ if countryCode == nil || countryCode!.isEmpty {
276
+ countryCode = self.currentCountryCode
277
+ }
278
+
279
+ guard let safeCountryCode = countryCode, !safeCountryCode.isEmpty else {
280
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "countryCode is required"])
281
+ }
282
+
283
+ self.checkoutSession = checkoutSession
284
+ self.currentCountryCode = safeCountryCode
285
+
286
+ let paymentSelected = Yuno.PaymentSelected(
287
+ paymentMethodType: paymentMethodType,
288
+ vaultedToken: vaultedToken
289
+ )
290
+
291
+ Yuno.startPaymentLite(
292
+ with: self,
293
+ paymentSelected: paymentSelected,
294
+ showPaymentStatus: showPaymentStatus
295
+ )
296
+
297
+ // Return initial processing status
298
+ resolver("PROCESSING")
299
+ } catch {
300
+ rejecter("SEAMLESS_ERROR", "Failed to start seamless payment: \(error.localizedDescription)", error)
301
+ }
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Hide loader.
307
+ */
308
+ @objc
309
+ func hideLoader(
310
+ _ resolver: @escaping RCTPromiseResolveBlock,
311
+ rejecter: @escaping RCTPromiseRejectBlock
312
+ ) {
313
+ DispatchQueue.main.async {
314
+ do {
315
+ Yuno.hideLoader()
316
+ resolver(nil)
317
+ } catch {
318
+ rejecter("HIDE_LOADER_ERROR", "Failed to hide loader: \(error.localizedDescription)", error)
319
+ }
320
+ }
321
+ }
322
+
323
+ /**
324
+ * Receive deeplink for payment resumption.
325
+ */
326
+ @objc
327
+ func receiveDeeplink(
328
+ _ url: String,
329
+ resolver: @escaping RCTPromiseResolveBlock,
330
+ rejecter: @escaping RCTPromiseRejectBlock
331
+ ) {
332
+ DispatchQueue.main.async {
333
+ do {
334
+ guard !url.isEmpty, let deeplink = URL(string: url) else {
335
+ throw NSError(domain: "YunoSdk", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"])
336
+ }
337
+
338
+ Yuno.receiveDeeplink(deeplink)
339
+ resolver(nil)
340
+ } catch {
341
+ rejecter("DEEPLINK_ERROR", "Failed to process deeplink: \(error.localizedDescription)", error)
342
+ }
343
+ }
344
+ }
345
+
346
+ // MARK: - Helper Methods
347
+
348
+ private func mapToCardFlow(_ cardFlow: String) -> YunoCardFlow {
349
+ switch cardFlow {
350
+ case "STEP_BY_STEP":
351
+ return .multiStep
352
+ default:
353
+ return .oneStep
354
+ }
355
+ }
356
+
357
+ private func mapStatusToString(_ status: YunoPaymentStatus) -> String {
358
+ switch status {
359
+ case .rejected:
360
+ return "REJECTED"
361
+ case .succeeded:
362
+ return "SUCCEEDED"
363
+ case .failed:
364
+ return "FAILED"
365
+ case .processing:
366
+ return "PROCESSING"
367
+ case .internalError:
368
+ return "INTERNAL_ERROR"
369
+ case .cancelledByUser:
370
+ return "CANCELLED_BY_USER"
371
+ @unknown default:
372
+ return "INTERNAL_ERROR"
373
+ }
374
+ }
375
+
376
+ // MARK: - Event Emitters
377
+
378
+ private func sendPaymentStatusEvent(status: YunoPaymentStatus, token: String? = nil) {
379
+ var params: [String: Any] = ["status": mapStatusToString(status)]
380
+ if let token = token {
381
+ params["token"] = token
382
+ }
383
+ sendEvent(withName: "YunoPaymentStatus", body: params)
384
+ }
385
+
386
+ private func sendEnrollmentStatusEvent(status: YunoPaymentStatus) {
387
+ let params: [String: Any] = ["status": mapStatusToString(status)]
388
+ sendEvent(withName: "YunoEnrollmentStatus", body: params)
389
+ }
390
+
391
+ private func sendOneTimeTokenEvent(token: String) {
392
+ sendEvent(withName: "YunoOneTimeToken", body: token)
393
+ }
394
+ }
395
+
396
+ // MARK: - YunoPaymentDelegate Extension
397
+ extension YunoSdk: YunoPaymentDelegate {
398
+ func yunoCreatePayment(with token: String) {
399
+ sendOneTimeTokenEvent(token: token)
400
+ }
401
+
402
+ func yunoPaymentResult(_ result: Yuno.Result) {
403
+ sendPaymentStatusEvent(status: mapResultToStatus(result))
404
+ }
405
+
406
+ var countryCode: String {
407
+ return currentCountryCode ?? ""
408
+ }
409
+
410
+ var checkoutSession: String {
411
+ return self.checkoutSession
412
+ }
413
+
414
+ private func mapResultToStatus(_ result: Yuno.Result) -> YunoPaymentStatus {
415
+ switch result {
416
+ case .succeeded:
417
+ return .succeeded
418
+ case .failed:
419
+ return .failed
420
+ case .rejected:
421
+ return .rejected
422
+ case .processing:
423
+ return .processing
424
+ case .cancelledByUser:
425
+ return .cancelledByUser
426
+ @unknown default:
427
+ return .internalError
428
+ }
429
+ }
430
+ }
431
+
432
+ // MARK: - YunoEnrollmentDelegate Extension
433
+ extension YunoSdk: YunoEnrollmentDelegate {
434
+ func yunoEnrollmentResult(_ result: Yuno.Result) {
435
+ sendEnrollmentStatusEvent(status: mapResultToStatus(result))
436
+ }
437
+
438
+ var customerSession: String {
439
+ return self.customerSession
440
+ }
441
+ }
442
+