fairsure-checkout-sdk 1.0.8 → 1.0.10
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/dist/components/PaystackCheckout.d.ts +3 -1
- package/dist/components/PaystackCheckout.js +12 -4
- package/dist/components/USSDPayment.js +37 -4
- package/dist/components/usePaymentCheckout.d.ts +1 -1
- package/dist/components/usePaymentCheckout.js +132 -14
- package/dist/context/CheckoutProvider.js +1 -1
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/PaystackCheckout.tsx +14 -2
- package/src/components/USSDPayment.tsx +41 -5
- package/src/components/usePaymentCheckout.ts +134 -11
- package/src/context/CheckoutProvider.tsx +2 -0
- package/src/types.ts +2 -0
|
@@ -8,6 +8,8 @@ type CheckoutProps = {
|
|
|
8
8
|
merchantName?: string;
|
|
9
9
|
onClose: () => void;
|
|
10
10
|
onSuccess?: (reference: string) => void;
|
|
11
|
+
onPending?: (result: any) => void;
|
|
12
|
+
onError?: (error: any) => void;
|
|
11
13
|
};
|
|
12
|
-
export default function Checkout({ requestId, customerEmail, customerName, customerPhone, amount, merchantName, onClose, onSuccess, }: CheckoutProps): import("react").JSX.Element;
|
|
14
|
+
export default function Checkout({ requestId, customerEmail, customerName, customerPhone, amount, merchantName, onClose, onSuccess, onPending, onError, }: CheckoutProps): import("react").JSX.Element;
|
|
13
15
|
export {};
|
|
@@ -10,10 +10,16 @@ const paymentMethods = [
|
|
|
10
10
|
{ id: "transfer", name: "Transfer", icon: "business-outline" },
|
|
11
11
|
{ id: "ussd", name: "USSD", icon: "phone-portrait-outline" },
|
|
12
12
|
];
|
|
13
|
-
export default function Checkout({ requestId, customerEmail, customerName, customerPhone, amount, merchantName = "Merchant", onClose, onSuccess, }) {
|
|
13
|
+
export default function Checkout({ requestId, customerEmail, customerName, customerPhone, amount, merchantName = "Merchant", onClose, onSuccess, onPending, onError, }) {
|
|
14
14
|
const checkout = usePaymentCheckout(amount, requestId, customerEmail, customerName, customerPhone, (reference) => {
|
|
15
15
|
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(reference);
|
|
16
16
|
handleClose();
|
|
17
|
+
}, (result) => {
|
|
18
|
+
onPending === null || onPending === void 0 ? void 0 : onPending(result);
|
|
19
|
+
handleClose();
|
|
20
|
+
}, (error) => {
|
|
21
|
+
onError === null || onError === void 0 ? void 0 : onError(error);
|
|
22
|
+
handleClose();
|
|
17
23
|
});
|
|
18
24
|
const handleClose = () => {
|
|
19
25
|
checkout.resetForm();
|
|
@@ -93,9 +99,11 @@ export default function Checkout({ requestId, customerEmail, customerName, custo
|
|
|
93
99
|
<Text style={styles.payButtonText}>{getButtonText()}</Text>
|
|
94
100
|
{checkout.loading && (<ActivityIndicator size="small" color="white"/>)}
|
|
95
101
|
</TouchableOpacity>
|
|
96
|
-
{!checkout.loading && checkout.timeLeft <= 0 && (
|
|
97
|
-
|
|
98
|
-
|
|
102
|
+
{/* {!checkout.loading && checkout.timeLeft <= 0 && (
|
|
103
|
+
<TouchableOpacity>
|
|
104
|
+
<Text>Resend</Text>
|
|
105
|
+
</TouchableOpacity>
|
|
106
|
+
)} */}
|
|
99
107
|
|
|
100
108
|
{/* Footer */}
|
|
101
109
|
<View style={styles.footer}>
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Ionicons } from "@expo/vector-icons";
|
|
2
2
|
import { ActivityIndicator, ScrollView, StyleSheet, Text, TouchableOpacity, View, } from "react-native";
|
|
3
3
|
export default function USSDPayment({ selectedBank, setSelectedBank, showBankDropdown, ussString, setShowBankDropdown, ussdBanks, loading, copied, handleCopy, }) {
|
|
4
|
-
// console.log("USSSSSS", ussdBanks);
|
|
5
4
|
return (<View>
|
|
6
5
|
<View style={styles.inputGroup}>
|
|
7
6
|
<Text style={styles.inputLabel}>Select Your Bank</Text>
|
|
@@ -12,6 +11,18 @@ export default function USSDPayment({ selectedBank, setSelectedBank, showBankDro
|
|
|
12
11
|
<Ionicons name="chevron-down" size={20} color="#9CA3AF"/>
|
|
13
12
|
</TouchableOpacity>
|
|
14
13
|
|
|
14
|
+
{!showBankDropdown && !selectedBank && (<View style={styles.instructionContainer}>
|
|
15
|
+
<Text style={styles.instructionTitle}>How to pay with USSD</Text>
|
|
16
|
+
|
|
17
|
+
<Text style={styles.instructionText}>
|
|
18
|
+
1. Select your bank{"\n"}
|
|
19
|
+
2. Dial the generated USSD code{"\n"}
|
|
20
|
+
3. Follow the prompts on your phone{"\n"}
|
|
21
|
+
4. Authorize payment with your PIN{"\n"}
|
|
22
|
+
5. Click the "Confirm Payment" button.
|
|
23
|
+
</Text>
|
|
24
|
+
</View>)}
|
|
25
|
+
|
|
15
26
|
{showBankDropdown && (<BankDropdown ussdBanks={ussdBanks} loading={loading} onSelectBank={(bank) => {
|
|
16
27
|
setSelectedBank(bank);
|
|
17
28
|
setShowBankDropdown(false);
|
|
@@ -51,12 +62,32 @@ function USSDInstructions({ ussdCode, copied, handleCopy, loading, }) {
|
|
|
51
62
|
<Text style={styles.ussdStepsText}>
|
|
52
63
|
1. Dial the USSD code on your phone{"\n"}
|
|
53
64
|
2. Follow the prompts on your screen{"\n"}
|
|
54
|
-
3. Authorize payment with your bank PIN
|
|
65
|
+
3. Authorize payment with your bank PIN{"\n"}
|
|
66
|
+
4. Click the "Confirm Payment" button.
|
|
55
67
|
</Text>
|
|
56
68
|
</View>
|
|
57
69
|
</View>);
|
|
58
70
|
}
|
|
59
71
|
const styles = StyleSheet.create({
|
|
72
|
+
instructionContainer: {
|
|
73
|
+
marginTop: 12,
|
|
74
|
+
padding: 16,
|
|
75
|
+
backgroundColor: "#F9FAFB",
|
|
76
|
+
borderRadius: 12,
|
|
77
|
+
borderWidth: 1,
|
|
78
|
+
borderColor: "#E5E7EB",
|
|
79
|
+
},
|
|
80
|
+
instructionTitle: {
|
|
81
|
+
fontSize: 14,
|
|
82
|
+
fontWeight: "600",
|
|
83
|
+
color: "#111827",
|
|
84
|
+
marginBottom: 8,
|
|
85
|
+
},
|
|
86
|
+
instructionText: {
|
|
87
|
+
fontSize: 13,
|
|
88
|
+
lineHeight: 22,
|
|
89
|
+
color: "#6B7280",
|
|
90
|
+
},
|
|
60
91
|
overlay: {
|
|
61
92
|
flex: 1,
|
|
62
93
|
backgroundColor: "rgba(0,0,0,0.5)",
|
|
@@ -250,8 +281,9 @@ const styles = StyleSheet.create({
|
|
|
250
281
|
},
|
|
251
282
|
ussdCodeContainer: {
|
|
252
283
|
backgroundColor: "white", // bg-white
|
|
253
|
-
borderRadius:
|
|
254
|
-
|
|
284
|
+
borderRadius: 8, // rounded-xl
|
|
285
|
+
paddingHorizontal: 12, // p-4
|
|
286
|
+
paddingTop: 12,
|
|
255
287
|
marginBottom: 12, // mb-3
|
|
256
288
|
},
|
|
257
289
|
ussdCodeRow: {
|
|
@@ -277,6 +309,7 @@ const styles = StyleSheet.create({
|
|
|
277
309
|
},
|
|
278
310
|
ussdStepsText: {
|
|
279
311
|
fontSize: 14, // text-sm
|
|
312
|
+
padding: 4, // px-2
|
|
280
313
|
color: "#1E40AF", // text-indigo-800
|
|
281
314
|
},
|
|
282
315
|
payButton: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare function usePaymentCheckout(amount: number, requestId: string, customerEmail: string, customerName: string, customerPhone: string, onSuccess?: (reference: string) => void): {
|
|
1
|
+
export declare function usePaymentCheckout(amount: number, requestId: string, customerEmail: string, customerName: string, customerPhone: string, onSuccess?: (reference: string) => void, onPending?: (result: any) => void, onError?: (error: any) => void): {
|
|
2
2
|
selectedMethod: string;
|
|
3
3
|
cardNumber: string;
|
|
4
4
|
expiryDate: string;
|
|
@@ -3,7 +3,7 @@ import * as Clipboard from "expo-clipboard";
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { Dimensions, Platform } from "react-native";
|
|
5
5
|
const { width, height } = Dimensions.get("window");
|
|
6
|
-
export function usePaymentCheckout(amount, requestId, customerEmail, customerName, customerPhone, onSuccess) {
|
|
6
|
+
export function usePaymentCheckout(amount, requestId, customerEmail, customerName, customerPhone, onSuccess, onPending, onError) {
|
|
7
7
|
const [selectedMethod, setSelectedMethod] = useState("card");
|
|
8
8
|
const [cardNumber, setCardNumber] = useState("");
|
|
9
9
|
const [expiryDate, setExpiryDate] = useState("");
|
|
@@ -67,7 +67,7 @@ export function usePaymentCheckout(amount, requestId, customerEmail, customerNam
|
|
|
67
67
|
}
|
|
68
68
|
}, [selectedMethod]);
|
|
69
69
|
const fetchTransferDetails = async () => {
|
|
70
|
-
var _a
|
|
70
|
+
var _a;
|
|
71
71
|
setLoading(true);
|
|
72
72
|
try {
|
|
73
73
|
const payload = {
|
|
@@ -84,8 +84,7 @@ export function usePaymentCheckout(amount, requestId, customerEmail, customerNam
|
|
|
84
84
|
"User-Agent": "PostmanRuntime/7.51.0",
|
|
85
85
|
},
|
|
86
86
|
});
|
|
87
|
-
|
|
88
|
-
setTransferDetail((_b = res === null || res === void 0 ? void 0 : res.data) === null || _b === void 0 ? void 0 : _b.data);
|
|
87
|
+
setTransferDetail((_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.data);
|
|
89
88
|
}
|
|
90
89
|
catch (error) {
|
|
91
90
|
console.log("FETCH ERROR:", error);
|
|
@@ -111,6 +110,7 @@ export function usePaymentCheckout(amount, requestId, customerEmail, customerNam
|
|
|
111
110
|
"User-Agent": "PostmanRuntime/7.51.0",
|
|
112
111
|
},
|
|
113
112
|
});
|
|
113
|
+
console.log("USSD GENERATION RES", JSON.stringify(res.data.data, null, 2));
|
|
114
114
|
setUssdBankResponse((_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.data);
|
|
115
115
|
}
|
|
116
116
|
catch (error) {
|
|
@@ -121,13 +121,14 @@ export function usePaymentCheckout(amount, requestId, customerEmail, customerNam
|
|
|
121
121
|
}
|
|
122
122
|
};
|
|
123
123
|
const verifyUssd = async () => {
|
|
124
|
+
var _a, _b, _c, _d;
|
|
124
125
|
try {
|
|
125
126
|
setLoading(true);
|
|
126
127
|
const payload = {
|
|
127
128
|
codeReference: ussdBankResponse === null || ussdBankResponse === void 0 ? void 0 : ussdBankResponse.codeRef,
|
|
128
129
|
amount: ussdBankResponse === null || ussdBankResponse === void 0 ? void 0 : ussdBankResponse.amount,
|
|
129
130
|
};
|
|
130
|
-
const res = await axios.post("https://api.
|
|
131
|
+
const res = await axios.post("https://api.fairsurepay.com/api/pub/ussd-status", payload, {
|
|
131
132
|
headers: {
|
|
132
133
|
Accept: "application/json",
|
|
133
134
|
"Content-Type": "application/json",
|
|
@@ -135,16 +136,54 @@ export function usePaymentCheckout(amount, requestId, customerEmail, customerNam
|
|
|
135
136
|
"User-Agent": "PostmanRuntime/7.51.0",
|
|
136
137
|
},
|
|
137
138
|
});
|
|
138
|
-
|
|
139
|
-
|
|
139
|
+
const result = (_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.data;
|
|
140
|
+
const status = (_c = (_b = result === null || result === void 0 ? void 0 : result.message) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _c !== void 0 ? _c : "";
|
|
141
|
+
if (status.includes("pending")) {
|
|
142
|
+
onPending === null || onPending === void 0 ? void 0 : onPending(result);
|
|
143
|
+
}
|
|
144
|
+
else if (status.includes("success") && (result === null || result === void 0 ? void 0 : result.paid)) {
|
|
145
|
+
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(result.transactionRef);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
onError === null || onError === void 0 ? void 0 : onError((_d = result === null || result === void 0 ? void 0 : result.message) !== null && _d !== void 0 ? _d : "Payment could not be verified");
|
|
149
|
+
}
|
|
140
150
|
}
|
|
141
151
|
catch (error) {
|
|
142
152
|
console.log("FETCH ERROR:", error);
|
|
153
|
+
onError === null || onError === void 0 ? void 0 : onError(error);
|
|
143
154
|
}
|
|
144
155
|
finally {
|
|
145
156
|
setLoading(false);
|
|
146
157
|
}
|
|
147
158
|
};
|
|
159
|
+
// const verifyUssd = async () => {
|
|
160
|
+
// try {
|
|
161
|
+
// setLoading(true);
|
|
162
|
+
// const payload = {
|
|
163
|
+
// codeReference: ussdBankResponse?.codeRef,
|
|
164
|
+
// amount: ussdBankResponse?.amount,
|
|
165
|
+
// };
|
|
166
|
+
// const res = await axios.post(
|
|
167
|
+
// "https://api.fairsurepay.com/api/pub/ussd-status",
|
|
168
|
+
// payload,
|
|
169
|
+
// {
|
|
170
|
+
// headers: {
|
|
171
|
+
// Accept: "application/json",
|
|
172
|
+
// "Content-Type": "application/json",
|
|
173
|
+
// publickey: "LIVE_7AXSCCY8R3HABAN14QP7",
|
|
174
|
+
// "User-Agent": "PostmanRuntime/7.51.0",
|
|
175
|
+
// },
|
|
176
|
+
// },
|
|
177
|
+
// );
|
|
178
|
+
// console.log("USSD PAYMENT RESPONSE", res);
|
|
179
|
+
// onSuccess?.(cardDetails.transactionRef);
|
|
180
|
+
// setLoading(false);
|
|
181
|
+
// } catch (error) {
|
|
182
|
+
// console.log("FETCH ERROR:", error);
|
|
183
|
+
// } finally {
|
|
184
|
+
// setLoading(false);
|
|
185
|
+
// }
|
|
186
|
+
// };
|
|
148
187
|
useEffect(() => {
|
|
149
188
|
if (selectedBank) {
|
|
150
189
|
generateUssdCode();
|
|
@@ -302,12 +341,12 @@ export function usePaymentCheckout(amount, requestId, customerEmail, customerNam
|
|
|
302
341
|
}
|
|
303
342
|
};
|
|
304
343
|
const verifyCardPayment = async () => {
|
|
344
|
+
var _a, _b, _c, _d;
|
|
305
345
|
setLoading(true);
|
|
306
346
|
try {
|
|
307
347
|
const payload = {
|
|
308
348
|
transactionId: cardDetails === null || cardDetails === void 0 ? void 0 : cardDetails.transactionRef,
|
|
309
349
|
paymentId: cardDetails === null || cardDetails === void 0 ? void 0 : cardDetails.paymentId,
|
|
310
|
-
// eciFlag: "07",
|
|
311
350
|
otp: otp,
|
|
312
351
|
customerName,
|
|
313
352
|
customerPhone,
|
|
@@ -321,17 +360,85 @@ export function usePaymentCheckout(amount, requestId, customerEmail, customerNam
|
|
|
321
360
|
"User-Agent": "PostmanRuntime/7.36.0",
|
|
322
361
|
},
|
|
323
362
|
});
|
|
324
|
-
|
|
325
|
-
|
|
363
|
+
const result = (_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.data;
|
|
364
|
+
const status = (_c = (_b = result === null || result === void 0 ? void 0 : result.message) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _c !== void 0 ? _c : "";
|
|
365
|
+
if (status.includes("pending")) {
|
|
366
|
+
onPending === null || onPending === void 0 ? void 0 : onPending(result);
|
|
367
|
+
}
|
|
368
|
+
else if (status.includes("success") || (result === null || result === void 0 ? void 0 : result.paid)) {
|
|
369
|
+
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(cardDetails.transactionRef);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
onError === null || onError === void 0 ? void 0 : onError((_d = result === null || result === void 0 ? void 0 : result.message) !== null && _d !== void 0 ? _d : "Card payment could not be verified");
|
|
373
|
+
}
|
|
326
374
|
return res === null || res === void 0 ? void 0 : res.data;
|
|
327
375
|
}
|
|
328
376
|
catch (error) {
|
|
329
|
-
setLoading(false);
|
|
330
377
|
console.log("ERROR", error);
|
|
378
|
+
onError === null || onError === void 0 ? void 0 : onError(error);
|
|
379
|
+
}
|
|
380
|
+
finally {
|
|
381
|
+
setLoading(false);
|
|
331
382
|
}
|
|
332
383
|
};
|
|
384
|
+
// const verifyCardPayment = async () => {
|
|
385
|
+
// setLoading(true);
|
|
386
|
+
// try {
|
|
387
|
+
// const payload = {
|
|
388
|
+
// transactionId: cardDetails?.transactionRef,
|
|
389
|
+
// paymentId: cardDetails?.paymentId,
|
|
390
|
+
// // eciFlag: "07",
|
|
391
|
+
// otp: otp,
|
|
392
|
+
// customerName,
|
|
393
|
+
// customerPhone,
|
|
394
|
+
// customerEmail,
|
|
395
|
+
// };
|
|
396
|
+
// const res = await axios.post(
|
|
397
|
+
// "https://api.fairsurepay.com/api/pub/submit-otp",
|
|
398
|
+
// payload,
|
|
399
|
+
// {
|
|
400
|
+
// headers: {
|
|
401
|
+
// Accept: "application/json",
|
|
402
|
+
// "Content-Type": "application/json",
|
|
403
|
+
// publickey: "LIVE_7AXSCCY8R3HABAN14QP7",
|
|
404
|
+
// "User-Agent": "PostmanRuntime/7.36.0",
|
|
405
|
+
// },
|
|
406
|
+
// },
|
|
407
|
+
// );
|
|
408
|
+
// onSuccess?.(transferDetail.transactionReference);
|
|
409
|
+
// setLoading(false);
|
|
410
|
+
// return res?.data;
|
|
411
|
+
// } catch (error) {
|
|
412
|
+
// setLoading(false);
|
|
413
|
+
// console.log("ERROR", error);
|
|
414
|
+
// }
|
|
415
|
+
// };
|
|
416
|
+
// const verifyTransfer = async () => {
|
|
417
|
+
// setLoading(true);
|
|
418
|
+
// try {
|
|
419
|
+
// const res = await axios.get(
|
|
420
|
+
// `https://api.fairsurepay.com/api/pub/transfer-status?transactionReference=${transferDetail?.transactionReference}`,
|
|
421
|
+
// {
|
|
422
|
+
// timeout: 15000,
|
|
423
|
+
// headers: {
|
|
424
|
+
// Accept: "application/json",
|
|
425
|
+
// "Content-Type": "application/json",
|
|
426
|
+
// publickey: "LIVE_7AXSCCY8R3HABAN14QP7",
|
|
427
|
+
// "User-Agent": "PostmanRuntime/7.36.0",
|
|
428
|
+
// },
|
|
429
|
+
// },
|
|
430
|
+
// );
|
|
431
|
+
// console.log("RESPONSE", res);
|
|
432
|
+
// onSuccess?.(transferDetail.transactionReference);
|
|
433
|
+
// return res?.data;
|
|
434
|
+
// } catch (error: any) {
|
|
435
|
+
// console.log("Failed to Verify transfer", error.response?.data);
|
|
436
|
+
// } finally {
|
|
437
|
+
// setLoading(false);
|
|
438
|
+
// }
|
|
439
|
+
// };
|
|
333
440
|
const verifyTransfer = async () => {
|
|
334
|
-
var _a;
|
|
441
|
+
var _a, _b, _c, _d, _e;
|
|
335
442
|
setLoading(true);
|
|
336
443
|
try {
|
|
337
444
|
const res = await axios.get(`https://api.fairsurepay.com/api/pub/transfer-status?transactionReference=${transferDetail === null || transferDetail === void 0 ? void 0 : transferDetail.transactionReference}`, {
|
|
@@ -343,11 +450,22 @@ export function usePaymentCheckout(amount, requestId, customerEmail, customerNam
|
|
|
343
450
|
"User-Agent": "PostmanRuntime/7.36.0",
|
|
344
451
|
},
|
|
345
452
|
});
|
|
346
|
-
|
|
453
|
+
const result = (_a = res === null || res === void 0 ? void 0 : res.data) === null || _a === void 0 ? void 0 : _a.data;
|
|
454
|
+
const status = (_c = (_b = result === null || result === void 0 ? void 0 : result.message) === null || _b === void 0 ? void 0 : _b.toLowerCase()) !== null && _c !== void 0 ? _c : "";
|
|
455
|
+
if (status.includes("pending")) {
|
|
456
|
+
onPending === null || onPending === void 0 ? void 0 : onPending(result);
|
|
457
|
+
}
|
|
458
|
+
else if (status.includes("success") || (result === null || result === void 0 ? void 0 : result.paid)) {
|
|
459
|
+
onSuccess === null || onSuccess === void 0 ? void 0 : onSuccess(transferDetail.transactionReference);
|
|
460
|
+
}
|
|
461
|
+
else {
|
|
462
|
+
onError === null || onError === void 0 ? void 0 : onError((_d = result === null || result === void 0 ? void 0 : result.message) !== null && _d !== void 0 ? _d : "Transfer could not be verified");
|
|
463
|
+
}
|
|
347
464
|
return res === null || res === void 0 ? void 0 : res.data;
|
|
348
465
|
}
|
|
349
466
|
catch (error) {
|
|
350
|
-
console.log("Failed to Verify transfer", (
|
|
467
|
+
console.log("Failed to Verify transfer", (_e = error.response) === null || _e === void 0 ? void 0 : _e.data);
|
|
468
|
+
onError === null || onError === void 0 ? void 0 : onError(error);
|
|
351
469
|
}
|
|
352
470
|
finally {
|
|
353
471
|
setLoading(false);
|
|
@@ -10,7 +10,7 @@ export function CheckoutProvider({ children }) {
|
|
|
10
10
|
return (<CheckoutContext.Provider value={{ openCheckout }}>
|
|
11
11
|
{children}
|
|
12
12
|
|
|
13
|
-
{config && (<Checkout amount={config.amount} merchantName={config.merchantName} onSuccess={config.onSuccess} onClose={closeCheckout} requestId={config.requestId} customerEmail={config.customerEmail} customerName={config.customerName} customerPhone={config.customerPhone}/>)}
|
|
13
|
+
{config && (<Checkout amount={config.amount} merchantName={config.merchantName} onSuccess={config.onSuccess} onPending={config.onPending} onError={config.onError} onClose={closeCheckout} requestId={config.requestId} customerEmail={config.customerEmail} customerName={config.customerName} customerPhone={config.customerPhone}/>)}
|
|
14
14
|
</CheckoutContext.Provider>);
|
|
15
15
|
}
|
|
16
16
|
export const useCheckoutContext = () => useContext(CheckoutContext);
|
package/dist/types.d.ts
CHANGED
package/package.json
CHANGED
|
@@ -24,6 +24,8 @@ type CheckoutProps = {
|
|
|
24
24
|
merchantName?: string;
|
|
25
25
|
onClose: () => void;
|
|
26
26
|
onSuccess?: (reference: string) => void;
|
|
27
|
+
onPending?: (result: any) => void;
|
|
28
|
+
onError?: (error: any) => void;
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
const paymentMethods = [
|
|
@@ -41,6 +43,8 @@ export default function Checkout({
|
|
|
41
43
|
merchantName = "Merchant",
|
|
42
44
|
onClose,
|
|
43
45
|
onSuccess,
|
|
46
|
+
onPending,
|
|
47
|
+
onError,
|
|
44
48
|
}: CheckoutProps) {
|
|
45
49
|
const checkout = usePaymentCheckout(
|
|
46
50
|
amount,
|
|
@@ -52,6 +56,14 @@ export default function Checkout({
|
|
|
52
56
|
onSuccess?.(reference);
|
|
53
57
|
handleClose();
|
|
54
58
|
},
|
|
59
|
+
(result) => {
|
|
60
|
+
onPending?.(result);
|
|
61
|
+
handleClose();
|
|
62
|
+
},
|
|
63
|
+
(error) => {
|
|
64
|
+
onError?.(error);
|
|
65
|
+
handleClose();
|
|
66
|
+
},
|
|
55
67
|
);
|
|
56
68
|
|
|
57
69
|
const handleClose = () => {
|
|
@@ -194,11 +206,11 @@ export default function Checkout({
|
|
|
194
206
|
<ActivityIndicator size="small" color="white" />
|
|
195
207
|
)}
|
|
196
208
|
</TouchableOpacity>
|
|
197
|
-
{!checkout.loading && checkout.timeLeft <= 0 && (
|
|
209
|
+
{/* {!checkout.loading && checkout.timeLeft <= 0 && (
|
|
198
210
|
<TouchableOpacity>
|
|
199
211
|
<Text>Resend</Text>
|
|
200
212
|
</TouchableOpacity>
|
|
201
|
-
)}
|
|
213
|
+
)} */}
|
|
202
214
|
|
|
203
215
|
{/* Footer */}
|
|
204
216
|
<View style={styles.footer}>
|
|
@@ -36,8 +36,6 @@ export default function USSDPayment({
|
|
|
36
36
|
copied,
|
|
37
37
|
handleCopy,
|
|
38
38
|
}: USSDPaymentProps) {
|
|
39
|
-
// console.log("USSSSSS", ussdBanks);
|
|
40
|
-
|
|
41
39
|
return (
|
|
42
40
|
<View>
|
|
43
41
|
<View style={styles.inputGroup}>
|
|
@@ -56,6 +54,20 @@ export default function USSDPayment({
|
|
|
56
54
|
<Ionicons name="chevron-down" size={20} color="#9CA3AF" />
|
|
57
55
|
</TouchableOpacity>
|
|
58
56
|
|
|
57
|
+
{!showBankDropdown && !selectedBank && (
|
|
58
|
+
<View style={styles.instructionContainer}>
|
|
59
|
+
<Text style={styles.instructionTitle}>How to pay with USSD</Text>
|
|
60
|
+
|
|
61
|
+
<Text style={styles.instructionText}>
|
|
62
|
+
1. Select your bank{"\n"}
|
|
63
|
+
2. Dial the generated USSD code{"\n"}
|
|
64
|
+
3. Follow the prompts on your phone{"\n"}
|
|
65
|
+
4. Authorize payment with your PIN{"\n"}
|
|
66
|
+
5. Click the "Confirm Payment" button.
|
|
67
|
+
</Text>
|
|
68
|
+
</View>
|
|
69
|
+
)}
|
|
70
|
+
|
|
59
71
|
{showBankDropdown && (
|
|
60
72
|
<BankDropdown
|
|
61
73
|
ussdBanks={ussdBanks}
|
|
@@ -153,13 +165,35 @@ function USSDInstructions({
|
|
|
153
165
|
<Text style={styles.ussdStepsText}>
|
|
154
166
|
1. Dial the USSD code on your phone{"\n"}
|
|
155
167
|
2. Follow the prompts on your screen{"\n"}
|
|
156
|
-
3. Authorize payment with your bank PIN
|
|
168
|
+
3. Authorize payment with your bank PIN{"\n"}
|
|
169
|
+
4. Click the "Confirm Payment" button.
|
|
157
170
|
</Text>
|
|
158
171
|
</View>
|
|
159
172
|
</View>
|
|
160
173
|
);
|
|
161
174
|
}
|
|
162
175
|
const styles = StyleSheet.create({
|
|
176
|
+
instructionContainer: {
|
|
177
|
+
marginTop: 12,
|
|
178
|
+
padding: 16,
|
|
179
|
+
backgroundColor: "#F9FAFB",
|
|
180
|
+
borderRadius: 12,
|
|
181
|
+
borderWidth: 1,
|
|
182
|
+
borderColor: "#E5E7EB",
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
instructionTitle: {
|
|
186
|
+
fontSize: 14,
|
|
187
|
+
fontWeight: "600",
|
|
188
|
+
color: "#111827",
|
|
189
|
+
marginBottom: 8,
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
instructionText: {
|
|
193
|
+
fontSize: 13,
|
|
194
|
+
lineHeight: 22,
|
|
195
|
+
color: "#6B7280",
|
|
196
|
+
},
|
|
163
197
|
overlay: {
|
|
164
198
|
flex: 1,
|
|
165
199
|
backgroundColor: "rgba(0,0,0,0.5)",
|
|
@@ -356,8 +390,9 @@ const styles = StyleSheet.create({
|
|
|
356
390
|
},
|
|
357
391
|
ussdCodeContainer: {
|
|
358
392
|
backgroundColor: "white", // bg-white
|
|
359
|
-
borderRadius:
|
|
360
|
-
|
|
393
|
+
borderRadius: 8, // rounded-xl
|
|
394
|
+
paddingHorizontal: 12, // p-4
|
|
395
|
+
paddingTop: 12,
|
|
361
396
|
marginBottom: 12, // mb-3
|
|
362
397
|
},
|
|
363
398
|
ussdCodeRow: {
|
|
@@ -383,6 +418,7 @@ const styles = StyleSheet.create({
|
|
|
383
418
|
},
|
|
384
419
|
ussdStepsText: {
|
|
385
420
|
fontSize: 14, // text-sm
|
|
421
|
+
padding: 4, // px-2
|
|
386
422
|
color: "#1E40AF", // text-indigo-800
|
|
387
423
|
},
|
|
388
424
|
payButton: {
|
|
@@ -12,6 +12,8 @@ export function usePaymentCheckout(
|
|
|
12
12
|
customerName: string,
|
|
13
13
|
customerPhone: string,
|
|
14
14
|
onSuccess?: (reference: string) => void,
|
|
15
|
+
onPending?: (result: any) => void,
|
|
16
|
+
onError?: (error: any) => void,
|
|
15
17
|
) {
|
|
16
18
|
const [selectedMethod, setSelectedMethod] = useState("card");
|
|
17
19
|
const [cardNumber, setCardNumber] = useState("");
|
|
@@ -104,8 +106,6 @@ export function usePaymentCheckout(
|
|
|
104
106
|
},
|
|
105
107
|
},
|
|
106
108
|
);
|
|
107
|
-
console.log("RESPONSE", res?.data?.data);
|
|
108
|
-
|
|
109
109
|
setTransferDetail(res?.data?.data);
|
|
110
110
|
} catch (error) {
|
|
111
111
|
console.log("FETCH ERROR:", error);
|
|
@@ -135,6 +135,11 @@ export function usePaymentCheckout(
|
|
|
135
135
|
},
|
|
136
136
|
},
|
|
137
137
|
);
|
|
138
|
+
console.log(
|
|
139
|
+
"USSD GENERATION RES",
|
|
140
|
+
JSON.stringify(res.data.data, null, 2),
|
|
141
|
+
);
|
|
142
|
+
|
|
138
143
|
setUssdBankResponse(res?.data?.data);
|
|
139
144
|
} catch (error) {
|
|
140
145
|
console.log("FETCH ERROR:", error);
|
|
@@ -151,7 +156,7 @@ export function usePaymentCheckout(
|
|
|
151
156
|
amount: ussdBankResponse?.amount,
|
|
152
157
|
};
|
|
153
158
|
const res = await axios.post(
|
|
154
|
-
"https://api.
|
|
159
|
+
"https://api.fairsurepay.com/api/pub/ussd-status",
|
|
155
160
|
payload,
|
|
156
161
|
{
|
|
157
162
|
headers: {
|
|
@@ -162,15 +167,54 @@ export function usePaymentCheckout(
|
|
|
162
167
|
},
|
|
163
168
|
},
|
|
164
169
|
);
|
|
165
|
-
|
|
166
|
-
|
|
170
|
+
|
|
171
|
+
const result = res?.data?.data;
|
|
172
|
+
const status = result?.message?.toLowerCase() ?? "";
|
|
173
|
+
if (status.includes("pending")) {
|
|
174
|
+
onPending?.(result);
|
|
175
|
+
} else if (status.includes("success") && result?.paid) {
|
|
176
|
+
onSuccess?.(result.transactionRef);
|
|
177
|
+
} else {
|
|
178
|
+
onError?.(result?.message ?? "Payment could not be verified");
|
|
179
|
+
}
|
|
167
180
|
} catch (error) {
|
|
168
181
|
console.log("FETCH ERROR:", error);
|
|
182
|
+
onError?.(error);
|
|
169
183
|
} finally {
|
|
170
184
|
setLoading(false);
|
|
171
185
|
}
|
|
172
186
|
};
|
|
173
187
|
|
|
188
|
+
// const verifyUssd = async () => {
|
|
189
|
+
// try {
|
|
190
|
+
// setLoading(true);
|
|
191
|
+
// const payload = {
|
|
192
|
+
// codeReference: ussdBankResponse?.codeRef,
|
|
193
|
+
// amount: ussdBankResponse?.amount,
|
|
194
|
+
// };
|
|
195
|
+
// const res = await axios.post(
|
|
196
|
+
// "https://api.fairsurepay.com/api/pub/ussd-status",
|
|
197
|
+
// payload,
|
|
198
|
+
// {
|
|
199
|
+
// headers: {
|
|
200
|
+
// Accept: "application/json",
|
|
201
|
+
// "Content-Type": "application/json",
|
|
202
|
+
// publickey: "LIVE_7AXSCCY8R3HABAN14QP7",
|
|
203
|
+
// "User-Agent": "PostmanRuntime/7.51.0",
|
|
204
|
+
// },
|
|
205
|
+
// },
|
|
206
|
+
// );
|
|
207
|
+
// console.log("USSD PAYMENT RESPONSE", res);
|
|
208
|
+
|
|
209
|
+
// onSuccess?.(cardDetails.transactionRef);
|
|
210
|
+
// setLoading(false);
|
|
211
|
+
// } catch (error) {
|
|
212
|
+
// console.log("FETCH ERROR:", error);
|
|
213
|
+
// } finally {
|
|
214
|
+
// setLoading(false);
|
|
215
|
+
// }
|
|
216
|
+
// };
|
|
217
|
+
|
|
174
218
|
useEffect(() => {
|
|
175
219
|
if (selectedBank) {
|
|
176
220
|
generateUssdCode();
|
|
@@ -342,13 +386,13 @@ export function usePaymentCheckout(
|
|
|
342
386
|
setLoading(false);
|
|
343
387
|
}
|
|
344
388
|
};
|
|
389
|
+
|
|
345
390
|
const verifyCardPayment = async () => {
|
|
346
391
|
setLoading(true);
|
|
347
392
|
try {
|
|
348
393
|
const payload = {
|
|
349
394
|
transactionId: cardDetails?.transactionRef,
|
|
350
395
|
paymentId: cardDetails?.paymentId,
|
|
351
|
-
// eciFlag: "07",
|
|
352
396
|
otp: otp,
|
|
353
397
|
customerName,
|
|
354
398
|
customerPhone,
|
|
@@ -366,14 +410,83 @@ export function usePaymentCheckout(
|
|
|
366
410
|
},
|
|
367
411
|
},
|
|
368
412
|
);
|
|
369
|
-
|
|
370
|
-
|
|
413
|
+
|
|
414
|
+
const result = res?.data?.data;
|
|
415
|
+
const status = result?.message?.toLowerCase() ?? "";
|
|
416
|
+
|
|
417
|
+
if (status.includes("pending")) {
|
|
418
|
+
onPending?.(result);
|
|
419
|
+
} else if (status.includes("success") || result?.paid) {
|
|
420
|
+
onSuccess?.(cardDetails.transactionRef);
|
|
421
|
+
} else {
|
|
422
|
+
onError?.(result?.message ?? "Card payment could not be verified");
|
|
423
|
+
}
|
|
371
424
|
return res?.data;
|
|
372
425
|
} catch (error) {
|
|
373
|
-
setLoading(false);
|
|
374
426
|
console.log("ERROR", error);
|
|
427
|
+
onError?.(error);
|
|
428
|
+
} finally {
|
|
429
|
+
setLoading(false);
|
|
375
430
|
}
|
|
376
431
|
};
|
|
432
|
+
// const verifyCardPayment = async () => {
|
|
433
|
+
// setLoading(true);
|
|
434
|
+
// try {
|
|
435
|
+
// const payload = {
|
|
436
|
+
// transactionId: cardDetails?.transactionRef,
|
|
437
|
+
// paymentId: cardDetails?.paymentId,
|
|
438
|
+
// // eciFlag: "07",
|
|
439
|
+
// otp: otp,
|
|
440
|
+
// customerName,
|
|
441
|
+
// customerPhone,
|
|
442
|
+
// customerEmail,
|
|
443
|
+
// };
|
|
444
|
+
// const res = await axios.post(
|
|
445
|
+
// "https://api.fairsurepay.com/api/pub/submit-otp",
|
|
446
|
+
// payload,
|
|
447
|
+
// {
|
|
448
|
+
// headers: {
|
|
449
|
+
// Accept: "application/json",
|
|
450
|
+
// "Content-Type": "application/json",
|
|
451
|
+
// publickey: "LIVE_7AXSCCY8R3HABAN14QP7",
|
|
452
|
+
// "User-Agent": "PostmanRuntime/7.36.0",
|
|
453
|
+
// },
|
|
454
|
+
// },
|
|
455
|
+
// );
|
|
456
|
+
// onSuccess?.(transferDetail.transactionReference);
|
|
457
|
+
// setLoading(false);
|
|
458
|
+
// return res?.data;
|
|
459
|
+
// } catch (error) {
|
|
460
|
+
// setLoading(false);
|
|
461
|
+
// console.log("ERROR", error);
|
|
462
|
+
// }
|
|
463
|
+
// };
|
|
464
|
+
// const verifyTransfer = async () => {
|
|
465
|
+
// setLoading(true);
|
|
466
|
+
// try {
|
|
467
|
+
// const res = await axios.get(
|
|
468
|
+
// `https://api.fairsurepay.com/api/pub/transfer-status?transactionReference=${transferDetail?.transactionReference}`,
|
|
469
|
+
// {
|
|
470
|
+
// timeout: 15000,
|
|
471
|
+
// headers: {
|
|
472
|
+
// Accept: "application/json",
|
|
473
|
+
// "Content-Type": "application/json",
|
|
474
|
+
// publickey: "LIVE_7AXSCCY8R3HABAN14QP7",
|
|
475
|
+
// "User-Agent": "PostmanRuntime/7.36.0",
|
|
476
|
+
// },
|
|
477
|
+
// },
|
|
478
|
+
// );
|
|
479
|
+
// console.log("RESPONSE", res);
|
|
480
|
+
|
|
481
|
+
// onSuccess?.(transferDetail.transactionReference);
|
|
482
|
+
// return res?.data;
|
|
483
|
+
// } catch (error: any) {
|
|
484
|
+
// console.log("Failed to Verify transfer", error.response?.data);
|
|
485
|
+
// } finally {
|
|
486
|
+
// setLoading(false);
|
|
487
|
+
// }
|
|
488
|
+
// };
|
|
489
|
+
|
|
377
490
|
const verifyTransfer = async () => {
|
|
378
491
|
setLoading(true);
|
|
379
492
|
try {
|
|
@@ -389,15 +502,25 @@ export function usePaymentCheckout(
|
|
|
389
502
|
},
|
|
390
503
|
},
|
|
391
504
|
);
|
|
392
|
-
|
|
505
|
+
|
|
506
|
+
const result = res?.data?.data;
|
|
507
|
+
const status = result?.message?.toLowerCase() ?? "";
|
|
508
|
+
|
|
509
|
+
if (status.includes("pending")) {
|
|
510
|
+
onPending?.(result);
|
|
511
|
+
} else if (status.includes("success") || result?.paid) {
|
|
512
|
+
onSuccess?.(transferDetail.transactionReference);
|
|
513
|
+
} else {
|
|
514
|
+
onError?.(result?.message ?? "Transfer could not be verified");
|
|
515
|
+
}
|
|
393
516
|
return res?.data;
|
|
394
517
|
} catch (error: any) {
|
|
395
518
|
console.log("Failed to Verify transfer", error.response?.data);
|
|
519
|
+
onError?.(error);
|
|
396
520
|
} finally {
|
|
397
521
|
setLoading(false);
|
|
398
522
|
}
|
|
399
523
|
};
|
|
400
|
-
|
|
401
524
|
const resetForm = () => {
|
|
402
525
|
setCardNumber("");
|
|
403
526
|
setExpiryDate("");
|
|
@@ -23,6 +23,8 @@ export function CheckoutProvider({ children }: { children: React.ReactNode }) {
|
|
|
23
23
|
amount={config.amount}
|
|
24
24
|
merchantName={config.merchantName}
|
|
25
25
|
onSuccess={config.onSuccess}
|
|
26
|
+
onPending={config.onPending}
|
|
27
|
+
onError={config.onError}
|
|
26
28
|
onClose={closeCheckout}
|
|
27
29
|
requestId={config.requestId}
|
|
28
30
|
customerEmail={config.customerEmail}
|
package/src/types.ts
CHANGED