nimbbl-mobile-react-native-sdk 1.3.4 → 1.3.5-alpha.0
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 +19 -25
- package/ios/NimbblReactNativeSDK.m +0 -4
- package/ios/NimbblReactNativeSDK.swift +31 -5
- package/lib/NimbblSDK.d.ts +1 -0
- package/lib/NimbblSDK.js +34 -39
- package/package.json +4 -9
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Nimbbl React Native SDK
|
|
2
2
|
|
|
3
|
-
**✅ Stable Release v1.3.
|
|
3
|
+
**✅ Stable Release v1.3.5-alpha.0 - Production Ready!**
|
|
4
4
|
|
|
5
5
|
A comprehensive React Native SDK for integrating Nimbbl payment gateway into your mobile applications. This SDK provides a seamless bridge between React Native and native payment functionality, offering a unified API for both iOS and Android platforms.
|
|
6
6
|
|
|
@@ -36,23 +36,21 @@ const nimbblSDK = NimbblSDK.getSharedInstance();
|
|
|
36
36
|
// Initialize with default production configuration
|
|
37
37
|
await nimbblSDK.initialize();
|
|
38
38
|
|
|
39
|
-
// Set up payment response handler
|
|
40
|
-
nimbblSDK.addCheckoutResponseListener((data) => {
|
|
41
|
-
if (data.status === 'success') {
|
|
42
|
-
console.log('Payment successful:', data);
|
|
43
|
-
} else {
|
|
44
|
-
console.log('Payment failed:', data);
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
|
|
48
39
|
// Start payment with all optional parameters
|
|
49
|
-
await nimbblSDK.checkout({
|
|
40
|
+
const result = await nimbblSDK.checkout({
|
|
50
41
|
orderToken: 'YOUR_ORDER_TOKEN',
|
|
51
42
|
paymentModeCode: '<OPTIONAL>',
|
|
52
43
|
bankCode: '<OPTIONAL>',
|
|
53
44
|
walletCode: '<OPTIONAL>',
|
|
54
45
|
paymentFlow: '<OPTIONAL>'
|
|
55
46
|
});
|
|
47
|
+
|
|
48
|
+
// `checkout()` resolves with the native SDK response payload
|
|
49
|
+
if (result?.status === 'success') {
|
|
50
|
+
console.log('Payment successful:', result);
|
|
51
|
+
} else {
|
|
52
|
+
console.log('Payment result:', result);
|
|
53
|
+
}
|
|
56
54
|
```
|
|
57
55
|
|
|
58
56
|
**That's it! Your payment integration is complete.** 🎉
|
|
@@ -78,7 +76,12 @@ await nimbblSDK.checkout({
|
|
|
78
76
|
| `^0.73.0` | ✅ Supported | Latest stable version |
|
|
79
77
|
| `^0.74.0` | ✅ Supported | Latest stable version |
|
|
80
78
|
| `^0.75.0` | ✅ Supported | Latest stable version |
|
|
81
|
-
| `^0.76.0` | ✅
|
|
79
|
+
| `^0.76.0` | ✅ Supported | Previously tested |
|
|
80
|
+
| `^0.81.0` | ✅ Tested | iOS 26 toolchain verified |
|
|
81
|
+
|
|
82
|
+
### iOS 26 note
|
|
83
|
+
|
|
84
|
+
- Tested by building the sample app against the iOS 26 simulator SDK with React Native `0.81.x`.
|
|
82
85
|
|
|
83
86
|
### Node.js Version Support
|
|
84
87
|
|
|
@@ -135,16 +138,7 @@ await nimbblSDK.initialize({
|
|
|
135
138
|
### 3. Set Up Payment Response Handler
|
|
136
139
|
|
|
137
140
|
```javascript
|
|
138
|
-
//
|
|
139
|
-
nimbblSDK.addCheckoutResponseListener((data) => {
|
|
140
|
-
if (data.status === 'success') {
|
|
141
|
-
console.log('Payment successful:', data);
|
|
142
|
-
// Handle successful payment
|
|
143
|
-
} else {
|
|
144
|
-
console.log('Payment failed:', data);
|
|
145
|
-
// Handle failed payment
|
|
146
|
-
}
|
|
147
|
-
});
|
|
141
|
+
// `checkout()` returns the payment response payload (resolve) or throws if checkout couldn't start (reject)
|
|
148
142
|
```
|
|
149
143
|
|
|
150
144
|
### 4. Start Payment
|
|
@@ -323,7 +317,7 @@ class PaymentManager {
|
|
|
323
317
|
**Problem**: WebView opens and closes, but payment status screen doesn't appear.
|
|
324
318
|
|
|
325
319
|
**Solution**:
|
|
326
|
-
- Ensure you're using the latest SDK version (`^1.3.
|
|
320
|
+
- Ensure you're using the latest SDK version (`^1.3.5-alpha.0`)
|
|
327
321
|
- The SDK automatically manages event listeners - no manual setup required
|
|
328
322
|
- Check that your app properly handles the payment success/failure events
|
|
329
323
|
|
|
@@ -434,14 +428,14 @@ For production applications, consider locking to specific versions:
|
|
|
434
428
|
```json
|
|
435
429
|
{
|
|
436
430
|
"dependencies": {
|
|
437
|
-
"nimbbl-mobile-react-native-sdk": "1.3.
|
|
431
|
+
"nimbbl-mobile-react-native-sdk": "1.3.5-alpha.0"
|
|
438
432
|
}
|
|
439
433
|
}
|
|
440
434
|
```
|
|
441
435
|
|
|
442
436
|
## 📝 Release Notes
|
|
443
437
|
|
|
444
|
-
### v1.3.
|
|
438
|
+
### v1.3.5-alpha.0 - Stable Release ✅
|
|
445
439
|
|
|
446
440
|
**🚀 Stable Production-Ready React Native SDK for Nimbbl Payments**
|
|
447
441
|
|
|
@@ -7,10 +7,6 @@ RCT_EXTERN_METHOD(initialize:(NSDictionary *)config
|
|
|
7
7
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
8
8
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
9
9
|
|
|
10
|
-
RCT_EXTERN_METHOD(createShopOrder:(NSDictionary *)orderData
|
|
11
|
-
resolver:(RCTPromiseResolveBlock)resolve
|
|
12
|
-
rejecter:(RCTPromiseRejectBlock)reject)
|
|
13
|
-
|
|
14
10
|
RCT_EXTERN_METHOD(checkout:(NSDictionary *)options
|
|
15
11
|
resolver:(RCTPromiseResolveBlock)resolve
|
|
16
12
|
rejecter:(RCTPromiseRejectBlock)reject)
|
|
@@ -7,7 +7,6 @@ import UIKit
|
|
|
7
7
|
class NimbblReactNativeSDK: RCTEventEmitter, NimbblCheckoutSDKDelegate {
|
|
8
8
|
|
|
9
9
|
private var config: [String: Any] = [:]
|
|
10
|
-
private var isInitialized = false
|
|
11
10
|
private var checkoutCallback: RCTResponseSenderBlock?
|
|
12
11
|
|
|
13
12
|
override init() {
|
|
@@ -57,8 +56,6 @@ class NimbblReactNativeSDK: RCTEventEmitter, NimbblCheckoutSDKDelegate {
|
|
|
57
56
|
let appCode = self.config["app_code"] as? String
|
|
58
57
|
NimbblCheckoutSDK.shared.initialize(appCode: appCode)
|
|
59
58
|
|
|
60
|
-
isInitialized = true
|
|
61
|
-
|
|
62
59
|
let result: [String: Any] = [
|
|
63
60
|
"success": true,
|
|
64
61
|
"message": "SDK initialized successfully"
|
|
@@ -95,8 +92,7 @@ class NimbblReactNativeSDK: RCTEventEmitter, NimbblCheckoutSDKDelegate {
|
|
|
95
92
|
paymentFlow: paymentFlow
|
|
96
93
|
)
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
guard let rootViewController = UIApplication.shared.windows.first?.rootViewController else {
|
|
95
|
+
guard let rootViewController = self.findPresentingViewController() else {
|
|
100
96
|
reject("NO_VIEW_CONTROLLER", "Could not find root view controller", nil)
|
|
101
97
|
return
|
|
102
98
|
}
|
|
@@ -111,6 +107,21 @@ class NimbblReactNativeSDK: RCTEventEmitter, NimbblCheckoutSDKDelegate {
|
|
|
111
107
|
reject("CHECKOUT_FAILED", error.localizedDescription, error)
|
|
112
108
|
}
|
|
113
109
|
}
|
|
110
|
+
|
|
111
|
+
private func findPresentingViewController() -> UIViewController? {
|
|
112
|
+
if #available(iOS 13.0, *) {
|
|
113
|
+
let windowScenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
|
|
114
|
+
for scene in windowScenes {
|
|
115
|
+
let candidateWindow = scene.windows.first(where: { $0.isKeyWindow }) ?? scene.windows.first
|
|
116
|
+
if let root = candidateWindow?.rootViewController {
|
|
117
|
+
return root.topMostViewController()
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return nil
|
|
121
|
+
} else {
|
|
122
|
+
return UIApplication.shared.keyWindow?.rootViewController?.topMostViewController()
|
|
123
|
+
}
|
|
124
|
+
}
|
|
114
125
|
|
|
115
126
|
// MARK: - NimbblCheckoutSDKDelegate
|
|
116
127
|
|
|
@@ -122,3 +133,18 @@ class NimbblReactNativeSDK: RCTEventEmitter, NimbblCheckoutSDKDelegate {
|
|
|
122
133
|
// Note: Removed fallback to event emitter for cleaner implementation
|
|
123
134
|
}
|
|
124
135
|
}
|
|
136
|
+
|
|
137
|
+
private extension UIViewController {
|
|
138
|
+
func topMostViewController() -> UIViewController {
|
|
139
|
+
if let presented = self.presentedViewController {
|
|
140
|
+
return presented.topMostViewController()
|
|
141
|
+
}
|
|
142
|
+
if let nav = self as? UINavigationController, let visible = nav.visibleViewController {
|
|
143
|
+
return visible.topMostViewController()
|
|
144
|
+
}
|
|
145
|
+
if let tab = self as? UITabBarController, let selected = tab.selectedViewController {
|
|
146
|
+
return selected.topMostViewController()
|
|
147
|
+
}
|
|
148
|
+
return self
|
|
149
|
+
}
|
|
150
|
+
}
|
package/lib/NimbblSDK.d.ts
CHANGED
package/lib/NimbblSDK.js
CHANGED
|
@@ -23,6 +23,7 @@ class NimbblSDK {
|
|
|
23
23
|
}
|
|
24
24
|
this.config = null;
|
|
25
25
|
this.isInitialized = false;
|
|
26
|
+
this.checkoutInProgress = false;
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* Get shared instance (matching iOS pattern)
|
|
@@ -62,46 +63,40 @@ class NimbblSDK {
|
|
|
62
63
|
if (!this.isInitialized) {
|
|
63
64
|
throw new Error(constants_1.ERROR_MESSAGES[constants_1.ERROR_CODES.SDK_NOT_INITIALIZED]);
|
|
64
65
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
order_token: options.orderToken,
|
|
68
|
-
payment_mode_code: options.paymentModeCode || '',
|
|
69
|
-
bank_code: options.bankCode || '',
|
|
70
|
-
wallet_code: options.walletCode || '',
|
|
71
|
-
payment_flow: options.paymentFlow || '',
|
|
72
|
-
checkout_experience: options.checkoutExperience || 'redirect',
|
|
73
|
-
upi_id: options.upiId || '',
|
|
74
|
-
upi_app_code: options.upiAppCode || '',
|
|
75
|
-
emi_code: options.emiCode || '',
|
|
76
|
-
};
|
|
77
|
-
// Use callback-based approach - SDK will always return a response
|
|
78
|
-
return new Promise((resolve) => {
|
|
79
|
-
// Store the resolve function for the native module to call
|
|
80
|
-
const nativeModule = NimbblReactNativeSDK;
|
|
81
|
-
nativeModule.setCheckoutCallback((result) => {
|
|
82
|
-
// Return the raw JSON response from native SDK directly
|
|
83
|
-
resolve(result);
|
|
84
|
-
});
|
|
85
|
-
// Start the checkout process
|
|
86
|
-
nativeModule
|
|
87
|
-
.checkout(checkoutPayload)
|
|
88
|
-
.then(() => {
|
|
89
|
-
// Native checkout initiated successfully
|
|
90
|
-
})
|
|
91
|
-
.catch((error) => {
|
|
92
|
-
resolve({
|
|
93
|
-
status: 'error',
|
|
94
|
-
message: error.message || 'Failed to initiate native checkout',
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
return {
|
|
101
|
-
status: 'error',
|
|
102
|
-
message: error instanceof Error ? error.message : 'Checkout failed',
|
|
103
|
-
};
|
|
66
|
+
if (this.checkoutInProgress) {
|
|
67
|
+
throw new Error('Checkout already in progress.');
|
|
104
68
|
}
|
|
69
|
+
const checkoutPayload = {
|
|
70
|
+
order_token: options.orderToken,
|
|
71
|
+
payment_mode_code: options.paymentModeCode || '',
|
|
72
|
+
bank_code: options.bankCode || '',
|
|
73
|
+
wallet_code: options.walletCode || '',
|
|
74
|
+
payment_flow: options.paymentFlow || '',
|
|
75
|
+
checkout_experience: options.checkoutExperience || 'redirect',
|
|
76
|
+
upi_id: options.upiId || '',
|
|
77
|
+
upi_app_code: options.upiAppCode || '',
|
|
78
|
+
emi_code: options.emiCode || '',
|
|
79
|
+
};
|
|
80
|
+
const nativeModule = NimbblReactNativeSDK;
|
|
81
|
+
// Callback-based: resolve on native response; reject if checkout cannot be initiated.
|
|
82
|
+
return new Promise((resolve, reject) => {
|
|
83
|
+
this.checkoutInProgress = true;
|
|
84
|
+
let settled = false;
|
|
85
|
+
nativeModule.setCheckoutCallback((result) => {
|
|
86
|
+
if (settled)
|
|
87
|
+
return;
|
|
88
|
+
settled = true;
|
|
89
|
+
this.checkoutInProgress = false;
|
|
90
|
+
resolve(result);
|
|
91
|
+
});
|
|
92
|
+
nativeModule.checkout(checkoutPayload).catch((error) => {
|
|
93
|
+
if (settled)
|
|
94
|
+
return;
|
|
95
|
+
settled = true;
|
|
96
|
+
this.checkoutInProgress = false;
|
|
97
|
+
reject(error);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
105
100
|
}
|
|
106
101
|
}
|
|
107
102
|
NimbblSDK.shared = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nimbbl-mobile-react-native-sdk",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.5-alpha.0",
|
|
4
4
|
"description": "Nimbbl React Native SDK for payment integration",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -52,14 +52,9 @@
|
|
|
52
52
|
"publishConfig": {
|
|
53
53
|
"access": "public"
|
|
54
54
|
},
|
|
55
|
-
"peerDependencies": {
|
|
56
|
-
"react": ">=16.8.0",
|
|
57
|
-
"react-native": ">=0.60.0"
|
|
58
|
-
},
|
|
59
55
|
"devDependencies": {
|
|
60
56
|
"@types/jest": "^29.5.0",
|
|
61
|
-
"@types/react": "^
|
|
62
|
-
"@types/react-native": "^0.72.0",
|
|
57
|
+
"@types/react": "^19.1.0",
|
|
63
58
|
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
64
59
|
"@typescript-eslint/parser": "^6.0.0",
|
|
65
60
|
"eslint": "^8.19.0",
|
|
@@ -68,8 +63,8 @@
|
|
|
68
63
|
"jest": "^29.2.1",
|
|
69
64
|
"npm-run-all": "^4.1.5",
|
|
70
65
|
"prettier": "^3.0.0",
|
|
71
|
-
"react": "
|
|
72
|
-
"react-native": "0.
|
|
66
|
+
"react": "19.1.0",
|
|
67
|
+
"react-native": "0.81.0",
|
|
73
68
|
"ts-jest": "^29.1.0",
|
|
74
69
|
"typescript": "^5.0.0",
|
|
75
70
|
"@react-navigation/native": "^7.1.18",
|