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,326 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreateXcelTransactionRequest,
|
|
3
|
+
GenerateDynamicLinkRequest,
|
|
4
|
+
GenerateDynamicLinkResponse,
|
|
5
|
+
GeneratePaymentLinkRequest,
|
|
6
|
+
GeneratePaymentLinkResponse,
|
|
7
|
+
MerchantDetails,
|
|
8
|
+
MerchantFeesResponse,
|
|
9
|
+
MerchantProductsResponse,
|
|
10
|
+
TransactionDataResponse,
|
|
11
|
+
XcelAccountVerificationResponse,
|
|
12
|
+
XcelPayGateConfig,
|
|
13
|
+
XcelTransactionResponse,
|
|
14
|
+
} from "../types";
|
|
15
|
+
|
|
16
|
+
const DEFAULT_BASE_URL = "https://api.xcelapp.com";
|
|
17
|
+
const PAYGATE_BASE_URL = "https://paygate.xcelapp.com";
|
|
18
|
+
|
|
19
|
+
export class XcelPayGateClient {
|
|
20
|
+
private config: Required<XcelPayGateConfig>;
|
|
21
|
+
|
|
22
|
+
constructor(config: XcelPayGateConfig) {
|
|
23
|
+
this.config = {
|
|
24
|
+
...config,
|
|
25
|
+
baseUrl: config.baseUrl || DEFAULT_BASE_URL,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private getHeaders(): Record<string, string> {
|
|
30
|
+
return {
|
|
31
|
+
"Content-Type": "application/json",
|
|
32
|
+
"x-merchant-id": this.config.merchantId,
|
|
33
|
+
"x-public-key": this.config.publicKey,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async generatePaymentLink(
|
|
38
|
+
request: GeneratePaymentLinkRequest
|
|
39
|
+
): Promise<GeneratePaymentLinkResponse> {
|
|
40
|
+
const headers = this.getHeaders();
|
|
41
|
+
const url = `${this.config.baseUrl}/transactions-service/paygate/generate-payment-link`;
|
|
42
|
+
|
|
43
|
+
console.log('=== [XcelPayGate] Generate Payment Link Request ===');
|
|
44
|
+
console.log('URL:', url);
|
|
45
|
+
console.log('Headers:', JSON.stringify(headers, null, 2));
|
|
46
|
+
console.log('Payload:', JSON.stringify(request, null, 2));
|
|
47
|
+
|
|
48
|
+
const response = await fetch(url, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers,
|
|
51
|
+
body: JSON.stringify(request),
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
console.log('=== [XcelPayGate] Generate Payment Link Response ===');
|
|
55
|
+
console.log('Status Code:', response.status);
|
|
56
|
+
console.log('Status Text:', response.statusText);
|
|
57
|
+
console.log('Response Headers:', JSON.stringify(Object.fromEntries(response.headers.entries()), null, 2));
|
|
58
|
+
|
|
59
|
+
if (!response.ok) {
|
|
60
|
+
const errorText = await response.text();
|
|
61
|
+
console.log('Error Response Body:', errorText);
|
|
62
|
+
let errorMessage = `Failed to generate payment link: ${response.statusText}`;
|
|
63
|
+
try {
|
|
64
|
+
const errorData = JSON.parse(errorText);
|
|
65
|
+
console.log('Parsed Error Data:', JSON.stringify(errorData, null, 2));
|
|
66
|
+
errorMessage =
|
|
67
|
+
errorData.message || errorData.status_reason || errorMessage;
|
|
68
|
+
} catch {
|
|
69
|
+
errorMessage = errorText || errorMessage;
|
|
70
|
+
}
|
|
71
|
+
throw new Error(errorMessage);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const responseData = await response.json();
|
|
75
|
+
console.log('Success Response Body:', JSON.stringify(responseData, null, 2));
|
|
76
|
+
|
|
77
|
+
if (responseData.data) {
|
|
78
|
+
console.log('--- Response Data Details ---');
|
|
79
|
+
console.log('Transaction ID:', responseData.data.transaction_id);
|
|
80
|
+
console.log('Payment Code:', responseData.data.payment_code);
|
|
81
|
+
console.log('Payment Link:', responseData.data.payment_link);
|
|
82
|
+
console.log('Amount:', responseData.data.amount);
|
|
83
|
+
console.log('Currency:', responseData.data.currency);
|
|
84
|
+
console.log('Expires At:', responseData.data.expires_at);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log('=== End Generate Payment Link Response ===\n');
|
|
88
|
+
|
|
89
|
+
return responseData;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
async getTransactionData(
|
|
93
|
+
paymentCode: string
|
|
94
|
+
): Promise<TransactionDataResponse> {
|
|
95
|
+
const headers = this.getHeaders();
|
|
96
|
+
console.log('[XcelPayGate] Get Transaction Data - Headers:', JSON.stringify(headers, null, 2));
|
|
97
|
+
console.log('[XcelPayGate] Get Transaction Data - Payment Code:', paymentCode);
|
|
98
|
+
|
|
99
|
+
const response = await fetch(
|
|
100
|
+
`${this.config.baseUrl}/transactions-service/paygate/get-transaction-data/${paymentCode}`,
|
|
101
|
+
{
|
|
102
|
+
method: "GET",
|
|
103
|
+
headers,
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
throw new Error(`Failed to get transaction data: ${response.statusText}`);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const responseData = await response.json();
|
|
112
|
+
console.log('[XcelPayGate] Get Transaction Data - Response:', JSON.stringify(responseData, null, 2));
|
|
113
|
+
return responseData;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async getMerchantDetails(merchantId?: string): Promise<MerchantDetails> {
|
|
117
|
+
const id = merchantId || this.config.merchantId;
|
|
118
|
+
const headers = this.getHeaders();
|
|
119
|
+
console.log('[XcelPayGate] Get Merchant Details - Headers:', JSON.stringify(headers, null, 2));
|
|
120
|
+
console.log('[XcelPayGate] Get Merchant Details - Merchant ID:', id);
|
|
121
|
+
|
|
122
|
+
const response = await fetch(
|
|
123
|
+
`${this.config.baseUrl}/business-api/merchant/details/${id}`,
|
|
124
|
+
{
|
|
125
|
+
method: "GET",
|
|
126
|
+
headers,
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
if (!response.ok) {
|
|
131
|
+
throw new Error(`Failed to get merchant details: ${response.statusText}`);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const responseData = await response.json();
|
|
135
|
+
console.log('[XcelPayGate] Get Merchant Details - Response:', JSON.stringify(responseData, null, 2));
|
|
136
|
+
return responseData;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async getMerchantProducts(merchantId?: string): Promise<MerchantProductsResponse> {
|
|
140
|
+
const id = merchantId || this.config.merchantId;
|
|
141
|
+
const headers = this.getHeaders();
|
|
142
|
+
console.log('[XcelPayGate] Get Merchant Products - Headers:', JSON.stringify(headers, null, 2));
|
|
143
|
+
console.log('[XcelPayGate] Get Merchant Products - Merchant ID:', id);
|
|
144
|
+
|
|
145
|
+
const response = await fetch(
|
|
146
|
+
`${this.config.baseUrl}/business-api/merchant/products/${id}`,
|
|
147
|
+
{
|
|
148
|
+
method: "GET",
|
|
149
|
+
headers,
|
|
150
|
+
}
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
if (!response.ok) {
|
|
154
|
+
throw new Error(`Failed to get merchant products: ${response.statusText}`);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const responseData = await response.json();
|
|
158
|
+
console.log('[XcelPayGate] Get Merchant Products - Response:', JSON.stringify(responseData, null, 2));
|
|
159
|
+
|
|
160
|
+
if (responseData.data?.data && Array.isArray(responseData.data.data)) {
|
|
161
|
+
console.log('--- Merchant Products ---');
|
|
162
|
+
responseData.data.data.forEach((product: any, index: number) => {
|
|
163
|
+
console.log(`Product ${index + 1}:`);
|
|
164
|
+
console.log(' Product ID:', product.product_id);
|
|
165
|
+
console.log(' Product Name:', product.name);
|
|
166
|
+
console.log(' Active:', product.active.status);
|
|
167
|
+
console.log(' Web Enabled:', product.web);
|
|
168
|
+
console.log(' Payment Code:', product.payment_code);
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return responseData;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async getMerchantFees(merchantId?: string): Promise<MerchantFeesResponse> {
|
|
176
|
+
const id = merchantId || this.config.merchantId;
|
|
177
|
+
const headers = this.getHeaders();
|
|
178
|
+
console.log('[XcelPayGate] Get Merchant Fees - Headers:', JSON.stringify(headers, null, 2));
|
|
179
|
+
console.log('[XcelPayGate] Get Merchant Fees - Merchant ID:', id);
|
|
180
|
+
|
|
181
|
+
const response = await fetch(
|
|
182
|
+
`${this.config.baseUrl}/transactions-service/merchant/charge-customer/${id}`,
|
|
183
|
+
{
|
|
184
|
+
method: "GET",
|
|
185
|
+
headers,
|
|
186
|
+
}
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
if (!response.ok) {
|
|
190
|
+
throw new Error(`Failed to get merchant fees: ${response.statusText}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return response.json();
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async getMerchantAccounts(merchantId?: string): Promise<any> {
|
|
197
|
+
const id = merchantId || this.config.merchantId;
|
|
198
|
+
const headers = this.getHeaders();
|
|
199
|
+
console.log('[XcelPayGate] Get Merchant Accounts - Headers:', JSON.stringify(headers, null, 2));
|
|
200
|
+
console.log('[XcelPayGate] Get Merchant Accounts - Merchant ID:', id);
|
|
201
|
+
|
|
202
|
+
const response = await fetch(
|
|
203
|
+
`${this.config.baseUrl}/business-api/merchant/pos/${id}`,
|
|
204
|
+
{
|
|
205
|
+
method: "GET",
|
|
206
|
+
headers,
|
|
207
|
+
}
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
if (!response.ok) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
`Failed to get merchant accounts: ${response.statusText}`
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
return response.json();
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
async verifyXcelAccount(
|
|
220
|
+
countryCode: string,
|
|
221
|
+
phoneNumber: string
|
|
222
|
+
): Promise<XcelAccountVerificationResponse> {
|
|
223
|
+
const headers = this.getHeaders();
|
|
224
|
+
console.log('[XcelPayGate] Verify Xcel Account - Headers:', JSON.stringify(headers, null, 2));
|
|
225
|
+
console.log('[XcelPayGate] Verify Xcel Account - Country Code:', countryCode, 'Phone Number:', phoneNumber);
|
|
226
|
+
|
|
227
|
+
const response = await fetch(
|
|
228
|
+
`${this.config.baseUrl}/xas/v1/accounts/users/${countryCode}/${phoneNumber}`,
|
|
229
|
+
{
|
|
230
|
+
method: "GET",
|
|
231
|
+
headers,
|
|
232
|
+
}
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
if (!response.ok) {
|
|
236
|
+
throw new Error(`Failed to verify XCEL account: ${response.statusText}`);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return response.json();
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async generateDynamicLink(
|
|
243
|
+
request: GenerateDynamicLinkRequest
|
|
244
|
+
): Promise<GenerateDynamicLinkResponse> {
|
|
245
|
+
const headers = this.getHeaders();
|
|
246
|
+
console.log('[XcelPayGate] Generate Dynamic Link - Headers:', JSON.stringify(headers, null, 2));
|
|
247
|
+
console.log('[XcelPayGate] Generate Dynamic Link - Payload:', JSON.stringify(request, null, 2));
|
|
248
|
+
|
|
249
|
+
const response = await fetch(
|
|
250
|
+
`${this.config.baseUrl}/esa/otp/generate/dynamic-link`,
|
|
251
|
+
{
|
|
252
|
+
method: "POST",
|
|
253
|
+
headers,
|
|
254
|
+
body: JSON.stringify(request),
|
|
255
|
+
}
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
if (!response.ok) {
|
|
259
|
+
throw new Error(
|
|
260
|
+
`Failed to generate dynamic link: ${response.statusText}`
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return response.json();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
async createXcelTransaction(
|
|
268
|
+
request: CreateXcelTransactionRequest
|
|
269
|
+
): Promise<XcelTransactionResponse> {
|
|
270
|
+
const headers = this.getHeaders();
|
|
271
|
+
console.log('[XcelPayGate] Create Xcel Transaction - Headers:', JSON.stringify(headers, null, 2));
|
|
272
|
+
console.log('[XcelPayGate] Create Xcel Transaction - Payload:', JSON.stringify(request, null, 2));
|
|
273
|
+
|
|
274
|
+
const response = await fetch(
|
|
275
|
+
`${this.config.baseUrl}/xas/v1/pos/create_transaction`,
|
|
276
|
+
{
|
|
277
|
+
method: "POST",
|
|
278
|
+
headers,
|
|
279
|
+
body: JSON.stringify(request),
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
|
|
283
|
+
if (!response.ok) {
|
|
284
|
+
throw new Error(
|
|
285
|
+
`Failed to create XCEL transaction: ${response.statusText}`
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return response.json();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
async getXcelTransactionStatus(
|
|
293
|
+
merchantId: string,
|
|
294
|
+
externalReference: string
|
|
295
|
+
): Promise<XcelTransactionResponse> {
|
|
296
|
+
const headers = this.getHeaders();
|
|
297
|
+
console.log('[XcelPayGate] Get Xcel Transaction Status - Headers:', JSON.stringify(headers, null, 2));
|
|
298
|
+
console.log('[XcelPayGate] Get Xcel Transaction Status - Merchant ID:', merchantId, 'External Reference:', externalReference);
|
|
299
|
+
|
|
300
|
+
const response = await fetch(
|
|
301
|
+
`${this.config.baseUrl}/xas/v1/pos/transaction/${merchantId}/${externalReference}`,
|
|
302
|
+
{
|
|
303
|
+
method: "GET",
|
|
304
|
+
headers,
|
|
305
|
+
}
|
|
306
|
+
);
|
|
307
|
+
|
|
308
|
+
if (!response.ok) {
|
|
309
|
+
throw new Error(
|
|
310
|
+
`Failed to get transaction status: ${response.statusText}`
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
return response.json();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
getCheckoutUrl(merchantId?: string): string {
|
|
318
|
+
const id = merchantId || this.config.merchantId;
|
|
319
|
+
return `${PAYGATE_BASE_URL}/pay/${id}`;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
getFullPaymentUrl(paymentCode: string, merchantId?: string): string {
|
|
323
|
+
const checkoutUrl = this.getCheckoutUrl(merchantId);
|
|
324
|
+
return `${checkoutUrl}?code=${paymentCode}`;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* XcelPaymentFlow - Complete Payment Flow Component
|
|
3
|
+
*
|
|
4
|
+
* All-in-one component that handles:
|
|
5
|
+
* - Payment form UI
|
|
6
|
+
* - WebView navigation
|
|
7
|
+
* - Payment completion
|
|
8
|
+
* - Receipt display
|
|
9
|
+
*
|
|
10
|
+
* Just drop this in your app and you're done!
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* import { XcelPaymentFlow } from '@xcelapp/paygate-sdk';
|
|
15
|
+
*
|
|
16
|
+
* export default function App() {
|
|
17
|
+
* return (
|
|
18
|
+
* <XcelPaymentFlow
|
|
19
|
+
* config={{
|
|
20
|
+
* merchantId: 'your-merchant-id',
|
|
21
|
+
* publicKey: 'your-public-key',
|
|
22
|
+
* }}
|
|
23
|
+
* onPaymentComplete={(result) => {
|
|
24
|
+
* console.log('Payment done!', result);
|
|
25
|
+
* }}
|
|
26
|
+
* />
|
|
27
|
+
* );
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import React, { useState } from 'react';
|
|
33
|
+
import { View, StyleSheet, Modal, SafeAreaView } from 'react-native';
|
|
34
|
+
import { XcelPaymentScreen, XcelPaymentScreenProps } from './XcelPaymentScreen';
|
|
35
|
+
import { XcelPaymentWebView, PaymentResult } from './XcelPaymentWebView';
|
|
36
|
+
import type { XcelPayGateConfig } from '../types';
|
|
37
|
+
|
|
38
|
+
export interface XcelPaymentFlowProps {
|
|
39
|
+
/** SDK Configuration */
|
|
40
|
+
config?: XcelPayGateConfig;
|
|
41
|
+
|
|
42
|
+
/** Called when payment completes (success/fail) */
|
|
43
|
+
onPaymentComplete?: (result: PaymentResult) => void;
|
|
44
|
+
|
|
45
|
+
/** Called when payment is cancelled */
|
|
46
|
+
onCancel?: () => void;
|
|
47
|
+
|
|
48
|
+
/** Pass through props to XcelPaymentScreen */
|
|
49
|
+
screenProps?: Partial<XcelPaymentScreenProps>;
|
|
50
|
+
|
|
51
|
+
/** Show receipt screen (implement your own or use default) */
|
|
52
|
+
renderReceipt?: (result: PaymentResult) => React.ReactNode;
|
|
53
|
+
|
|
54
|
+
/** Use modal for WebView (default: true) */
|
|
55
|
+
useModal?: boolean;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function XcelPaymentFlow({
|
|
59
|
+
config,
|
|
60
|
+
onPaymentComplete,
|
|
61
|
+
onCancel,
|
|
62
|
+
screenProps = {},
|
|
63
|
+
renderReceipt,
|
|
64
|
+
useModal = true,
|
|
65
|
+
}: XcelPaymentFlowProps) {
|
|
66
|
+
const [paymentLink, setPaymentLink] = useState<string | null>(null);
|
|
67
|
+
const [paymentCode, setPaymentCode] = useState<string | null>(null);
|
|
68
|
+
const [showWebView, setShowWebView] = useState(false);
|
|
69
|
+
const [paymentResult, setPaymentResult] = useState<PaymentResult | null>(null);
|
|
70
|
+
|
|
71
|
+
const handlePaymentLinkGenerated = (link: string, code: string) => {
|
|
72
|
+
setPaymentLink(link);
|
|
73
|
+
setPaymentCode(code);
|
|
74
|
+
setShowWebView(true);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const handleSuccess = (result: PaymentResult) => {
|
|
78
|
+
setPaymentResult(result);
|
|
79
|
+
setShowWebView(false);
|
|
80
|
+
onPaymentComplete?.(result);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const handleFailure = (result: PaymentResult) => {
|
|
84
|
+
setPaymentResult(result);
|
|
85
|
+
setShowWebView(false);
|
|
86
|
+
onPaymentComplete?.(result);
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
const handlePending = (result: PaymentResult) => {
|
|
90
|
+
setPaymentResult(result);
|
|
91
|
+
setShowWebView(false);
|
|
92
|
+
onPaymentComplete?.(result);
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const handleCancelWebView = () => {
|
|
96
|
+
setShowWebView(false);
|
|
97
|
+
onCancel?.();
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Show receipt if available
|
|
101
|
+
if (paymentResult && renderReceipt) {
|
|
102
|
+
return <>{renderReceipt(paymentResult)}</>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const webViewContent = paymentLink && (
|
|
106
|
+
<XcelPaymentWebView
|
|
107
|
+
paymentLink={paymentLink}
|
|
108
|
+
paymentCode={paymentCode || undefined}
|
|
109
|
+
onSuccess={handleSuccess}
|
|
110
|
+
onFailure={handleFailure}
|
|
111
|
+
onPending={handlePending}
|
|
112
|
+
onCancel={handleCancelWebView}
|
|
113
|
+
/>
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
return (
|
|
117
|
+
<View style={styles.container}>
|
|
118
|
+
{/* Payment Form */}
|
|
119
|
+
<XcelPaymentScreen
|
|
120
|
+
config={config}
|
|
121
|
+
onPaymentLinkGenerated={handlePaymentLinkGenerated}
|
|
122
|
+
{...screenProps}
|
|
123
|
+
/>
|
|
124
|
+
|
|
125
|
+
{/* WebView Modal or Inline */}
|
|
126
|
+
{showWebView && (
|
|
127
|
+
useModal ? (
|
|
128
|
+
<Modal
|
|
129
|
+
visible={showWebView}
|
|
130
|
+
animationType="slide"
|
|
131
|
+
presentationStyle="fullScreen"
|
|
132
|
+
onRequestClose={handleCancelWebView}
|
|
133
|
+
>
|
|
134
|
+
<SafeAreaView style={styles.modalContainer}>
|
|
135
|
+
{webViewContent}
|
|
136
|
+
</SafeAreaView>
|
|
137
|
+
</Modal>
|
|
138
|
+
) : (
|
|
139
|
+
webViewContent
|
|
140
|
+
)
|
|
141
|
+
)}
|
|
142
|
+
</View>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const styles = StyleSheet.create({
|
|
147
|
+
container: {
|
|
148
|
+
flex: 1,
|
|
149
|
+
},
|
|
150
|
+
modalContainer: {
|
|
151
|
+
flex: 1,
|
|
152
|
+
backgroundColor: '#fff',
|
|
153
|
+
},
|
|
154
|
+
});
|