xcel-paygate-sdk 1.0.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/LICENSE +21 -0
- package/README.md +225 -0
- package/dist/api/client.d.ts +19 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/client.js +215 -0
- package/dist/components/XcelPaymentFlow.d.ts +50 -0
- package/dist/components/XcelPaymentFlow.d.ts.map +1 -0
- package/dist/components/XcelPaymentFlow.js +125 -0
- package/dist/components/XcelPaymentScreen.d.ts +67 -0
- package/dist/components/XcelPaymentScreen.d.ts.map +1 -0
- package/dist/components/XcelPaymentScreen.js +356 -0
- package/dist/components/XcelPaymentWebView.d.ts +76 -0
- package/dist/components/XcelPaymentWebView.d.ts.map +1 -0
- package/dist/components/XcelPaymentWebView.js +413 -0
- package/dist/components/index.d.ts +12 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +14 -0
- package/dist/context/XcelPayGateProvider.d.ts +56 -0
- package/dist/context/XcelPayGateProvider.d.ts.map +1 -0
- package/dist/context/XcelPayGateProvider.js +107 -0
- package/dist/hooks/use-payment-completion.d.ts +75 -0
- package/dist/hooks/use-payment-completion.d.ts.map +1 -0
- package/dist/hooks/use-payment-completion.js +181 -0
- package/dist/hooks/use-xcel-paygate.d.ts +96 -0
- package/dist/hooks/use-xcel-paygate.d.ts.map +1 -0
- package/dist/hooks/use-xcel-paygate.js +279 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +65 -0
- package/dist/services/checkout.d.ts +32 -0
- package/dist/services/checkout.d.ts.map +1 -0
- package/dist/services/checkout.js +137 -0
- package/dist/services/xcel-wallet.d.ts +23 -0
- package/dist/services/xcel-wallet.d.ts.map +1 -0
- package/dist/services/xcel-wallet.js +107 -0
- package/dist/types/index.d.ts +373 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/payment-completion.d.ts +87 -0
- package/dist/utils/payment-completion.d.ts.map +1 -0
- package/dist/utils/payment-completion.js +110 -0
- package/dist/utils/payment-helpers.d.ts +55 -0
- package/dist/utils/payment-helpers.d.ts.map +1 -0
- package/dist/utils/payment-helpers.js +261 -0
- package/package.json +51 -0
- package/src/api/client.ts +326 -0
- package/src/components/XcelPaymentFlow.tsx +154 -0
- package/src/components/XcelPaymentScreen.tsx +477 -0
- package/src/components/XcelPaymentWebView.tsx +533 -0
- package/src/components/index.ts +14 -0
- package/src/context/XcelPayGateProvider.tsx +98 -0
- package/src/hooks/use-payment-completion.ts +225 -0
- package/src/hooks/use-xcel-paygate.ts +363 -0
- package/src/index.ts +70 -0
- package/src/services/checkout.ts +165 -0
- package/src/services/xcel-wallet.ts +175 -0
- package/src/types/index.ts +407 -0
- package/src/utils/payment-completion.ts +144 -0
- package/src/utils/payment-helpers.ts +287 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XcelPaymentScreen - Complete Payment UI Component
|
|
3
|
+
*
|
|
4
|
+
* Drop-in payment screen with full UI and logic.
|
|
5
|
+
* Just import and use - handles everything!
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { XcelPaymentScreen } from '@xcelapp/paygate-sdk';
|
|
10
|
+
*
|
|
11
|
+
* export default function PaymentPage() {
|
|
12
|
+
* return (
|
|
13
|
+
* <XcelPaymentScreen
|
|
14
|
+
* config={{
|
|
15
|
+
* merchantId: 'your-merchant-id',
|
|
16
|
+
* publicKey: 'your-public-key',
|
|
17
|
+
* }}
|
|
18
|
+
* onPaymentComplete={(result) => {
|
|
19
|
+
* console.log('Payment complete:', result);
|
|
20
|
+
* }}
|
|
21
|
+
* />
|
|
22
|
+
* );
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
import React from 'react';
|
|
27
|
+
import { ViewStyle, TextStyle } from 'react-native';
|
|
28
|
+
import type { XcelPayGateConfig, PaymentRequest, TransactionData } from '../types';
|
|
29
|
+
export interface XcelPaymentScreenProps {
|
|
30
|
+
/** SDK Configuration */
|
|
31
|
+
config?: XcelPayGateConfig;
|
|
32
|
+
/** Optional: Custom styles */
|
|
33
|
+
styles?: {
|
|
34
|
+
container?: ViewStyle;
|
|
35
|
+
button?: ViewStyle;
|
|
36
|
+
buttonText?: TextStyle;
|
|
37
|
+
input?: ViewStyle;
|
|
38
|
+
[key: string]: ViewStyle | TextStyle | undefined;
|
|
39
|
+
};
|
|
40
|
+
/** Optional: Pre-filled form values */
|
|
41
|
+
defaultValues?: {
|
|
42
|
+
amount?: string;
|
|
43
|
+
email?: string;
|
|
44
|
+
phone?: string;
|
|
45
|
+
description?: string;
|
|
46
|
+
};
|
|
47
|
+
/** Optional: Customize payment request */
|
|
48
|
+
paymentConfig?: Partial<Omit<PaymentRequest, 'amount' | 'currency'>>;
|
|
49
|
+
/** Called when payment link is generated */
|
|
50
|
+
onPaymentLinkGenerated?: (paymentLink: string, paymentCode: string) => void;
|
|
51
|
+
/** Called when payment is complete (success/fail) */
|
|
52
|
+
onPaymentComplete?: (transaction: TransactionData) => void;
|
|
53
|
+
/** Called on error */
|
|
54
|
+
onError?: (error: Error) => void;
|
|
55
|
+
/** Show status check button */
|
|
56
|
+
showStatusButton?: boolean;
|
|
57
|
+
/** Enable auto-polling */
|
|
58
|
+
enablePolling?: boolean;
|
|
59
|
+
/** Custom button text */
|
|
60
|
+
buttonText?: string;
|
|
61
|
+
/** Currency (default: XAF) */
|
|
62
|
+
currency?: string;
|
|
63
|
+
/** Hide form, only show button */
|
|
64
|
+
minimalMode?: boolean;
|
|
65
|
+
}
|
|
66
|
+
export declare function XcelPaymentScreen({ config, styles: customStyles, defaultValues, paymentConfig, onPaymentLinkGenerated, onPaymentComplete, onError, showStatusButton, enablePolling, buttonText, currency, minimalMode, }: XcelPaymentScreenProps): React.JSX.Element;
|
|
67
|
+
//# sourceMappingURL=XcelPaymentScreen.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XcelPaymentScreen.d.ts","sourceRoot":"","sources":["../../src/components/XcelPaymentScreen.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,EASL,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAEnF,MAAM,WAAW,sBAAsB;IACrC,wBAAwB;IACxB,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAE3B,8BAA8B;IAC9B,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,MAAM,CAAC,EAAE,SAAS,CAAC;QACnB,UAAU,CAAC,EAAE,SAAS,CAAC;QACvB,KAAK,CAAC,EAAE,SAAS,CAAC;QAClB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;KAClD,CAAC;IAEF,uCAAuC;IACvC,aAAa,CAAC,EAAE;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IAEF,0CAA0C;IAC1C,aAAa,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC,cAAc,EAAE,QAAQ,GAAG,UAAU,CAAC,CAAC,CAAC;IAErE,4CAA4C;IAC5C,sBAAsB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAE5E,qDAAqD;IACrD,iBAAiB,CAAC,EAAE,CAAC,WAAW,EAAE,eAAe,KAAK,IAAI,CAAC;IAE3D,sBAAsB;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC,+BAA+B;IAC/B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,0BAA0B;IAC1B,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,yBAAyB;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,8BAA8B;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAElB,kCAAkC;IAClC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,MAAM,EAAE,YAAiB,EACzB,aAAkB,EAClB,aAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,OAAO,EACP,gBAAuB,EACvB,aAAqB,EACrB,UAAoC,EACpC,QAAgB,EAChB,WAAmB,GACpB,EAAE,sBAAsB,qBAiPxB"}
|
|
@@ -0,0 +1,356 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* XcelPaymentScreen - Complete Payment UI Component
|
|
4
|
+
*
|
|
5
|
+
* Drop-in payment screen with full UI and logic.
|
|
6
|
+
* Just import and use - handles everything!
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import { XcelPaymentScreen } from '@xcelapp/paygate-sdk';
|
|
11
|
+
*
|
|
12
|
+
* export default function PaymentPage() {
|
|
13
|
+
* return (
|
|
14
|
+
* <XcelPaymentScreen
|
|
15
|
+
* config={{
|
|
16
|
+
* merchantId: 'your-merchant-id',
|
|
17
|
+
* publicKey: 'your-public-key',
|
|
18
|
+
* }}
|
|
19
|
+
* onPaymentComplete={(result) => {
|
|
20
|
+
* console.log('Payment complete:', result);
|
|
21
|
+
* }}
|
|
22
|
+
* />
|
|
23
|
+
* );
|
|
24
|
+
* }
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
28
|
+
if (k2 === undefined) k2 = k;
|
|
29
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
30
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
31
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
32
|
+
}
|
|
33
|
+
Object.defineProperty(o, k2, desc);
|
|
34
|
+
}) : (function(o, m, k, k2) {
|
|
35
|
+
if (k2 === undefined) k2 = k;
|
|
36
|
+
o[k2] = m[k];
|
|
37
|
+
}));
|
|
38
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
39
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
40
|
+
}) : function(o, v) {
|
|
41
|
+
o["default"] = v;
|
|
42
|
+
});
|
|
43
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
44
|
+
var ownKeys = function(o) {
|
|
45
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
46
|
+
var ar = [];
|
|
47
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
48
|
+
return ar;
|
|
49
|
+
};
|
|
50
|
+
return ownKeys(o);
|
|
51
|
+
};
|
|
52
|
+
return function (mod) {
|
|
53
|
+
if (mod && mod.__esModule) return mod;
|
|
54
|
+
var result = {};
|
|
55
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
56
|
+
__setModuleDefault(result, mod);
|
|
57
|
+
return result;
|
|
58
|
+
};
|
|
59
|
+
})();
|
|
60
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
61
|
+
exports.XcelPaymentScreen = XcelPaymentScreen;
|
|
62
|
+
const react_1 = __importStar(require("react"));
|
|
63
|
+
const react_native_1 = require("react-native");
|
|
64
|
+
const use_xcel_paygate_1 = require("../hooks/use-xcel-paygate");
|
|
65
|
+
function XcelPaymentScreen({ config, styles: customStyles = {}, defaultValues = {}, paymentConfig = {}, onPaymentLinkGenerated, onPaymentComplete, onError, showStatusButton = true, enablePolling = false, buttonText = 'Generate Payment Link', currency = 'XAF', minimalMode = false, }) {
|
|
66
|
+
// Form state
|
|
67
|
+
const [amount, setAmount] = (0, react_1.useState)(defaultValues.amount || '1000');
|
|
68
|
+
const [email, setEmail] = (0, react_1.useState)(defaultValues.email || '');
|
|
69
|
+
const [phone, setPhone] = (0, react_1.useState)(defaultValues.phone || '');
|
|
70
|
+
const [description, setDescription] = (0, react_1.useState)(defaultValues.description || '');
|
|
71
|
+
// SDK Hook
|
|
72
|
+
const { initiatePayment, checkStatus, loading, error, paymentLink, paymentCode, transaction, } = (0, use_xcel_paygate_1.useCheckout)(config || undefined);
|
|
73
|
+
// Optional polling - only if enabled
|
|
74
|
+
const pollingEnabled = enablePolling && !!paymentCode;
|
|
75
|
+
const pollingResult = pollingEnabled
|
|
76
|
+
? (0, use_xcel_paygate_1.usePaymentPolling)(config || null, paymentCode, {
|
|
77
|
+
enabled: true,
|
|
78
|
+
maxAttempts: 24,
|
|
79
|
+
intervalMs: 5000,
|
|
80
|
+
})
|
|
81
|
+
: { result: null, isPolling: false };
|
|
82
|
+
const { result, isPolling } = pollingResult;
|
|
83
|
+
// Handle payment initiation
|
|
84
|
+
const handlePay = async () => {
|
|
85
|
+
try {
|
|
86
|
+
const response = await initiatePayment({
|
|
87
|
+
amount,
|
|
88
|
+
currency,
|
|
89
|
+
client_transaction_id: `TXN-${Date.now()}`,
|
|
90
|
+
customer_email: email,
|
|
91
|
+
customer_phone: phone,
|
|
92
|
+
description: description,
|
|
93
|
+
channel: 'WEB',
|
|
94
|
+
redirect_url: 'https://business.xcelapp.com/#/auth',
|
|
95
|
+
...paymentConfig,
|
|
96
|
+
});
|
|
97
|
+
const link = response.data.payment_link;
|
|
98
|
+
const code = response.data.payment_code;
|
|
99
|
+
console.log('✓ Payment Link Generated:', link);
|
|
100
|
+
console.log('✓ Payment Code:', code);
|
|
101
|
+
onPaymentLinkGenerated === null || onPaymentLinkGenerated === void 0 ? void 0 : onPaymentLinkGenerated(link, code);
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
const errorObj = err instanceof Error ? err : new Error('Payment failed');
|
|
105
|
+
console.error('Payment Error:', errorObj);
|
|
106
|
+
onError === null || onError === void 0 ? void 0 : onError(errorObj);
|
|
107
|
+
react_native_1.Alert.alert('Error', errorObj.message);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
// Handle status check
|
|
111
|
+
const handleCheckStatus = async () => {
|
|
112
|
+
if (!paymentCode) {
|
|
113
|
+
react_native_1.Alert.alert('Error', 'No payment code available');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
try {
|
|
117
|
+
const txn = await checkStatus();
|
|
118
|
+
react_native_1.Alert.alert('Payment Status', `Status: ${txn.status}\nAmount: ${txn.amount} ${txn.currency}`);
|
|
119
|
+
if (onPaymentComplete && (txn.status === 'SUCCESS' || txn.status === 'FAILED')) {
|
|
120
|
+
onPaymentComplete(txn);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch (err) {
|
|
124
|
+
const errorObj = err instanceof Error ? err : new Error('Status check failed');
|
|
125
|
+
onError === null || onError === void 0 ? void 0 : onError(errorObj);
|
|
126
|
+
react_native_1.Alert.alert('Error', errorObj.message);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
// Handle polling result - result is PaymentResult, not TransactionData
|
|
130
|
+
// We don't call onPaymentComplete here since it expects TransactionData
|
|
131
|
+
// User should use check status manually if using polling
|
|
132
|
+
// Minimal mode - just show payment link if available
|
|
133
|
+
if (minimalMode && paymentLink) {
|
|
134
|
+
return (<react_native_1.View style={[styles.container, customStyles.container]}>
|
|
135
|
+
<react_native_1.Text style={styles.title}>Payment Link Ready</react_native_1.Text>
|
|
136
|
+
<react_native_1.Text style={styles.paymentLink}>{paymentLink}</react_native_1.Text>
|
|
137
|
+
<react_native_1.Text style={styles.label}>Payment Code: {paymentCode}</react_native_1.Text>
|
|
138
|
+
{showStatusButton && (<react_native_1.Pressable style={[styles.secondaryButton, customStyles.button]} onPress={handleCheckStatus}>
|
|
139
|
+
<react_native_1.Text style={[styles.secondaryButtonText, customStyles.buttonText]}>
|
|
140
|
+
Check Status
|
|
141
|
+
</react_native_1.Text>
|
|
142
|
+
</react_native_1.Pressable>)}
|
|
143
|
+
</react_native_1.View>);
|
|
144
|
+
}
|
|
145
|
+
return (<react_native_1.ScrollView style={[styles.container, customStyles.container]}>
|
|
146
|
+
<react_native_1.View style={styles.content}>
|
|
147
|
+
<react_native_1.Text style={styles.title}>XCEL PayGate</react_native_1.Text>
|
|
148
|
+
<react_native_1.Text style={styles.subtitle}>Secure Payment Processing</react_native_1.Text>
|
|
149
|
+
|
|
150
|
+
{/* Payment Form */}
|
|
151
|
+
{!minimalMode && (<react_native_1.View style={styles.section}>
|
|
152
|
+
<react_native_1.Text style={styles.sectionTitle}>Payment Details</react_native_1.Text>
|
|
153
|
+
|
|
154
|
+
<react_native_1.Text style={styles.label}>Amount ({currency})</react_native_1.Text>
|
|
155
|
+
<react_native_1.TextInput style={[styles.input, customStyles.input]} value={amount} onChangeText={setAmount} placeholder="1000" keyboardType="decimal-pad"/>
|
|
156
|
+
|
|
157
|
+
<react_native_1.Text style={styles.label}>Customer Email (Optional)</react_native_1.Text>
|
|
158
|
+
<react_native_1.TextInput style={[styles.input, customStyles.input]} value={email} onChangeText={setEmail} placeholder="customer@example.com" keyboardType="email-address" autoCapitalize="none"/>
|
|
159
|
+
|
|
160
|
+
<react_native_1.Text style={styles.label}>Customer Phone (Optional)</react_native_1.Text>
|
|
161
|
+
<react_native_1.TextInput style={[styles.input, customStyles.input]} value={phone} onChangeText={setPhone} placeholder="237233429972" keyboardType="phone-pad"/>
|
|
162
|
+
|
|
163
|
+
<react_native_1.Text style={styles.label}>Description (Optional)</react_native_1.Text>
|
|
164
|
+
<react_native_1.TextInput style={[styles.input, customStyles.input]} value={description} onChangeText={setDescription} placeholder="Payment description"/>
|
|
165
|
+
</react_native_1.View>)}
|
|
166
|
+
|
|
167
|
+
{/* Generate Payment Button */}
|
|
168
|
+
<react_native_1.Pressable style={[
|
|
169
|
+
styles.button,
|
|
170
|
+
customStyles.button,
|
|
171
|
+
loading && styles.buttonDisabled,
|
|
172
|
+
]} onPress={handlePay} disabled={loading}>
|
|
173
|
+
{loading ? (<react_native_1.ActivityIndicator color="#fff"/>) : (<react_native_1.Text style={[styles.buttonText, customStyles.buttonText]}>
|
|
174
|
+
{buttonText}
|
|
175
|
+
</react_native_1.Text>)}
|
|
176
|
+
</react_native_1.Pressable>
|
|
177
|
+
|
|
178
|
+
{/* Payment Result Section */}
|
|
179
|
+
{paymentCode && (<react_native_1.View style={styles.resultSection}>
|
|
180
|
+
<react_native_1.Text style={styles.resultTitle}>✓ Payment Created</react_native_1.Text>
|
|
181
|
+
|
|
182
|
+
<react_native_1.View style={styles.resultRow}>
|
|
183
|
+
<react_native_1.Text style={styles.resultLabel}>Payment Code:</react_native_1.Text>
|
|
184
|
+
<react_native_1.Text style={styles.resultValue}>{paymentCode}</react_native_1.Text>
|
|
185
|
+
</react_native_1.View>
|
|
186
|
+
|
|
187
|
+
{paymentLink && (<react_native_1.View style={styles.resultRow}>
|
|
188
|
+
<react_native_1.Text style={styles.resultLabel}>Payment Link:</react_native_1.Text>
|
|
189
|
+
<react_native_1.Text style={[styles.resultValue, styles.linkText]} numberOfLines={1}>
|
|
190
|
+
{paymentLink}
|
|
191
|
+
</react_native_1.Text>
|
|
192
|
+
</react_native_1.View>)}
|
|
193
|
+
|
|
194
|
+
{transaction && (<>
|
|
195
|
+
<react_native_1.View style={styles.resultRow}>
|
|
196
|
+
<react_native_1.Text style={styles.resultLabel}>Status:</react_native_1.Text>
|
|
197
|
+
<react_native_1.Text style={[styles.resultValue, styles.statusText]}>
|
|
198
|
+
{transaction.status}
|
|
199
|
+
</react_native_1.Text>
|
|
200
|
+
</react_native_1.View>
|
|
201
|
+
|
|
202
|
+
<react_native_1.View style={styles.resultRow}>
|
|
203
|
+
<react_native_1.Text style={styles.resultLabel}>Transaction ID:</react_native_1.Text>
|
|
204
|
+
<react_native_1.Text style={styles.resultValue}>
|
|
205
|
+
{transaction.transaction_id}
|
|
206
|
+
</react_native_1.Text>
|
|
207
|
+
</react_native_1.View>
|
|
208
|
+
</>)}
|
|
209
|
+
|
|
210
|
+
{isPolling && (<react_native_1.Text style={styles.pollingText}>Checking payment status...</react_native_1.Text>)}
|
|
211
|
+
|
|
212
|
+
{/* Manual Status Check */}
|
|
213
|
+
{showStatusButton && (<react_native_1.Pressable style={[styles.secondaryButton, customStyles.button]} onPress={handleCheckStatus}>
|
|
214
|
+
<react_native_1.Text style={[styles.secondaryButtonText, customStyles.buttonText]}>
|
|
215
|
+
Check Status Manually
|
|
216
|
+
</react_native_1.Text>
|
|
217
|
+
</react_native_1.Pressable>)}
|
|
218
|
+
</react_native_1.View>)}
|
|
219
|
+
|
|
220
|
+
{/* Error Display */}
|
|
221
|
+
{error && (<react_native_1.View style={styles.errorBox}>
|
|
222
|
+
<react_native_1.Text style={styles.errorText}>⚠️ {error.message}</react_native_1.Text>
|
|
223
|
+
</react_native_1.View>)}
|
|
224
|
+
</react_native_1.View>
|
|
225
|
+
</react_native_1.ScrollView>);
|
|
226
|
+
}
|
|
227
|
+
const styles = react_native_1.StyleSheet.create({
|
|
228
|
+
container: {
|
|
229
|
+
flex: 1,
|
|
230
|
+
backgroundColor: '#fff',
|
|
231
|
+
},
|
|
232
|
+
content: {
|
|
233
|
+
padding: 20,
|
|
234
|
+
},
|
|
235
|
+
title: {
|
|
236
|
+
fontSize: 24,
|
|
237
|
+
fontWeight: 'bold',
|
|
238
|
+
marginBottom: 8,
|
|
239
|
+
textAlign: 'center',
|
|
240
|
+
color: '#000',
|
|
241
|
+
},
|
|
242
|
+
subtitle: {
|
|
243
|
+
fontSize: 16,
|
|
244
|
+
marginBottom: 24,
|
|
245
|
+
textAlign: 'center',
|
|
246
|
+
color: '#666',
|
|
247
|
+
},
|
|
248
|
+
section: {
|
|
249
|
+
marginBottom: 24,
|
|
250
|
+
padding: 16,
|
|
251
|
+
borderRadius: 8,
|
|
252
|
+
backgroundColor: '#f5f5f5',
|
|
253
|
+
},
|
|
254
|
+
sectionTitle: {
|
|
255
|
+
fontSize: 18,
|
|
256
|
+
fontWeight: '600',
|
|
257
|
+
marginBottom: 16,
|
|
258
|
+
color: '#000',
|
|
259
|
+
},
|
|
260
|
+
label: {
|
|
261
|
+
marginBottom: 8,
|
|
262
|
+
fontWeight: '600',
|
|
263
|
+
color: '#333',
|
|
264
|
+
},
|
|
265
|
+
input: {
|
|
266
|
+
backgroundColor: '#fff',
|
|
267
|
+
borderWidth: 1,
|
|
268
|
+
borderColor: '#ddd',
|
|
269
|
+
borderRadius: 8,
|
|
270
|
+
padding: 12,
|
|
271
|
+
marginBottom: 16,
|
|
272
|
+
fontSize: 16,
|
|
273
|
+
},
|
|
274
|
+
button: {
|
|
275
|
+
backgroundColor: '#007AFF',
|
|
276
|
+
padding: 16,
|
|
277
|
+
borderRadius: 8,
|
|
278
|
+
alignItems: 'center',
|
|
279
|
+
marginBottom: 16,
|
|
280
|
+
},
|
|
281
|
+
buttonDisabled: {
|
|
282
|
+
opacity: 0.6,
|
|
283
|
+
},
|
|
284
|
+
buttonText: {
|
|
285
|
+
color: '#fff',
|
|
286
|
+
fontSize: 16,
|
|
287
|
+
fontWeight: '600',
|
|
288
|
+
},
|
|
289
|
+
secondaryButton: {
|
|
290
|
+
backgroundColor: '#f0f0f0',
|
|
291
|
+
padding: 12,
|
|
292
|
+
borderRadius: 8,
|
|
293
|
+
alignItems: 'center',
|
|
294
|
+
marginTop: 8,
|
|
295
|
+
},
|
|
296
|
+
secondaryButtonText: {
|
|
297
|
+
color: '#007AFF',
|
|
298
|
+
fontSize: 14,
|
|
299
|
+
fontWeight: '600',
|
|
300
|
+
},
|
|
301
|
+
resultSection: {
|
|
302
|
+
padding: 16,
|
|
303
|
+
borderRadius: 8,
|
|
304
|
+
backgroundColor: '#e8f5e9',
|
|
305
|
+
marginBottom: 16,
|
|
306
|
+
},
|
|
307
|
+
resultTitle: {
|
|
308
|
+
fontSize: 18,
|
|
309
|
+
fontWeight: 'bold',
|
|
310
|
+
marginBottom: 16,
|
|
311
|
+
color: '#2e7d32',
|
|
312
|
+
},
|
|
313
|
+
resultRow: {
|
|
314
|
+
marginBottom: 12,
|
|
315
|
+
},
|
|
316
|
+
resultLabel: {
|
|
317
|
+
fontWeight: '600',
|
|
318
|
+
marginBottom: 4,
|
|
319
|
+
color: '#333',
|
|
320
|
+
},
|
|
321
|
+
resultValue: {
|
|
322
|
+
fontSize: 14,
|
|
323
|
+
color: '#000',
|
|
324
|
+
},
|
|
325
|
+
linkText: {
|
|
326
|
+
fontSize: 12,
|
|
327
|
+
color: '#007AFF',
|
|
328
|
+
},
|
|
329
|
+
statusText: {
|
|
330
|
+
fontWeight: 'bold',
|
|
331
|
+
fontSize: 16,
|
|
332
|
+
},
|
|
333
|
+
pollingText: {
|
|
334
|
+
marginTop: 12,
|
|
335
|
+
fontStyle: 'italic',
|
|
336
|
+
color: '#666',
|
|
337
|
+
},
|
|
338
|
+
errorBox: {
|
|
339
|
+
backgroundColor: '#ffebee',
|
|
340
|
+
padding: 16,
|
|
341
|
+
borderRadius: 8,
|
|
342
|
+
marginBottom: 16,
|
|
343
|
+
},
|
|
344
|
+
errorText: {
|
|
345
|
+
color: '#c62828',
|
|
346
|
+
fontWeight: '500',
|
|
347
|
+
},
|
|
348
|
+
paymentLink: {
|
|
349
|
+
fontSize: 12,
|
|
350
|
+
color: '#007AFF',
|
|
351
|
+
marginBottom: 16,
|
|
352
|
+
padding: 12,
|
|
353
|
+
backgroundColor: '#f5f5f5',
|
|
354
|
+
borderRadius: 8,
|
|
355
|
+
},
|
|
356
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XcelPaymentWebView - WebView Payment Handler Component
|
|
3
|
+
*
|
|
4
|
+
* Handles payment flow in a WebView with automatic status detection.
|
|
5
|
+
* Drop this component in your navigation stack and it handles everything!
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { XcelPaymentWebView } from '@xcelapp/paygate-sdk';
|
|
10
|
+
*
|
|
11
|
+
* export default function PaymentWebViewScreen({ route }) {
|
|
12
|
+
* const { paymentLink, paymentCode } = route.params;
|
|
13
|
+
*
|
|
14
|
+
* return (
|
|
15
|
+
* <XcelPaymentWebView
|
|
16
|
+
* paymentLink={paymentLink}
|
|
17
|
+
* paymentCode={paymentCode}
|
|
18
|
+
* onSuccess={(result) => {
|
|
19
|
+
* console.log('Payment successful!', result);
|
|
20
|
+
* navigation.navigate('Receipt', { result });
|
|
21
|
+
* }}
|
|
22
|
+
* onFailure={(result) => {
|
|
23
|
+
* console.log('Payment failed', result);
|
|
24
|
+
* navigation.goBack();
|
|
25
|
+
* }}
|
|
26
|
+
* />
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
import React from 'react';
|
|
32
|
+
import { ViewStyle, TextStyle } from 'react-native';
|
|
33
|
+
export interface PaymentResult {
|
|
34
|
+
status: 'SUCCESS' | 'FAILED' | 'PENDING';
|
|
35
|
+
paymentCode?: string;
|
|
36
|
+
transactionId?: string;
|
|
37
|
+
url?: string;
|
|
38
|
+
bodyText?: string;
|
|
39
|
+
}
|
|
40
|
+
export interface XcelPaymentWebViewProps {
|
|
41
|
+
/** Payment link URL */
|
|
42
|
+
paymentLink: string;
|
|
43
|
+
/** Payment code for tracking */
|
|
44
|
+
paymentCode?: string;
|
|
45
|
+
/** Additional payment details */
|
|
46
|
+
amount?: string;
|
|
47
|
+
currency?: string;
|
|
48
|
+
description?: string;
|
|
49
|
+
/** Called when payment succeeds */
|
|
50
|
+
onSuccess?: (result: PaymentResult) => void;
|
|
51
|
+
/** Called when payment fails */
|
|
52
|
+
onFailure?: (result: PaymentResult) => void;
|
|
53
|
+
/** Called when payment is pending */
|
|
54
|
+
onPending?: (result: PaymentResult) => void;
|
|
55
|
+
/** Called when user closes/cancels */
|
|
56
|
+
onCancel?: () => void;
|
|
57
|
+
/** Custom header component */
|
|
58
|
+
renderHeader?: () => React.ReactNode;
|
|
59
|
+
/** Custom loading component */
|
|
60
|
+
renderLoading?: () => React.ReactNode;
|
|
61
|
+
/** Custom styles */
|
|
62
|
+
styles?: {
|
|
63
|
+
container?: ViewStyle;
|
|
64
|
+
header?: ViewStyle;
|
|
65
|
+
backButton?: ViewStyle;
|
|
66
|
+
backButtonText?: TextStyle;
|
|
67
|
+
webview?: ViewStyle;
|
|
68
|
+
[key: string]: ViewStyle | TextStyle | undefined;
|
|
69
|
+
};
|
|
70
|
+
/** Success detection timeout (ms) */
|
|
71
|
+
successTimeout?: number;
|
|
72
|
+
/** Show back button */
|
|
73
|
+
showBackButton?: boolean;
|
|
74
|
+
}
|
|
75
|
+
export declare function XcelPaymentWebView({ paymentLink, paymentCode, amount, currency, description, onSuccess, onFailure, onPending, onCancel, renderHeader, renderLoading, styles: customStyles, successTimeout, showBackButton, }: XcelPaymentWebViewProps): React.JSX.Element;
|
|
76
|
+
//# sourceMappingURL=XcelPaymentWebView.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"XcelPaymentWebView.d.ts","sourceRoot":"","sources":["../../src/components/XcelPaymentWebView.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,KAAmD,MAAM,OAAO,CAAC;AACxE,OAAO,EAML,SAAS,EACT,SAAS,EACV,MAAM,cAAc,CAAC;AAEtB,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,SAAS,GAAG,QAAQ,GAAG,SAAS,CAAC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,uBAAuB;IACtC,uBAAuB;IACvB,WAAW,EAAE,MAAM,CAAC;IAEpB,gCAAgC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,iCAAiC;IACjC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,mCAAmC;IACnC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAE5C,gCAAgC;IAChC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAE5C,qCAAqC;IACrC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAE5C,sCAAsC;IACtC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IAEtB,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IAErC,+BAA+B;IAC/B,aAAa,CAAC,EAAE,MAAM,KAAK,CAAC,SAAS,CAAC;IAEtC,oBAAoB;IACpB,MAAM,CAAC,EAAE;QACP,SAAS,CAAC,EAAE,SAAS,CAAC;QACtB,MAAM,CAAC,EAAE,SAAS,CAAC;QACnB,UAAU,CAAC,EAAE,SAAS,CAAC;QACvB,cAAc,CAAC,EAAE,SAAS,CAAC;QAC3B,OAAO,CAAC,EAAE,SAAS,CAAC;QACpB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;KAClD,CAAC;IAEF,qCAAqC;IACrC,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,uBAAuB;IACvB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAAC,EACjC,WAAW,EACX,WAAW,EACX,MAAM,EACN,QAAQ,EACR,WAAW,EACX,SAAS,EACT,SAAS,EACT,SAAS,EACT,QAAQ,EACR,YAAY,EACZ,aAAa,EACb,MAAM,EAAE,YAAiB,EACzB,cAAsB,EACtB,cAAqB,GACtB,EAAE,uBAAuB,qBA4VzB"}
|