react-nomba-checkout-sdk 2.0.2 → 2.0.6
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 +365 -63
- package/dist/apis/useNombaCheckout.d.ts +3 -0
- package/dist/index.esm.js +1 -0
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +75 -74
- package/src/apis/useNombaCheckout.ts +59 -55
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# 🚀 React Nomba Checkout SDK
|
|
2
2
|
|
|
3
|
-
The
|
|
3
|
+
The **react-nomba-checkout-sdk** is a lightweight React SDK designed to simplify payment processing and checkout integration using [Nomba's](https://nomba.com/) secure and reliable infrastructure.
|
|
4
4
|
|
|
5
5
|
> Built with ❤️ by **Israel Itua**
|
|
6
6
|
|
|
@@ -18,15 +18,15 @@ yarn add react-nomba-checkout-sdk
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
-
## ⚡ Quick Start
|
|
21
|
+
## ⚡ Quick Start (React)
|
|
22
22
|
|
|
23
|
-
Here
|
|
23
|
+
Here's how to integrate the SDK into your React project:
|
|
24
24
|
|
|
25
25
|
```jsx
|
|
26
26
|
import { useState } from 'react';
|
|
27
27
|
import {
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
useNombaCheckout,
|
|
29
|
+
InitializeNombaCheckout,
|
|
30
30
|
} from 'react-nomba-checkout-sdk';
|
|
31
31
|
import './App.css';
|
|
32
32
|
|
|
@@ -34,59 +34,62 @@ import './App.css';
|
|
|
34
34
|
InitializeNombaCheckout();
|
|
35
35
|
|
|
36
36
|
function App() {
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
37
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
38
|
+
|
|
39
|
+
const handleCheckout = async () => {
|
|
40
|
+
setIsLoading(true);
|
|
41
|
+
|
|
42
|
+
const res = await useNombaCheckout({
|
|
43
|
+
accountId: 'your-account-id',
|
|
44
|
+
clientId: 'your-client-id',
|
|
45
|
+
order: {
|
|
46
|
+
callbackUrl: 'sample-url',
|
|
47
|
+
customerEmail: 'sample-email@gmail.com',
|
|
48
|
+
amount: '10.00',
|
|
49
|
+
currency: 'NGN',
|
|
50
|
+
orderMetaData: {
|
|
51
|
+
customMerchant: 'true',
|
|
52
|
+
},
|
|
53
|
+
splitRequest: {
|
|
54
|
+
splitType: 'PERCENTAGE',
|
|
55
|
+
splitList: [
|
|
56
|
+
{
|
|
57
|
+
accountId: 'your-account-id',
|
|
58
|
+
value: '65.45',
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
tokenizeCard: 'true',
|
|
64
|
+
onCreateOrder: (orderReference) => {
|
|
65
|
+
console.log('Function called after the order is created');
|
|
66
|
+
console.log({ orderReference });
|
|
67
|
+
setIsLoading(false);
|
|
68
|
+
},
|
|
69
|
+
onFailure: (err) => {
|
|
70
|
+
console.log('Function called if error occurs while creating order.');
|
|
71
|
+
console.log(err);
|
|
72
|
+
setIsLoading(false);
|
|
73
|
+
},
|
|
74
|
+
onClose: () => {
|
|
75
|
+
console.log('Function called when modal is closed.');
|
|
76
|
+
setIsLoading(false);
|
|
77
|
+
},
|
|
78
|
+
onPaymentSuccess: (successResponse) => {
|
|
79
|
+
console.log('Function called on payment success.');
|
|
80
|
+
console.log({ successResponse });
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return (
|
|
86
|
+
<>
|
|
87
|
+
<h1>Pay with Nomba</h1>
|
|
88
|
+
<button onClick={handleCheckout}>
|
|
89
|
+
{isLoading ? 'Please wait...' : 'Pay with Nomba Checkout'}
|
|
90
|
+
</button>
|
|
91
|
+
</>
|
|
92
|
+
);
|
|
90
93
|
}
|
|
91
94
|
|
|
92
95
|
export default App;
|
|
@@ -94,17 +97,297 @@ export default App;
|
|
|
94
97
|
|
|
95
98
|
---
|
|
96
99
|
|
|
100
|
+
## 🔥 Next.js Integration (App Router)
|
|
101
|
+
|
|
102
|
+
For Next.js 13+ with App Router, follow this setup to ensure proper client-side rendering:
|
|
103
|
+
|
|
104
|
+
### Step 1: Create the Checkout Component
|
|
105
|
+
|
|
106
|
+
Create `components/NombaCheckoutButton.tsx`:
|
|
107
|
+
|
|
108
|
+
```tsx
|
|
109
|
+
'use client';
|
|
110
|
+
|
|
111
|
+
import { useState, useEffect } from 'react';
|
|
112
|
+
import {
|
|
113
|
+
useNombaCheckout,
|
|
114
|
+
InitializeNombaCheckout,
|
|
115
|
+
} from 'react-nomba-checkout-sdk';
|
|
116
|
+
|
|
117
|
+
export default function NombaCheckoutButton() {
|
|
118
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
119
|
+
const [isInitialized, setIsInitialized] = useState(false);
|
|
120
|
+
|
|
121
|
+
useEffect(() => {
|
|
122
|
+
InitializeNombaCheckout();
|
|
123
|
+
setIsInitialized(true);
|
|
124
|
+
}, []);
|
|
125
|
+
|
|
126
|
+
const handleCheckout = async () => {
|
|
127
|
+
if (!isInitialized) {
|
|
128
|
+
console.log('SDK not initialized yet');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
setIsLoading(true);
|
|
133
|
+
|
|
134
|
+
const res = await useNombaCheckout({
|
|
135
|
+
accountId: 'your-account-id',
|
|
136
|
+
clientId: 'your-client-id',
|
|
137
|
+
order: {
|
|
138
|
+
callbackUrl: 'https://your-callback-url.com',
|
|
139
|
+
customerEmail: 'sample-email@gmail.com',
|
|
140
|
+
amount: '10.00',
|
|
141
|
+
currency: 'NGN',
|
|
142
|
+
orderMetaData: {
|
|
143
|
+
customMerchant: 'true',
|
|
144
|
+
},
|
|
145
|
+
splitRequest: {
|
|
146
|
+
splitType: 'PERCENTAGE',
|
|
147
|
+
splitList: [
|
|
148
|
+
{
|
|
149
|
+
accountId: 'your-account-id',
|
|
150
|
+
value: 65.45,
|
|
151
|
+
},
|
|
152
|
+
],
|
|
153
|
+
},
|
|
154
|
+
orderReference: 'your-order-reference',
|
|
155
|
+
customerId: '',
|
|
156
|
+
accountId: 'your-account-id',
|
|
157
|
+
},
|
|
158
|
+
tokenizeCard: true,
|
|
159
|
+
onCreateOrder: (orderReference) => {
|
|
160
|
+
console.log('Function called after the order is created');
|
|
161
|
+
console.log({ orderReference });
|
|
162
|
+
setIsLoading(false);
|
|
163
|
+
},
|
|
164
|
+
onFailure: (err) => {
|
|
165
|
+
console.log('Function called if error occurs while creating order.');
|
|
166
|
+
console.log(err);
|
|
167
|
+
setIsLoading(false);
|
|
168
|
+
},
|
|
169
|
+
onClose: () => {
|
|
170
|
+
console.log('Function called when modal is closed.');
|
|
171
|
+
setIsLoading(false);
|
|
172
|
+
return {};
|
|
173
|
+
},
|
|
174
|
+
onPaymentSuccess: (successResponse) => {
|
|
175
|
+
console.log('Function called on payment success.');
|
|
176
|
+
console.log({ successResponse });
|
|
177
|
+
return {};
|
|
178
|
+
},
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
return (
|
|
183
|
+
<>
|
|
184
|
+
<h1>Pay with Nomba</h1>
|
|
185
|
+
<button onClick={handleCheckout} disabled={!isInitialized}>
|
|
186
|
+
{isLoading ? 'Please wait...' : 'Pay with Nomba Checkout'}
|
|
187
|
+
</button>
|
|
188
|
+
</>
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Step 2: Use Dynamic Import in Your Page
|
|
194
|
+
|
|
195
|
+
Create or update your `app/page.tsx`:
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
'use client';
|
|
199
|
+
|
|
200
|
+
import dynamic from 'next/dynamic';
|
|
201
|
+
|
|
202
|
+
// Dynamically import the component with SSR disabled
|
|
203
|
+
const NombaCheckoutButton = dynamic(
|
|
204
|
+
() => import('@/components/NombaCheckoutButton'),
|
|
205
|
+
{ ssr: false }
|
|
206
|
+
);
|
|
207
|
+
|
|
208
|
+
export default function Home() {
|
|
209
|
+
return <NombaCheckoutButton />;
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Step 3: Configure Layout (Optional)
|
|
214
|
+
|
|
215
|
+
Update your `app/layout.tsx` if needed:
|
|
216
|
+
|
|
217
|
+
```tsx
|
|
218
|
+
import type { Metadata } from 'next';
|
|
219
|
+
import { Geist, Geist_Mono } from 'next/font/google';
|
|
220
|
+
import './globals.css';
|
|
221
|
+
|
|
222
|
+
const geistSans = Geist({
|
|
223
|
+
variable: '--font-geist-sans',
|
|
224
|
+
subsets: ['latin'],
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const geistMono = Geist_Mono({
|
|
228
|
+
variable: '--font-geist-mono',
|
|
229
|
+
subsets: ['latin'],
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
export const metadata: Metadata = {
|
|
233
|
+
title: 'Nomba Checkout Integration',
|
|
234
|
+
description: 'Payment processing with Nomba',
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
export default function RootLayout({
|
|
238
|
+
children,
|
|
239
|
+
}: Readonly<{
|
|
240
|
+
children: React.ReactNode;
|
|
241
|
+
}>) {
|
|
242
|
+
return (
|
|
243
|
+
<html lang='en'>
|
|
244
|
+
<body
|
|
245
|
+
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
|
|
246
|
+
suppressHydrationWarning
|
|
247
|
+
>
|
|
248
|
+
{children}
|
|
249
|
+
</body>
|
|
250
|
+
</html>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### ⚠️ Important Next.js Notes
|
|
256
|
+
|
|
257
|
+
- **Always use dynamic import with `ssr: false`** - The SDK requires browser APIs and must be rendered client-side only
|
|
258
|
+
- **Initialize SDK in useEffect** - Ensures proper initialization after component mounts
|
|
259
|
+
- **Use 'use client' directive** - Required for components using browser-specific features
|
|
260
|
+
- **Check initialization state** - Prevent checkout calls before SDK is ready
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
97
264
|
## 🔍 API Reference
|
|
98
265
|
|
|
99
|
-
###
|
|
266
|
+
### InitializeNombaCheckout()
|
|
267
|
+
|
|
268
|
+
Initializes the SDK. Call once when your app loads (or in useEffect for Next.js).
|
|
269
|
+
|
|
270
|
+
```js
|
|
271
|
+
InitializeNombaCheckout();
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
---
|
|
275
|
+
|
|
276
|
+
### useNombaCheckout(options)
|
|
277
|
+
|
|
278
|
+
Launches the Nomba checkout modal.
|
|
279
|
+
|
|
280
|
+
#### Options
|
|
100
281
|
|
|
101
|
-
|
|
282
|
+
| Parameter | Type | Required | Description |
|
|
283
|
+
| ------------------ | -------------- | -------- | ------------------------------ |
|
|
284
|
+
| `accountId` | string | Yes | Your Nomba account ID |
|
|
285
|
+
| `clientId` | string | Yes | Your Nomba client ID |
|
|
286
|
+
| `order` | object | Yes | Order details (see below) |
|
|
287
|
+
| `tokenizeCard` | boolean/string | No | Enable card tokenization |
|
|
288
|
+
| `onCreateOrder` | function | No | Callback after order creation |
|
|
289
|
+
| `onFailure` | function | No | Callback on error |
|
|
290
|
+
| `onClose` | function | No | Callback when modal closes |
|
|
291
|
+
| `onPaymentSuccess` | function | No | Callback on successful payment |
|
|
292
|
+
|
|
293
|
+
#### Order Object
|
|
294
|
+
|
|
295
|
+
| Field | Type | Required | Description |
|
|
296
|
+
| ---------------- | ------ | -------- | --------------------------- |
|
|
297
|
+
| `callbackUrl` | string | Yes | URL for payment callback |
|
|
298
|
+
| `customerEmail` | string | Yes | Customer's email address |
|
|
299
|
+
| `amount` | string | Yes | Payment amount |
|
|
300
|
+
| `currency` | string | Yes | Currency code (e.g., 'NGN') |
|
|
301
|
+
| `orderReference` | string | No | Your order reference |
|
|
302
|
+
| `customerId` | string | No | Customer identifier |
|
|
303
|
+
| `accountId` | string | No | Account ID for the order |
|
|
304
|
+
| `orderMetaData` | object | No | Additional metadata |
|
|
305
|
+
| `splitRequest` | object | No | Payment split configuration |
|
|
306
|
+
|
|
307
|
+
#### Split Request Object
|
|
308
|
+
|
|
309
|
+
| Field | Type | Required | Description |
|
|
310
|
+
| ----------- | ------ | -------- | ----------------------------- |
|
|
311
|
+
| `splitType` | string | Yes | 'PERCENTAGE' or 'FLAT' |
|
|
312
|
+
| `splitList` | array | Yes | Array of split configurations |
|
|
313
|
+
|
|
314
|
+
#### Split List Item
|
|
315
|
+
|
|
316
|
+
| Field | Type | Required | Description |
|
|
317
|
+
| ----------- | ------------- | -------- | --------------------------- |
|
|
318
|
+
| `accountId` | string | Yes | Account ID to receive split |
|
|
319
|
+
| `value` | number/string | Yes | Split amount or percentage |
|
|
102
320
|
|
|
103
321
|
---
|
|
104
322
|
|
|
105
|
-
|
|
323
|
+
## 📝 Example with All Options
|
|
106
324
|
|
|
107
|
-
|
|
325
|
+
```jsx
|
|
326
|
+
const res = await useNombaCheckout({
|
|
327
|
+
accountId: 'acc_123456',
|
|
328
|
+
clientId: 'client_123456',
|
|
329
|
+
order: {
|
|
330
|
+
callbackUrl: 'https://yoursite.com/payment/callback',
|
|
331
|
+
customerEmail: 'customer@example.com',
|
|
332
|
+
amount: '5000.00',
|
|
333
|
+
currency: 'NGN',
|
|
334
|
+
orderReference: 'ORDER-2024-001',
|
|
335
|
+
customerId: 'CUST-001',
|
|
336
|
+
accountId: 'acc_123456',
|
|
337
|
+
orderMetaData: {
|
|
338
|
+
customMerchant: 'true',
|
|
339
|
+
productName: 'Premium Plan',
|
|
340
|
+
},
|
|
341
|
+
splitRequest: {
|
|
342
|
+
splitType: 'PERCENTAGE',
|
|
343
|
+
splitList: [
|
|
344
|
+
{
|
|
345
|
+
accountId: 'acc_partner_1',
|
|
346
|
+
value: 20,
|
|
347
|
+
},
|
|
348
|
+
{
|
|
349
|
+
accountId: 'acc_partner_2',
|
|
350
|
+
value: 15,
|
|
351
|
+
},
|
|
352
|
+
],
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
tokenizeCard: true,
|
|
356
|
+
onCreateOrder: (orderReference) => {
|
|
357
|
+
console.log('Order created:', orderReference);
|
|
358
|
+
},
|
|
359
|
+
onFailure: (error) => {
|
|
360
|
+
console.error('Payment failed:', error);
|
|
361
|
+
},
|
|
362
|
+
onClose: () => {
|
|
363
|
+
console.log('Checkout modal closed');
|
|
364
|
+
return {};
|
|
365
|
+
},
|
|
366
|
+
onPaymentSuccess: (response) => {
|
|
367
|
+
console.log('Payment successful:', response);
|
|
368
|
+
return {};
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
---
|
|
374
|
+
|
|
375
|
+
## 🛠️ Troubleshooting
|
|
376
|
+
|
|
377
|
+
### Next.js Hydration Errors
|
|
378
|
+
|
|
379
|
+
- Ensure you're using `dynamic` import with `ssr: false`
|
|
380
|
+
- Add `suppressHydrationWarning` to your body tag in layout.tsx
|
|
381
|
+
|
|
382
|
+
### SDK Not Initialized
|
|
383
|
+
|
|
384
|
+
- In Next.js, initialize the SDK in `useEffect`
|
|
385
|
+
- Check that the button is disabled until `isInitialized` is true
|
|
386
|
+
|
|
387
|
+
### Modal Not Opening
|
|
388
|
+
|
|
389
|
+
- Verify that `InitializeNombaCheckout()` was called before `useNombaCheckout()`
|
|
390
|
+
- Check browser console for errors
|
|
108
391
|
|
|
109
392
|
---
|
|
110
393
|
|
|
@@ -112,4 +395,23 @@ Launches the Nomba checkout modal. |
|
|
|
112
395
|
|
|
113
396
|
**Israel Itua**
|
|
114
397
|
Frontend Engineer
|
|
115
|
-
[GitHub](https://github.com/the-israelItua/)
|
|
398
|
+
[GitHub](https://github.com/the-israelItua/)
|
|
399
|
+
|
|
400
|
+
---
|
|
401
|
+
|
|
402
|
+
## 👥 Contributors
|
|
403
|
+
|
|
404
|
+
- **Israel Itua** - Original Author - [GitHub](https://github.com/the-israelItua/)
|
|
405
|
+
- **Kelechi Uma** - Contributor - [GitHub](https://github.com/Kusjay)
|
|
406
|
+
|
|
407
|
+
---
|
|
408
|
+
|
|
409
|
+
## 📄 License
|
|
410
|
+
|
|
411
|
+
MIT
|
|
412
|
+
|
|
413
|
+
---
|
|
414
|
+
|
|
415
|
+
## 🤝 Contributing
|
|
416
|
+
|
|
417
|
+
Contributions, issues, and feature requests are welcome!
|
package/dist/index.esm.js
CHANGED
|
@@ -4042,6 +4042,7 @@ var useNombaCheckout = function (payload) { return __awaiter(undefined, undefine
|
|
|
4042
4042
|
switch (_d.label) {
|
|
4043
4043
|
case 0:
|
|
4044
4044
|
_d.trys.push([0, 2, , 3]);
|
|
4045
|
+
console.log('🔗 Using LOCAL SDK version!', payload.order.orderMetaData);
|
|
4045
4046
|
return [4 /*yield*/, handleNombaApiCall('/checkout/order', 'POST', {
|
|
4046
4047
|
order: __assign(__assign({}, payload.order), { accountId: payload.accountId }),
|
|
4047
4048
|
tokenizeCard: payload.tokenizeCard,
|