react-native-hyperswitch-dev-sdk 0.4.2 → 0.4.4
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/HyperswitchSdkReactNative.podspec +4 -0
- package/android/build.gradle +0 -6
- package/android/hyperswitch_autolinking.gradle +1 -1
- package/ios/Modules/ReactNative/HyperModule.h +25 -0
- package/ios/Modules/ReactNative/HyperModule.mm +169 -0
- package/ios/Modules/ReactNative/HyperswitchModule.swift +223 -165
- package/ios/Modules/ReactNative/NativeHyperswitchModule.mm +17 -12
- package/ios/Modules/ReactNative/NativeHyperswitchModuleImpl.swift +18 -7
- package/ios/Modules/ReactNative/NativePaymentElementModule.mm +122 -122
- package/ios/Views/Fabric/NativePaymentElementView.mm +8 -0
- package/ios/Views/Native/NativePaymentWidget.swift +26 -22
- package/ios/hyperswitchSDK/Core/HyperCVCWidget/CVCWidget.swift +3 -2
- package/ios/hyperswitchSDK/Core/HyperPaymentCardTextField/PaymentHandler.swift +1 -1
- package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheetView+UIKit.swift +79 -13
- package/ios/hyperswitchSDK/Core/HyperPaymentSheet/PaymentSheetView.swift +2 -2
- package/ios/hyperswitchSDK/Core/HyperPaymentWidget/PaymentWidget.swift +5 -4
- package/ios/hyperswitchSDK/Core/HyperSession/PaymentSession+UIKit.swift +14 -0
- package/ios/hyperswitchSDK/Core/NativeModule/{HyperModule.swift → HyperModuleImpl.swift} +156 -113
- package/ios/hyperswitchSDK/Core/NativeModule/RNHeadlessManager.swift +58 -22
- package/ios/hyperswitchSDK/Core/NativeModule/RNViewManager.swift +84 -29
- package/ios/hyperswitchSDK/Core/NativeModule/hyper-Bridging-Header.h +2 -0
- package/ios/hyperswitchSDK/Public/RNBridgeFactory.h +28 -0
- package/ios/hyperswitchSDK/Public/RNBridgeFactory.mm +167 -0
- package/ios/hyperswitchSDK/Shared/PaymentSheet.swift +1 -1
- package/lib/commonjs/index.bundle.js +1 -1
- package/lib/commonjs/index.bundle.js.map +1 -1
- package/lib/module/index.bundle.js +1 -1
- package/lib/module/index.bundle.js.map +1 -1
- package/package.json +6 -2
- package/src/context/PaymentSession.ts +2 -0
- package/src/specs/NativeHyperswitchModule.ts +2 -2
- package/ios/Modules/ReactNative/HyperswitchSdkReactNative.h +0 -5
- package/ios/Modules/ReactNative/HyperswitchSdkReactNative.mm +0 -121
- package/ios/hyperswitchSDK/Core/NativeModule/HyperModule.m +0 -31
|
@@ -119,9 +119,18 @@ public class NativeHyperswitchModuleImpl: NSObject {
|
|
|
119
119
|
])
|
|
120
120
|
return
|
|
121
121
|
}
|
|
122
|
+
|
|
123
|
+
// The SDK's getRootViewWithParams wraps the whole `props` dictionary
|
|
124
|
+
// under the `configuration` key, so we must pass the contents that
|
|
125
|
+
// belong inside `configuration`: the merchant-supplied configuration
|
|
126
|
+
// plus the session/hyperswitch metadata.
|
|
127
|
+
var sheetProps = params["configuration"] as? [String: Any] ?? [:]
|
|
128
|
+
sheetProps["hyperswitchConfig"] = params["hyperswitchConfig"]
|
|
129
|
+
sheetProps["paymentSessionConfig"] = params["paymentSessionConfig"]
|
|
130
|
+
|
|
122
131
|
session.presentPaymentSheetWithParams(
|
|
123
132
|
viewController: vc,
|
|
124
|
-
params:
|
|
133
|
+
params: sheetProps,
|
|
125
134
|
completion: { result in
|
|
126
135
|
switch result {
|
|
127
136
|
case .completed(let data):
|
|
@@ -264,11 +273,12 @@ public class NativeHyperswitchModuleImpl: NSObject {
|
|
|
264
273
|
}
|
|
265
274
|
}
|
|
266
275
|
|
|
267
|
-
// MARK: - confirmWithCustomerLastUsedPaymentMethod
|
|
268
|
-
// Android:
|
|
276
|
+
// MARK: - confirmWithCustomerLastUsedPaymentMethod
|
|
277
|
+
// JS / Android: confirmWithCustomerLastUsedPaymentMethod(reactTag: Double, promise: Promise?)
|
|
269
278
|
|
|
270
|
-
@objc(
|
|
279
|
+
@objc(confirmWithCustomerLastUsedPaymentMethod:resolve:reject:)
|
|
271
280
|
public func confirmWithCustomerLastUsedPaymentMethod(
|
|
281
|
+
reactTag: Double,
|
|
272
282
|
resolve: @escaping RCTPromiseResolveBlock,
|
|
273
283
|
reject: @escaping RCTPromiseRejectBlock
|
|
274
284
|
) {
|
|
@@ -276,11 +286,12 @@ public class NativeHyperswitchModuleImpl: NSObject {
|
|
|
276
286
|
resolve("{\"status\":\"failed\",\"message\":\"Not yet implemented\"}")
|
|
277
287
|
}
|
|
278
288
|
|
|
279
|
-
// MARK: - confirmWithCustomerDefaultPaymentMethod
|
|
280
|
-
// Android:
|
|
289
|
+
// MARK: - confirmWithCustomerDefaultPaymentMethod
|
|
290
|
+
// JS / Android: confirmWithCustomerDefaultPaymentMethod(reactTag: Double, promise: Promise?)
|
|
281
291
|
|
|
282
|
-
@objc(
|
|
292
|
+
@objc(confirmWithCustomerDefaultPaymentMethod:resolve:reject:)
|
|
283
293
|
public func confirmWithCustomerDefaultPaymentMethod(
|
|
294
|
+
reactTag: Double,
|
|
284
295
|
resolve: @escaping RCTPromiseResolveBlock,
|
|
285
296
|
reject: @escaping RCTPromiseRejectBlock
|
|
286
297
|
) {
|
|
@@ -1,129 +1,129 @@
|
|
|
1
|
+
////
|
|
2
|
+
//// NativePaymentElementModule.mm
|
|
3
|
+
////
|
|
4
|
+
//// TurboModule (New Architecture) for NativePaymentElementModule.
|
|
5
|
+
//// Module name: "NativePaymentElementModule"
|
|
6
|
+
////
|
|
7
|
+
//// Matches Android's NativePaymentWidgetModule (NativePaymentElementModuleSpec):
|
|
8
|
+
//// confirmPayment(reactTag, callback)
|
|
9
|
+
//// updateIntentInitForWidget(reactTag, callback)
|
|
10
|
+
//// updateIntentCompleteForWidget(reactTag, sdkAuthorization, callback)
|
|
11
|
+
////
|
|
12
|
+
//// Old arch (bridge): the view-manager commands (same methods) live on NativePaymentWidget
|
|
13
|
+
//// (RCTViewManager) which is accessible via NativeModules.NativePaymentWidget.
|
|
14
|
+
//// NativeHyperswitchSdk.ts still uses that path, so both old and new arch work.
|
|
15
|
+
////
|
|
16
|
+
//// New arch (TurboModule): this module is registered as "NativePaymentElementModule" and is
|
|
17
|
+
//// the spec-compliant TurboModule counterpart. It delegates to the
|
|
18
|
+
//// inner NativePaymentWidgetView found via NativePaymentWidgetViewRegistry.
|
|
19
|
+
////
|
|
1
20
|
//
|
|
2
|
-
|
|
21
|
+
//#import <React/RCTBridgeModule.h>
|
|
22
|
+
//#import <React/RCTUIManager.h>
|
|
3
23
|
//
|
|
4
|
-
|
|
5
|
-
|
|
24
|
+
//#if __has_include("HyperswitchSdkReactNative-Swift.h")
|
|
25
|
+
//#import "HyperswitchSdkReactNative-Swift.h"
|
|
26
|
+
//#else
|
|
27
|
+
//#import <HyperswitchSdkReactNative/HyperswitchSdkReactNative-Swift.h>
|
|
28
|
+
//#endif
|
|
6
29
|
//
|
|
7
|
-
|
|
8
|
-
// confirmPayment(reactTag, callback)
|
|
9
|
-
// updateIntentInitForWidget(reactTag, callback)
|
|
10
|
-
// updateIntentCompleteForWidget(reactTag, sdkAuthorization, callback)
|
|
30
|
+
//#import "NativePaymentWidgetViewRegistry.h"
|
|
11
31
|
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
32
|
+
//#ifdef RCT_NEW_ARCH_ENABLED
|
|
33
|
+
//#import <HyperswitchSdkReactNativeSpec/HyperswitchSdkReactNativeSpec.h>
|
|
34
|
+
//#endif
|
|
15
35
|
//
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
36
|
+
//// ─────────────────────────────────────────────────────────────────────────────
|
|
37
|
+
//// Private helper: find NativePaymentWidgetView by React tag.
|
|
38
|
+
////
|
|
39
|
+
//// Checks NativePaymentWidgetViewRegistry first (covers both old-arch direct
|
|
40
|
+
//// NativePaymentWidgetView instances registered there AND the inner widget views
|
|
41
|
+
//// registered by NativePaymentElementView for Fabric).
|
|
42
|
+
//// ─────────────────────────────────────────────────────────────────────────────
|
|
43
|
+
//static NativePaymentWidget * _Nullable widgetViewForTag(NSNumber *tag)
|
|
44
|
+
//{
|
|
45
|
+
// UIView *v = [[NativePaymentWidgetViewRegistry shared] viewForTag:tag];
|
|
46
|
+
// return [v isKindOfClass:[NativePaymentWidget class]]
|
|
47
|
+
// ? (NativePaymentWidget *)v
|
|
48
|
+
// : nil;
|
|
49
|
+
//}
|
|
19
50
|
//
|
|
20
|
-
|
|
21
|
-
#import <React/RCTBridgeModule.h>
|
|
22
|
-
#import <React/RCTUIManager.h>
|
|
23
|
-
|
|
24
|
-
#if __has_include("HyperswitchSdkReactNative-Swift.h")
|
|
25
|
-
#import "HyperswitchSdkReactNative-Swift.h"
|
|
26
|
-
#else
|
|
27
|
-
#import <HyperswitchSdkReactNative/HyperswitchSdkReactNative-Swift.h>
|
|
28
|
-
#endif
|
|
29
|
-
|
|
30
|
-
#import "NativePaymentWidgetViewRegistry.h"
|
|
31
|
-
|
|
32
|
-
#ifdef RCT_NEW_ARCH_ENABLED
|
|
33
|
-
#import <HyperswitchSdkReactNativeSpec/HyperswitchSdkReactNativeSpec.h>
|
|
34
|
-
#endif
|
|
35
|
-
|
|
36
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
37
|
-
// Private helper: find NativePaymentWidgetView by React tag.
|
|
51
|
+
//// ─────────────────────────────────────────────────────────────────────────────
|
|
38
52
|
//
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
// ── TurboModule wiring (New Architecture) ─────────────────────────────────────
|
|
117
|
-
// NativePaymentElementModuleSpecJSI is generated by iOS codegen from
|
|
118
|
-
// NativePaymentElementModule.ts → HyperswitchSdkReactNativeSpec pod.
|
|
119
|
-
#ifdef RCT_NEW_ARCH_ENABLED
|
|
120
|
-
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
121
|
-
(const facebook::react::ObjCTurboModule::InitParams &)params
|
|
122
|
-
{
|
|
123
|
-
return std::make_shared<facebook::react::NativePaymentElementModuleSpecJSI>(params);
|
|
124
|
-
}
|
|
125
|
-
#endif
|
|
126
|
-
|
|
127
|
-
+ (BOOL)requiresMainQueueSetup { return NO; }
|
|
128
|
-
|
|
129
|
-
@end
|
|
53
|
+
//// Use RCTBridgeModule for both arches; getTurboModule: below handles new arch wiring.
|
|
54
|
+
//@interface NativePaymentElementModule : NSObject <RCTBridgeModule>
|
|
55
|
+
//@end
|
|
56
|
+
//
|
|
57
|
+
//@implementation NativePaymentElementModule
|
|
58
|
+
//
|
|
59
|
+
//RCT_EXPORT_MODULE(NativePaymentElementModule)
|
|
60
|
+
//
|
|
61
|
+
//// ── confirmPayment ────────────────────────────────────────────────────────────
|
|
62
|
+
//// JS / Android: confirmPayment(reactTag: number, callback)
|
|
63
|
+
//// Mirrors Android NativePaymentWidgetModule.confirmPayment (mostly a stub there).
|
|
64
|
+
//// On iOS we do the real work via the shared registry.
|
|
65
|
+
//RCT_EXPORT_METHOD(confirmPayment:(double)reactTag
|
|
66
|
+
// callback:(RCTResponseSenderBlock)callback)
|
|
67
|
+
//{
|
|
68
|
+
// NSNumber *tag = @((NSInteger)reactTag);
|
|
69
|
+
//// dispatch_async(dispatch_get_main_queue(), ^{
|
|
70
|
+
//// NativePaymentWidget *view = widgetViewForTag(tag);
|
|
71
|
+
//// if (view) {
|
|
72
|
+
//// [view confirmPayment:callback];
|
|
73
|
+
//// } else {
|
|
74
|
+
//// callback(@[@{@"status": @"failed",
|
|
75
|
+
//// @"code": @"WIDGET_NOT_FOUND",
|
|
76
|
+
//// @"message": [NSString stringWithFormat:@"Widget not found for tag %@", tag]}]);
|
|
77
|
+
//// }
|
|
78
|
+
//// });
|
|
79
|
+
//}
|
|
80
|
+
//
|
|
81
|
+
//// ── updateIntentInitForWidget ─────────────────────────────────────────────────
|
|
82
|
+
//RCT_EXPORT_METHOD(updateIntentInitForWidget:(double)reactTag
|
|
83
|
+
// callback:(RCTResponseSenderBlock)callback)
|
|
84
|
+
//{
|
|
85
|
+
// NSNumber *tag = @((NSInteger)reactTag);
|
|
86
|
+
//// dispatch_async(dispatch_get_main_queue(), ^{
|
|
87
|
+
//// NativePaymentWidgetView *view = widgetViewForTag(tag);
|
|
88
|
+
//// if (view) {
|
|
89
|
+
//// [view updateIntentInit:callback];
|
|
90
|
+
//// } else {
|
|
91
|
+
//// callback(@[@{@"status": @"failed",
|
|
92
|
+
//// @"code": @"WIDGET_NOT_FOUND",
|
|
93
|
+
//// @"message": [NSString stringWithFormat:@"Widget not found for tag %@", tag]}]);
|
|
94
|
+
//// }
|
|
95
|
+
//// });
|
|
96
|
+
//}
|
|
97
|
+
//
|
|
98
|
+
//// ── updateIntentCompleteForWidget ─────────────────────────────────────────────
|
|
99
|
+
//RCT_EXPORT_METHOD(updateIntentCompleteForWidget:(double)reactTag
|
|
100
|
+
// sdkAuthorization:(NSString *)sdkAuthorization
|
|
101
|
+
// callback:(RCTResponseSenderBlock)callback)
|
|
102
|
+
//{
|
|
103
|
+
//// NSNumber *tag = @((NSInteger)reactTag);
|
|
104
|
+
//// dispatch_async(dispatch_get_main_queue(), ^{
|
|
105
|
+
//// NativePaymentWidgetView *view = widgetViewForTag(tag);
|
|
106
|
+
//// if (view) {
|
|
107
|
+
//// [view updateIntentCompleteWithSdkAuthorization:sdkAuthorization resolve:callback];
|
|
108
|
+
//// } else {
|
|
109
|
+
//// callback(@[@{@"status": @"failed",
|
|
110
|
+
//// @"code": @"WIDGET_NOT_FOUND",
|
|
111
|
+
//// @"message": [NSString stringWithFormat:@"Widget not found for tag %@", tag]}]);
|
|
112
|
+
//// }
|
|
113
|
+
//// });
|
|
114
|
+
//}
|
|
115
|
+
//
|
|
116
|
+
//// ── TurboModule wiring (New Architecture) ─────────────────────────────────────
|
|
117
|
+
//// NativePaymentElementModuleSpecJSI is generated by iOS codegen from
|
|
118
|
+
//// NativePaymentElementModule.ts → HyperswitchSdkReactNativeSpec pod.
|
|
119
|
+
//#ifdef RCT_NEW_ARCH_ENABLED
|
|
120
|
+
//- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
121
|
+
// (const facebook::react::ObjCTurboModule::InitParams &)params
|
|
122
|
+
//{
|
|
123
|
+
// return std::make_shared<facebook::react::NativePaymentElementModuleSpecJSI>(params);
|
|
124
|
+
//}
|
|
125
|
+
//#endif
|
|
126
|
+
//
|
|
127
|
+
//+ (BOOL)requiresMainQueueSetup { return NO; }
|
|
128
|
+
//
|
|
129
|
+
//@end
|
|
@@ -22,6 +22,14 @@
|
|
|
22
22
|
#import "NativePaymentElementView.h"
|
|
23
23
|
#import "NativePaymentWidgetViewRegistry.h"
|
|
24
24
|
|
|
25
|
+
// Defines RCTPromiseResolveBlock/RCTPromiseRejectBlock and RCTDirectEventBlock,
|
|
26
|
+
// referenced by the HyperswitchModule / NativePaymentWidgetView interfaces
|
|
27
|
+
// declared in the generated Swift header below.
|
|
28
|
+
#import <React/RCTBridgeModule.h>
|
|
29
|
+
#import <React/RCTComponent.h>
|
|
30
|
+
|
|
31
|
+
#include <folly/json.h>
|
|
32
|
+
|
|
25
33
|
#import <react/renderer/components/HyperswitchSdkReactNativeSpec/ComponentDescriptors.h>
|
|
26
34
|
#import <react/renderer/components/HyperswitchSdkReactNativeSpec/EventEmitters.h>
|
|
27
35
|
#import <react/renderer/components/HyperswitchSdkReactNativeSpec/Props.h>
|
|
@@ -42,7 +42,7 @@ internal class NativePaymentWidget: RCTViewManager {
|
|
|
42
42
|
}
|
|
43
43
|
// New-arch (Fabric) path: the Fabric NativePaymentElementView registered
|
|
44
44
|
// the inner NativePaymentWidgetView in the shared registry by the same tag.
|
|
45
|
-
// if let view = NativePaymentWidgetViewRegistry.shared.view(forTag: reactTag) as? NativePaymentWidgetView {
|
|
45
|
+
// if let view = NativePaymentWidgetViewRegistry.shared().view(forTag: reactTag) as? NativePaymentWidgetView {
|
|
46
46
|
// view.confirmPayment(rnCallback)
|
|
47
47
|
// return
|
|
48
48
|
// }
|
|
@@ -56,7 +56,7 @@ internal class NativePaymentWidget: RCTViewManager {
|
|
|
56
56
|
view.updateIntentInit(rnCallback)
|
|
57
57
|
return
|
|
58
58
|
}
|
|
59
|
-
// if let view = NativePaymentWidgetViewRegistry.shared.view(forTag: rootTag) as? NativePaymentWidgetView {
|
|
59
|
+
// if let view = NativePaymentWidgetViewRegistry.shared().view(forTag: rootTag) as? NativePaymentWidgetView {
|
|
60
60
|
// view.updateIntentInit(rnCallback)
|
|
61
61
|
// return
|
|
62
62
|
// }
|
|
@@ -74,7 +74,7 @@ internal class NativePaymentWidget: RCTViewManager {
|
|
|
74
74
|
view.updateIntentComplete(sdkAuthorization: sdkAuthorization, resolve: rnCallback)
|
|
75
75
|
return
|
|
76
76
|
}
|
|
77
|
-
// if let view = NativePaymentWidgetViewRegistry.shared.view(forTag: rootTag) as? NativePaymentWidgetView {
|
|
77
|
+
// if let view = NativePaymentWidgetViewRegistry.shared().view(forTag: rootTag) as? NativePaymentWidgetView {
|
|
78
78
|
// view.updateIntentComplete(sdkAuthorization: sdkAuthorization, resolve: rnCallback)
|
|
79
79
|
// return
|
|
80
80
|
// }
|
|
@@ -93,7 +93,7 @@ internal class NativePaymentWidget: RCTViewManager {
|
|
|
93
93
|
view.confirmCVCPayment(paymentToken: paymentToken, paymentMethodId: paymentMethodId, resolve: rnCallback)
|
|
94
94
|
return
|
|
95
95
|
}
|
|
96
|
-
// if let view = NativePaymentWidgetViewRegistry.shared.view(forTag: reactTag) as? NativePaymentWidgetView {
|
|
96
|
+
// if let view = NativePaymentWidgetViewRegistry.shared().view(forTag: reactTag) as? NativePaymentWidgetView {
|
|
97
97
|
// view.confirmCVCPayment(paymentToken: paymentToken, paymentMethodId: paymentMethodId, resolve: rnCallback)
|
|
98
98
|
// return
|
|
99
99
|
// }
|
|
@@ -102,20 +102,24 @@ internal class NativePaymentWidget: RCTViewManager {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
// @objc exposes this class
|
|
106
|
-
//
|
|
105
|
+
// public + @objc exposes this class (and the members below marked @objc) in the
|
|
106
|
+
// generated HyperswitchSdkReactNative-Swift.h header so the Objective-C++ Fabric
|
|
107
|
+
// component (NativePaymentElementView.mm) and TurboModule (NativePaymentElementModule.mm)
|
|
108
|
+
// can instantiate it, type-check it, and call its commands. Framework targets only emit
|
|
109
|
+
// public declarations into that header, even for callers in the same module.
|
|
107
110
|
@objc(NativePaymentWidgetView)
|
|
108
|
-
|
|
111
|
+
public class NativePaymentWidgetView: UIView {
|
|
109
112
|
|
|
110
113
|
private var paymentWidget: PaymentWidget?
|
|
111
114
|
private var cvcWidget: CVCWidget?
|
|
112
115
|
internal var cvcWidgetRef: CVCWidget? { cvcWidget }
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
@objc var
|
|
116
|
-
@objc var
|
|
117
|
-
@objc var
|
|
118
|
-
@objc var
|
|
116
|
+
// Public (not just internal) so these show up in the generated Objective-C
|
|
117
|
+
// header for the Fabric wrapper (NativePaymentElementView.mm) to set via the ObjC bridge.
|
|
118
|
+
@objc public var widgetType: String?
|
|
119
|
+
@objc public var sdkAuthorization: String?
|
|
120
|
+
@objc public var options: [String: Any]?
|
|
121
|
+
@objc public var onPaymentEvent: RCTDirectEventBlock?
|
|
122
|
+
@objc public var onPaymentResult: RCTDirectEventBlock?
|
|
119
123
|
private var responseSenderCallback: RCTResponseSenderBlock?
|
|
120
124
|
private var appliedConfigKey: String?
|
|
121
125
|
|
|
@@ -252,7 +256,7 @@ internal class NativePaymentWidgetView: UIView {
|
|
|
252
256
|
}
|
|
253
257
|
}
|
|
254
258
|
|
|
255
|
-
@objc func didSetProps() {
|
|
259
|
+
@objc public func didSetProps() {
|
|
256
260
|
guard isSupportedWidgetType(), let sdkAuthorization = effectiveSdkAuthorization() else { return }
|
|
257
261
|
|
|
258
262
|
let configKey = [widgetType ?? "", effectivePublishableKey() ?? "", effectiveProfileId() ?? "", sdkAuthorization].joined(separator: ":")
|
|
@@ -319,11 +323,11 @@ internal class NativePaymentWidgetView: UIView {
|
|
|
319
323
|
}
|
|
320
324
|
}
|
|
321
325
|
|
|
322
|
-
override func didSetProps(_ changedProps: [String]) {
|
|
326
|
+
public override func didSetProps(_ changedProps: [String]) {
|
|
323
327
|
self.didSetProps()
|
|
324
328
|
}
|
|
325
329
|
|
|
326
|
-
override init(frame: CGRect) {
|
|
330
|
+
public override init(frame: CGRect) {
|
|
327
331
|
super.init(frame: frame)
|
|
328
332
|
}
|
|
329
333
|
|
|
@@ -331,13 +335,13 @@ internal class NativePaymentWidgetView: UIView {
|
|
|
331
335
|
fatalError("init(coder:) has not been implemented")
|
|
332
336
|
}
|
|
333
337
|
|
|
334
|
-
|
|
338
|
+
public override func layoutSubviews() {
|
|
335
339
|
super.layoutSubviews()
|
|
336
340
|
paymentWidget?.frame = bounds
|
|
337
341
|
cvcWidget?.frame = bounds
|
|
338
342
|
}
|
|
339
343
|
|
|
340
|
-
|
|
344
|
+
@objc public func confirmPayment(_ rnCallback: @escaping RCTResponseSenderBlock) {
|
|
341
345
|
// avoiding duplicate confirm calls (confirmPayment triggered multiple times from RN layer)
|
|
342
346
|
if self.responseSenderCallback != nil {
|
|
343
347
|
let response = ["status": "failed", "error": "invalid call"]
|
|
@@ -358,7 +362,7 @@ internal class NativePaymentWidgetView: UIView {
|
|
|
358
362
|
paymentWidget.confirm()
|
|
359
363
|
}
|
|
360
364
|
|
|
361
|
-
|
|
365
|
+
@objc public func updateIntentInit(_ resolve: @escaping RCTResponseSenderBlock) {
|
|
362
366
|
guard let tag = rctRootTag else {
|
|
363
367
|
resolve([["status": "failed", "message": "Widget root tag not found"]])
|
|
364
368
|
return
|
|
@@ -370,7 +374,7 @@ internal class NativePaymentWidgetView: UIView {
|
|
|
370
374
|
}
|
|
371
375
|
|
|
372
376
|
let eventData: [String: Any] = ["rootTag": tag]
|
|
373
|
-
RNViewManager.sharedInstance.bridge
|
|
377
|
+
RNViewManager.sharedInstance.bridge?.enqueueJSCall(
|
|
374
378
|
"RCTDeviceEventEmitter",
|
|
375
379
|
method: "emit",
|
|
376
380
|
args: ["updateIntentInit", eventData],
|
|
@@ -378,7 +382,7 @@ internal class NativePaymentWidgetView: UIView {
|
|
|
378
382
|
)
|
|
379
383
|
}
|
|
380
384
|
|
|
381
|
-
|
|
385
|
+
@objc public func updateIntentComplete(sdkAuthorization: String, resolve: @escaping RCTResponseSenderBlock) {
|
|
382
386
|
guard let tag = rctRootTag else {
|
|
383
387
|
resolve([["status": "failed", "message": "Widget root tag not found"]])
|
|
384
388
|
return
|
|
@@ -393,7 +397,7 @@ internal class NativePaymentWidgetView: UIView {
|
|
|
393
397
|
"rootTag": tag,
|
|
394
398
|
"sdkAuthorization": sdkAuthorization,
|
|
395
399
|
]
|
|
396
|
-
RNViewManager.sharedInstance.bridge
|
|
400
|
+
RNViewManager.sharedInstance.bridge?.enqueueJSCall(
|
|
397
401
|
"RCTDeviceEventEmitter",
|
|
398
402
|
method: "emit",
|
|
399
403
|
args: ["updateIntentComplete", eventData],
|
|
@@ -14,7 +14,7 @@ public class CVCWidget: UIControl {
|
|
|
14
14
|
private var configurationDict: [String: Any]?
|
|
15
15
|
private var widgetReactTag: NSNumber?
|
|
16
16
|
internal var rootReactTag: NSNumber? { widgetReactTag }
|
|
17
|
-
private var rootView:
|
|
17
|
+
private var rootView: UIView?
|
|
18
18
|
private var cvcCallback: ((PaymentResult) -> Void)?
|
|
19
19
|
private var subscribedEventNames: [String]?
|
|
20
20
|
private let hyperswitch: Hyperswitch
|
|
@@ -112,7 +112,7 @@ public class CVCWidget: UIControl {
|
|
|
112
112
|
"paymentToken": paymentToken,
|
|
113
113
|
"paymentMethodId": paymentMethodId as Any,
|
|
114
114
|
]
|
|
115
|
-
|
|
115
|
+
RNViewManager.sharedInstance.bridge?.enqueueJSCall(
|
|
116
116
|
"RCTDeviceEventEmitter",
|
|
117
117
|
method: "emit",
|
|
118
118
|
args: ["triggerWidgetAction", payload],
|
|
@@ -134,3 +134,4 @@ public class CVCWidget: UIControl {
|
|
|
134
134
|
self.paymentEventListener = listener
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
|
+
|
|
@@ -27,7 +27,7 @@ public class PaymentHandler: NSObject {
|
|
|
27
27
|
self.completion = completion
|
|
28
28
|
|
|
29
29
|
RNViewManager.sharedInstance.responseHandler = self
|
|
30
|
-
|
|
30
|
+
HyperModuleImpl.shared.confirm(data: paymentParams.description())
|
|
31
31
|
}
|
|
32
32
|
public typealias PaymentHandlerActionPaymentIntentCompletionBlock = (
|
|
33
33
|
PaymentHandlerActionStatus, PaymentIntent?, NSError?
|
|
@@ -11,13 +11,13 @@ import React
|
|
|
11
11
|
/// Extension on the PaymentSheet class to handle the presentation of the payment sheet view.
|
|
12
12
|
internal extension PaymentSheet {
|
|
13
13
|
|
|
14
|
-
///
|
|
14
|
+
/// Present with a raw-string completion — the JS bundle's exit message is forwarded
|
|
15
|
+
/// unchanged to the caller. Used by the React Native TurboModule path.
|
|
15
16
|
private func presentWithRootView(
|
|
16
17
|
from presentingViewController: UIViewController,
|
|
17
|
-
rootView:
|
|
18
|
-
completion: @escaping (
|
|
18
|
+
rootView: UIView,
|
|
19
|
+
completion: @escaping (String) -> Void
|
|
19
20
|
) {
|
|
20
|
-
|
|
21
21
|
self.completion = completion
|
|
22
22
|
|
|
23
23
|
let paymentSheetViewController = HyperUIViewController()
|
|
@@ -25,25 +25,91 @@ internal extension PaymentSheet {
|
|
|
25
25
|
paymentSheetViewController.modalPresentationStyle = .overFullScreen
|
|
26
26
|
paymentSheetViewController.view = rootView
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
// Register the sheet and VC directly with HyperModuleImpl so that
|
|
29
|
+
// exitPaymentsheet can call the completion without relying on
|
|
30
|
+
// bridge.uiManager.addUIBlock (which doesn't find Fabric-rendered views).
|
|
31
|
+
HyperModuleImpl.shared.registerPaymentSheet(self, vc: paymentSheetViewController)
|
|
32
|
+
|
|
29
33
|
presentingViewController.present(paymentSheetViewController, animated: false)
|
|
30
34
|
}
|
|
31
35
|
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
// MARK: - Public-facing helpers (PaymentResult overloads kept for SwiftUI / native SDK usage)
|
|
37
|
+
|
|
38
|
+
/// Present with a typed `PaymentResult` — the result is serialised to a JSON string
|
|
39
|
+
/// internally so the single `completion: ((String) -> Void)?` property is shared.
|
|
40
|
+
func present(
|
|
41
|
+
from presentingViewController: UIViewController,
|
|
42
|
+
completion: @escaping (PaymentResult) -> Void
|
|
43
|
+
) {
|
|
44
|
+
presentWithRootView(
|
|
45
|
+
from: presentingViewController,
|
|
46
|
+
rootView: getRootView(),
|
|
47
|
+
completion: { raw in completion(PaymentSheet.paymentResult(from: raw)) }
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/// Present with custom props and a typed `PaymentResult` completion.
|
|
52
|
+
func presentWithParams(
|
|
53
|
+
from presentingViewController: UIViewController,
|
|
54
|
+
props: [String: Any],
|
|
55
|
+
completion: @escaping (PaymentResult) -> Void
|
|
56
|
+
) {
|
|
57
|
+
presentWithRootView(
|
|
58
|
+
from: presentingViewController,
|
|
59
|
+
rootView: getRootViewWithParams(props: props),
|
|
60
|
+
completion: { raw in completion(PaymentSheet.paymentResult(from: raw)) }
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// MARK: - Internal raw-string overloads (used by HyperswitchModule / TurboModule path)
|
|
34
65
|
|
|
35
|
-
|
|
36
|
-
|
|
66
|
+
/// Present with default configuration and a raw-string completion.
|
|
67
|
+
func present(
|
|
68
|
+
from presentingViewController: UIViewController,
|
|
69
|
+
rawCompletion: @escaping (String) -> Void
|
|
70
|
+
) {
|
|
71
|
+
presentWithRootView(
|
|
72
|
+
from: presentingViewController,
|
|
73
|
+
rootView: getRootView(),
|
|
74
|
+
completion: rawCompletion
|
|
75
|
+
)
|
|
37
76
|
}
|
|
38
77
|
|
|
39
|
-
///
|
|
78
|
+
/// Present with custom props and a raw-string completion.
|
|
40
79
|
func presentWithParams(
|
|
41
80
|
from presentingViewController: UIViewController,
|
|
42
81
|
props: [String: Any],
|
|
43
|
-
|
|
82
|
+
rawCompletion: @escaping (String) -> Void
|
|
44
83
|
) {
|
|
84
|
+
presentWithRootView(
|
|
85
|
+
from: presentingViewController,
|
|
86
|
+
rootView: getRootViewWithParams(props: props),
|
|
87
|
+
completion: rawCompletion
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// MARK: - Shared result deserialiser
|
|
45
92
|
|
|
46
|
-
|
|
47
|
-
|
|
93
|
+
/// Convert the raw JSON string sent by the JS bundle into a typed `PaymentResult`.
|
|
94
|
+
/// Mirrors the logic in `HyperModuleImpl.paymentResult(from:)`.
|
|
95
|
+
private static func paymentResult(from raw: String) -> PaymentResult {
|
|
96
|
+
guard
|
|
97
|
+
let data = raw.data(using: .utf8),
|
|
98
|
+
let dict = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
99
|
+
let status = dict["status"] as? String
|
|
100
|
+
else {
|
|
101
|
+
return .failed(error: NSError(domain: "UNKNOWN_ERROR", code: 0,
|
|
102
|
+
userInfo: ["message": "An error has occurred."]))
|
|
103
|
+
}
|
|
104
|
+
switch status {
|
|
105
|
+
case "success", "succeeded", "completed":
|
|
106
|
+
return .completed(data: status)
|
|
107
|
+
case "cancelled", "canceled":
|
|
108
|
+
return .canceled(data: status)
|
|
109
|
+
default:
|
|
110
|
+
let code = (dict["code"] as? String).flatMap { $0.isEmpty ? nil : $0 } ?? "UNKNOWN_ERROR"
|
|
111
|
+
let message = dict["message"] as? String ?? "An error has occurred."
|
|
112
|
+
return .failed(error: NSError(domain: code, code: 0, userInfo: ["message": message]))
|
|
113
|
+
}
|
|
48
114
|
}
|
|
49
115
|
}
|
|
@@ -13,7 +13,7 @@ import WebKit
|
|
|
13
13
|
internal extension PaymentSheet {
|
|
14
14
|
|
|
15
15
|
/// Method to get the root view for the payment sheet based on the configured properties.
|
|
16
|
-
func getRootView() ->
|
|
16
|
+
func getRootView() -> UIView {
|
|
17
17
|
|
|
18
18
|
let hyperswitchConfiguration = try? hyperswitchConfiguration?.toDictionary()
|
|
19
19
|
let paymentSessionConfiguration = try? paymentSessionConfiguration.toDictionary()
|
|
@@ -42,7 +42,7 @@ internal extension PaymentSheet {
|
|
|
42
42
|
|
|
43
43
|
/// Method to get the root view for the payment sheet with custom parameters.
|
|
44
44
|
/// - Note: Used by Flutter and React Native Wrappers to send separate props.
|
|
45
|
-
func getRootViewWithParams(props: [String: Any]) ->
|
|
45
|
+
func getRootViewWithParams(props: [String: Any]) -> UIView {
|
|
46
46
|
|
|
47
47
|
let hyperswitchConfiguration = try? hyperswitchConfiguration?.toDictionary()
|
|
48
48
|
let paymentSessionConfiguration = try? paymentSessionConfiguration.toDictionary()
|