boxpay-checkout-reactnative-sdk 1.0.0-beta03 → 1.0.0-beta05

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/src/index.tsx CHANGED
@@ -1,36 +1,9 @@
1
- import { useEffect, useRef, useState } from 'react';
2
- import { View, Text, BackHandler, AppState, Image, ScrollView, StatusBar, Alert } from 'react-native'; // Added ScrollView
3
- import Header from './components/header';
4
- import upiPostRequest from './postRequest/upiPostRequest';
5
- import { decode as atob } from 'base-64';
6
- import { Linking } from 'react-native';
7
- import LottieView from 'lottie-react-native';
8
- import PaymentSuccess from './components/paymentSuccess';
9
- import SessionExpire from './components/sessionExpire';
10
- import PaymentFailed from './components/paymentFailed';
11
- import fetchStatus from './postRequest/fetchStatus';
12
- import UpiScreen from './screens/upiScreen';
13
- import { useNavigation, type NavigationProp } from "@react-navigation/native";
14
- import type { CheckoutStackParamList } from './navigation';
15
- import { paymentHandler, setPaymentHandler } from "./sharedContext/paymentStatusHandler";
16
- import { loadCustomFonts, loadInterCustomFonts } from './components/fontFamily';
17
- import { setUserDataHandler, userDataHandler } from './sharedContext/userdataHandler';
18
- import { type PaymentResultObject, type PaymentClass, type InstrumentDetails, type PaymentMethod, type OrderItem, type BoxpayCheckoutProps, APIStatus, AnalyticsEvents } from './interface';
19
- import { checkoutDetailsHandler, setCheckoutDetailsHandler } from './sharedContext/checkoutDetailsHandler';
20
- import WebViewScreen from './screens/webViewScreen';
1
+ import { useEffect } from 'react';
2
+ import { setPaymentHandler } from "./sharedContext/paymentStatusHandler";
3
+ import type { BoxpayCheckoutProps} from './interface';
4
+ import { checkoutDetailsHandler } from './sharedContext/checkoutDetailsHandler';
21
5
  import styles from './styles/indexStyles';
22
- import getSymbolFromCurrency from 'currency-symbol-map';
23
- import type { ItemsProp } from './components/orderDetails';
24
- import OrderDetails from './components/orderDetails';
25
6
  import { SafeAreaView } from 'react-native-safe-area-context';
26
- import PaymentSelectorView from './components/paymentSelector';
27
- import SavedCardComponentView from './components/savedCardComponent';
28
- import ShimmerView from './components/shimmerView';
29
- import AddressComponent from './components/addressCard';
30
- import fetchSessionDetails from './postRequest/fetchSessionDetails';
31
- import MorePaymentMethods from './components/morePaymentMethods';
32
- import { fetchSavedInstrumentsHandler, handleFetchStatusResponseHandler, handlePaymentResponse } from './sharedContext/handlePaymentResponseHandler';
33
- import callUIAnalytics from './postRequest/callUIAnalytics';
34
7
  import CheckoutContainer from './navigation';
35
8
 
36
9
  const BoxpayCheckout = ({
@@ -39,720 +12,18 @@ const BoxpayCheckout = ({
39
12
  onPaymentResult,
40
13
  shopperToken = null,
41
14
  }: BoxpayCheckoutProps) => {
42
- const [status, setStatus] = useState('NOACTION');
43
- const [transactionId, setTransactionId] = useState('');
44
- const env = configurationOptions?.ENABLE_SANDBOX_ENV ? 'test' : 'prod';
45
- const appStateListenerRef = useRef<any>(null);
46
- const [loadingState, setLoadingState] = useState(false);
47
- const [isFirstLoading, setIsFirstLoading] = useState(true);
48
- const [amount, setAmount] = useState('');
49
- const totalItemsRef = useRef(0);
50
- const [address, setAddress] = useState('');
51
- const [failedModalOpen, setFailedModalState] = useState(false);
52
- const [successModalOpen, setSuccessModalState] = useState(false);
53
- const lastOpenendUrl = useRef<string>('');
54
- const paymentFailedMessage = useRef<string>(
55
- 'You may have cancelled the payment or there was a delay in response. Please retry.'
56
- );
57
- const [sessionExpireModalOpen, setSessionExppireModalState] = useState(false);
58
- const [successfulTimeStamp, setSuccessfulTimeStamp] = useState('');
59
- const navigation = useNavigation<NavigationProp<CheckoutStackParamList>>(); // Use correct type
60
- const timerRef = useRef<NodeJS.Timeout | null>(null);
61
- const [showWebView, setShowWebView] = useState(false);
62
- const [paymentUrl, setPaymentUrl] = useState<string | null>(null);
63
- const [paymentHtml, setPaymentHtml] = useState<string | null>(null);
64
- const isUpiOpeningRef = useRef(false);
65
- const shippingAmountRef = useRef('');
66
- const taxAmountRef = useRef('');
67
- const subTotalAmountRef = useRef('');
68
- const orderItemsArrayRef = useRef<ItemsProp[]>([]);
69
- const [recommendedInstrumentsArray, setRecommendedInstruments] = useState<PaymentClass[]>([]);
70
- const [savedCardArray, setSavedCardArray] = useState<PaymentClass[]>([]);
71
- const [savedUpiArray, setSavedUpiArray] = useState<PaymentClass[]>([]);
72
-
73
- let isFirstTimeLoadRef = true;
74
-
75
- const handlePaymentIntent = async (selectedIntent: string) => {
76
- setLoadingState(true);
77
- const response = await upiPostRequest({
78
- type: 'upi/intent',
79
- ...(selectedIntent && { upiAppDetails: { upiApp: selectedIntent } }), // Conditionally add upiAppDetails only if upiIntent is present
80
- });
81
- handlePaymentResponse({
82
- response: response,
83
- checkoutDetailsErrorMessage: checkoutDetailsHandler.checkoutDetails.errorMessage,
84
- onSetStatus: setStatus,
85
- onSetTransactionId: setTransactionId,
86
- onSetPaymentHtml: setPaymentHtml,
87
- onSetPaymentUrl: setPaymentUrl,
88
- onSetFailedMessage: (msg) => (paymentFailedMessage.current = msg),
89
- onShowFailedModal: () => setFailedModalState(true),
90
- onShowSuccessModal: (ts) => {
91
- setSuccessfulTimeStamp(ts);
92
- setSuccessModalState(true);
93
- },
94
- onShowSessionExpiredModal: () => setSessionExppireModalState(true),
95
- onNavigateToTimer: (id:string)=> navigation.navigate("UpiTimerScreen", {upiId : id}),
96
- onOpenUpiIntent : (url) => {
97
- urlToBase64(url);
98
- },
99
- setLoading: setLoadingState
100
- });
101
- };
102
-
103
- const handleUpiCollectPayment = async (
104
- upiId: string,
105
- instrumentRef: string,
106
- type: string
107
- ) => {
108
- const requestPayload: InstrumentDetails =
109
- type === 'Card'
110
- ? {
111
- type: 'card/token',
112
- savedCard: { instrumentRef: instrumentRef },
113
- }
114
- : {
115
- type: 'upi/collect',
116
- upi: instrumentRef
117
- ? { instrumentRef: instrumentRef }
118
- : { shopperVpa: upiId },
119
- };
120
- setLoadingState(true);
121
- const response = await upiPostRequest(requestPayload);
122
- handlePaymentResponse({
123
- response: response,
124
- upiId: upiId,
125
- checkoutDetailsErrorMessage: checkoutDetailsHandler.checkoutDetails.errorMessage,
126
- onSetStatus: setStatus,
127
- onSetTransactionId: setTransactionId,
128
- onSetPaymentHtml: setPaymentHtml,
129
- onSetPaymentUrl: setPaymentUrl,
130
- onSetFailedMessage: (msg) => (paymentFailedMessage.current = msg),
131
- onShowFailedModal: () => setFailedModalState(true),
132
- onShowSuccessModal: (ts) => {
133
- setSuccessfulTimeStamp(ts);
134
- setSuccessModalState(true);
135
- },
136
- onShowSessionExpiredModal: () => setSessionExppireModalState(true),
137
- onNavigateToTimer: (id:string)=> navigation.navigate("UpiTimerScreen", {upiId : id}),
138
- onOpenUpiIntent : (url) => {
139
- urlToBase64(url);
140
- },
141
- setLoading: setLoadingState
142
- });
143
- };
144
15
 
145
16
  useEffect(() => {
146
- if (isFirstTimeLoadRef) {
147
- isFirstTimeLoadRef = false;
148
- return;
149
- }
150
- const refreshData = () => {
151
- const address1Ref = userDataHandler.userData.address1;
152
- const address2Ref = userDataHandler.userData.address2;
153
- const cityRef = userDataHandler.userData.city;
154
- const stateRef = userDataHandler.userData.state;
155
- const postalCodeRef = userDataHandler.userData.pincode;
156
-
157
- if (address2Ref == null || address2Ref == '') {
158
- setAddress(
159
- `${address1Ref}, ${cityRef}, ${stateRef}, ${postalCodeRef}`
160
- );
161
- } else {
162
- setAddress(
163
- `${address1Ref}, ${address2Ref}, ${cityRef}, ${stateRef}, ${postalCodeRef}`
164
- );
165
- }
166
- };
167
-
168
- refreshData();
169
- });
170
-
171
- const urlToBase64 = (base64String: string) => {
172
- try {
173
- const decodedString = atob(base64String);
174
- lastOpenendUrl.current = decodedString;
175
- openUPIIntent(decodedString);
176
- } catch (error) {
177
- setFailedModalState(true);
178
- callUIAnalytics(AnalyticsEvents.FAILED_TO_LAUNCH_UPI_INTENT,"Index Screen UrlToBase64 failed",`${error}`)
179
- setLoadingState(false);
180
- }
181
- };
182
-
183
- const getRecommendedInstruments = async () => {
184
- fetchSavedInstrumentsHandler({
185
- setRecommendedList: setRecommendedInstruments,
186
- setUpiInstrumentList : setSavedUpiArray,
187
- setCardInstrumentList : setSavedCardArray
17
+ checkoutDetailsHandler.checkoutDetails.token = token
18
+ checkoutDetailsHandler.checkoutDetails.shopperToken = shopperToken
19
+ checkoutDetailsHandler.checkoutDetails.isSuccessScreenVisible = configurationOptions?.SHOW_BOXPAY_SUCCESS_SCREEN ? true : false
20
+ setPaymentHandler({
21
+ onPaymentResult: onPaymentResult,
188
22
  });
189
- setIsFirstLoading(false)
190
- };
191
-
192
- useEffect(() => {
193
- if (paymentUrl || paymentHtml) {
194
- setShowWebView(true);
195
- }
196
- }, [paymentUrl, paymentHtml]);
197
-
198
- const openUPIIntent = async (url: string) => {
199
- try {
200
- await Linking.openURL(url); // Open the UPI app
201
- appStateListenerRef.current = AppState.addEventListener(
202
- 'change',
203
- handleAppStateChange
204
- );
205
- isUpiOpeningRef.current = true;
206
- } catch (error) {
207
- isUpiOpeningRef.current = false;
208
- callUIAnalytics(AnalyticsEvents.FAILED_TO_LAUNCH_UPI_INTENT,"Index Screen open UPI Intent failed",`${error}`)
209
- setFailedModalState(true);
210
- setLoadingState(false);
211
- }
212
- };
213
-
214
- const handleAppStateChange = () => {
215
- if (AppState.currentState === 'active' && isUpiOpeningRef.current) {
216
- callFetchStatusApi();
217
- }
218
- };
219
-
220
- const stopExpireTimerCountDown = () => {
221
- if (timerRef.current) {
222
- clearInterval(timerRef.current);
223
- }
224
- };
225
-
226
- const callFetchStatusApi = async () => {
227
- const response = await fetchStatus();
228
- handleFetchStatusResponseHandler({
229
- response: response,
230
- checkoutDetailsErrorMessage: checkoutDetailsHandler.checkoutDetails.errorMessage,
231
- onSetStatus: setStatus,
232
- onSetTransactionId: setTransactionId,
233
- onSetFailedMessage: (msg) => (paymentFailedMessage.current = msg),
234
- onShowFailedModal: () => setFailedModalState(true),
235
- onShowSuccessModal: (ts) => {
236
- setSuccessfulTimeStamp(ts);
237
- setSuccessModalState(true);
238
- },
239
- onShowSessionExpiredModal: () => setSessionExppireModalState(true),
240
- setLoading: setLoadingState
241
- });
242
- appStateListenerRef.current?.remove();
243
- isUpiOpeningRef.current = false;
244
- };
245
-
246
- const onExitCheckout = () => {
247
- if (!loadingState) {
248
- stopExpireTimerCountDown();
249
- const mockPaymentResult: PaymentResultObject = {
250
- status: status,
251
- transactionId: transactionId,
252
- };
253
- paymentHandler.onPaymentResult(mockPaymentResult);
254
- return true;
255
- }
256
- return false;
257
- };
258
-
259
- useEffect(() => {
260
- const backHandler = BackHandler.addEventListener(
261
- 'hardwareBackPress',
262
- () => {
263
- if (showWebView) {
264
- setShowWebView(false);
265
- paymentFailedMessage.current =
266
- checkoutDetailsHandler.checkoutDetails.errorMessage;
267
- setStatus('Failed');
268
- setFailedModalState(true);
269
- setLoadingState(false);
270
- return true;
271
- } else if (loadingState) {
272
- return true;
273
- }
274
- return onExitCheckout(); // Allow back navigation if not loading
275
- }
276
- );
277
-
278
- return () => backHandler.remove();
279
23
  });
280
-
281
- useEffect(() => {
282
- async function loadFonts() {
283
- await loadCustomFonts();
284
- await loadInterCustomFonts();
285
- }
286
- loadFonts()
287
-
288
- async function loadSession() {
289
- if(token != "") {
290
- checkoutDetailsHandler.checkoutDetails.env = env
291
- checkoutDetailsHandler.checkoutDetails.token = token
292
- const response = await fetchSessionDetails()
293
- try {
294
- switch(response.apiStatus) {
295
- case APIStatus.Success : {
296
- const paymentMethods = response.data.configs.paymentMethods;
297
- const enabledFields = response.data.configs.enabledFields;
298
- const paymentDetails = response.data.paymentDetails;
299
- const methodFlags = {
300
- isUPIIntentVisible: false,
301
- isUPICollectVisible: false,
302
- isCardsVisible: false,
303
- isWalletVisible: false,
304
- isNetbankingVisible: false,
305
- isEMIVisible: false,
306
- isBNPLVisible: false,
307
- };
308
-
309
- paymentMethods.forEach((method: PaymentMethod) => {
310
- if (method.type === 'Upi') {
311
- if (method.brand === 'UpiIntent') {
312
- methodFlags.isUPIIntentVisible = true;
313
- } else if (method.brand === 'UpiCollect') {
314
- methodFlags.isUPICollectVisible = true;
315
- }
316
- } else if (method.type === 'Card') {
317
- methodFlags.isCardsVisible = true;
318
- } else if (method.type === 'Wallet') {
319
- methodFlags.isWalletVisible = true;
320
- } else if (method.type === 'NetBanking') {
321
- methodFlags.isNetbankingVisible = true;
322
- } else if (method.type === 'Emi') {
323
- methodFlags.isEMIVisible = true;
324
- } else if (method.type === 'BuyNowPayLater') {
325
- methodFlags.isBNPLVisible = true;
326
- }
327
- });
328
-
329
- setAmount(paymentDetails.money.amountLocaleFull);
330
- const currencyCode: string | undefined =
331
- paymentDetails?.money?.currencyCode;
332
- const symbol = currencyCode
333
- ? (getSymbolFromCurrency(currencyCode) ?? '₹')
334
- : '₹';
335
- if (
336
- paymentDetails.order != null &&
337
- paymentDetails.order.items != null
338
- ) {
339
- const total = paymentDetails.order.items.reduce(
340
- (sum: number, item: OrderItem) => sum + (item.quantity || 1),
341
- 0
342
- );
343
- totalItemsRef.current = total;
344
- shippingAmountRef.current =
345
- paymentDetails.order.shippingAmountLocaleFull != null
346
- ? paymentDetails.order.shippingAmountLocaleFull
347
- : '';
348
- taxAmountRef.current =
349
- paymentDetails.order.taxAmountLocaleFull != null
350
- ? paymentDetails.order.taxAmountLocaleFull
351
- : '';
352
- subTotalAmountRef.current =
353
- paymentDetails.order.originalAmountLocaleFull != null
354
- ? paymentDetails.order.originalAmountLocaleFull
355
- : '';
356
- const formattedItemsArray: ItemsProp[] =
357
- paymentDetails.order.items.map((item: OrderItem) => ({
358
- imageUrl: item.imageUrl,
359
- imageTitle: item.itemName,
360
- imageOty: item.quantity,
361
- imageAmount: item.amountWithoutTaxLocaleFull,
362
- }));
363
- orderItemsArrayRef.current = formattedItemsArray;
364
- }
365
- const emailRef = paymentDetails.shopper.email;
366
- const firstNameRef = paymentDetails.shopper.firstName;
367
- const lastNameRef = paymentDetails.shopper.lastName;
368
- const phoneRef = paymentDetails.shopper.phoneNumber;
369
- const uniqueIdRef = paymentDetails.shopper.uniqueReference;
370
- const dobRef = paymentDetails.shopper.dateOfBirth;
371
- const panRef = paymentDetails.shopper.panNumber;
372
- startCountdown(response.data.sessionExpiryTimestamp);
373
- let labelTypeRef = null;
374
- let address1Ref = null;
375
- let labelNameRef = null;
376
- let address2Ref = null;
377
- let cityRef = null;
378
- let stateRef = null;
379
- let postalCodeRef = null;
380
- let countryCodeRef = null;
381
- if (paymentDetails.shopper.deliveryAddress != null) {
382
- const deliveryObject = paymentDetails.shopper.deliveryAddress;
383
- labelTypeRef = deliveryObject.labelType;
384
- labelNameRef = deliveryObject.labelName;
385
- address1Ref = deliveryObject.address1;
386
- address2Ref = deliveryObject.address2;
387
- cityRef = deliveryObject.city;
388
- stateRef = deliveryObject.state;
389
- postalCodeRef = deliveryObject.postalCode;
390
- countryCodeRef = deliveryObject.countryCode;
391
- if (address2Ref == null || address2Ref == '') {
392
- setAddress(
393
- `${address1Ref}, ${cityRef}, ${stateRef}, ${postalCodeRef}`
394
- );
395
- } else {
396
- setAddress(
397
- `${address1Ref}, ${address2Ref}, ${cityRef}, ${stateRef}, ${postalCodeRef}`
398
- );
399
- }
400
- }
401
- if (['APPROVED', 'SUCCESS', 'PAID'].includes(response.data.status)) {
402
- setSuccessfulTimeStamp(response.data.lastPaidAtTimestamp);
403
- setTransactionId(response.data.lastTransactionId);
404
- setStatus(response.data.status);
405
- setSuccessModalState(true);
406
- } else if (['EXPIRED'].includes(response.data.status)) {
407
- setSessionExppireModalState(true);
408
- }
409
- setUserDataHandler({
410
- userData: {
411
- email: emailRef,
412
- firstName: firstNameRef,
413
- lastName: lastNameRef,
414
- phone: phoneRef,
415
- uniqueId: uniqueIdRef,
416
- dob: dobRef,
417
- pan: panRef,
418
- address1: address1Ref,
419
- address2: address2Ref,
420
- city: cityRef,
421
- state: stateRef,
422
- pincode: postalCodeRef,
423
- country: countryCodeRef,
424
- labelType: labelTypeRef,
425
- labelName: labelNameRef,
426
- },
427
- });
428
- const isFieldEnabled = (fieldName: string) => {
429
- return enabledFields.some(
430
- (field: { field: string }) => field.field === fieldName
431
- );
432
- };
433
-
434
- const isFieldEditable = (fieldName: string) => {
435
- const field = enabledFields.find(
436
- (field: { field: string; editable: boolean }) =>
437
- field.field === fieldName
438
- );
439
- return field?.editable === true;
440
- };
441
-
442
- setCheckoutDetailsHandler({
443
- checkoutDetails: {
444
- currencySymbol: symbol,
445
- amount: paymentDetails.money.amountLocaleFull,
446
- token: token,
447
- brandColor:
448
- response.data.merchantDetails.checkoutTheme.primaryButtonColor,
449
- env: env,
450
- itemsLength: totalItemsRef.current,
451
- errorMessage:
452
- 'You may have cancelled the payment or there was a delay in response. Please retry.',
453
- shopperToken: shopperToken,
454
- isSuccessScreenVisible: configurationOptions?.SHOW_BOXPAY_SUCCESS_SCREEN ? true : false,
455
- isShippingAddressEnabled: isFieldEnabled('SHIPPING_ADDRESS'),
456
- isShippingAddressEditable: isFieldEditable('SHIPPING_ADDRESS'),
457
- isFullNameEnabled: isFieldEnabled('SHOPPER_NAME'),
458
- isFullNameEditable: isFieldEditable('SHOPPER_NAME'),
459
- isEmailEnabled: isFieldEnabled('SHOPPER_EMAIL'),
460
- isEmailEditable: isFieldEditable('SHOPPER_EMAIL'),
461
- isPhoneEnabled: isFieldEnabled('SHOPPER_PHONE'),
462
- isPhoneEditable: isFieldEditable('SHOPPER_PHONE'),
463
- isPanEnabled: isFieldEnabled('SHOPPER_PAN'),
464
- isPanEditable: isFieldEditable('SHOPPER_PAN'),
465
- isDOBEnabled: isFieldEnabled('SHOPPER_DOB'),
466
- isDOBEditable: isFieldEditable('SHOPPER_DOB'),
467
- isUpiIntentMethodEnabled : methodFlags.isUPIIntentVisible,
468
- isUpiCollectMethodEnabled : methodFlags.isUPICollectVisible,
469
- isCardMethodEnabled : methodFlags.isCardsVisible,
470
- isWalletMethodEnabled : methodFlags.isWalletVisible,
471
- isNetBankingMethodEnabled : methodFlags.isNetbankingVisible,
472
- isEmiMethodEnabled : methodFlags.isEMIVisible,
473
- isBnplMethodEnabled : methodFlags.isBNPLVisible
474
- },
475
- });
476
- setPaymentHandler({
477
- onPaymentResult: onPaymentResult,
478
- });
479
- callUIAnalytics(AnalyticsEvents.CHECKOUT_LOADED,"Index Screen Session Loaded","")
480
- break;
481
- }
482
- case APIStatus.Failed : {
483
- Alert.alert('Error', response.data.status.reason);
484
- break
485
- }
486
- default : {
487
- break
488
- }
489
- }
490
- } catch(error) {
491
- Alert.alert('Error', `${error}`);
492
- }
493
- } else {
494
- Alert.alert('Error', `Token is empty`);
495
- }
496
- }
497
- loadSession()
498
-
499
- if(shopperToken != null && shopperToken != "") {
500
- checkoutDetailsHandler.checkoutDetails.shopperToken = shopperToken
501
- getRecommendedInstruments()
502
- }
503
-
504
- }, [token]);
505
-
506
- const handleRecommendedSectionClick = (instrumentValue: string) => {
507
- const updatedList = recommendedInstrumentsArray.map((item) => ({
508
- ...item,
509
- isSelected: item.id === instrumentValue,
510
- }));
511
- setRecommendedInstruments(updatedList);
512
- setDefaultSavedUpiList();
513
- setDefaultSavedCardsList();
514
- };
515
-
516
- const handleSavedUpiSectionClick = (instrumentValue: string) => {
517
- const updatedList = savedUpiArray.map((item) => ({
518
- ...item,
519
- isSelected: item.id === instrumentValue,
520
- }));
521
- setSavedUpiArray(updatedList);
522
- setDefaultRecommendedList();
523
- setDefaultSavedCardsList();
524
- };
525
-
526
- const handleSavedCardSectionClick = (instrumentValue: string) => {
527
- const updatedList = savedCardArray.map((item) => ({
528
- ...item,
529
- isSelected: item.id === instrumentValue,
530
- }));
531
- setSavedCardArray(updatedList);
532
- setDefaultRecommendedList();
533
- setDefaultSavedUpiList();
534
- };
535
-
536
- const setDefaultRecommendedList = () => {
537
- const updatedList = recommendedInstrumentsArray.map((item) => ({
538
- ...item,
539
- isSelected: false,
540
- }));
541
- setRecommendedInstruments(updatedList);
542
- };
543
-
544
- const setDefaultSavedCardsList = () => {
545
- const updatedList = savedCardArray.map((item) => ({
546
- ...item,
547
- isSelected: false,
548
- }));
549
- setSavedCardArray(updatedList);
550
- };
551
-
552
- const setDefaultSavedUpiList = () => {
553
- const updatedList = savedUpiArray.map((item) => ({
554
- ...item,
555
- isSelected: false,
556
- }));
557
- setSavedUpiArray(updatedList);
558
- };
559
-
560
- function startCountdown(sessionExpiryTimestamp: string) {
561
- if (sessionExpiryTimestamp === '') {
562
- return;
563
- }
564
- const expiryTime = new Date(sessionExpiryTimestamp);
565
- const expiryTimeIST = new Date(expiryTime.getTime() + 5.5 * 60 * 60 * 1000);
566
-
567
- timerRef.current = setInterval(() => {
568
- const currentTimeIST = new Date(
569
- new Date().getTime() + 5.5 * 60 * 60 * 1000
570
- );
571
- const timeDiff = expiryTimeIST.getTime() - currentTimeIST.getTime();
572
- if (timeDiff <= 0) {
573
- if (timerRef.current) {
574
- clearInterval(timerRef.current);
575
- }
576
- setStatus('EXPIRED');
577
- setSessionExppireModalState(true);
578
- }
579
- // const hours = Math.floor((timeDiff / (1000 * 60 * 60)) % 24);
580
- // const minutes = Math.floor((timeDiff / (1000 * 60)) % 60);
581
- // const seconds = Math.floor((timeDiff / 1000) % 60);
582
-
583
- // console.log(`${hours}hr ${minutes}min ${seconds}sec`)
584
- }, 1000);
585
- }
586
-
24
+
587
25
  return (
588
26
  <SafeAreaView style={styles.screenView}>
589
- <StatusBar barStyle="dark-content" />
590
- {isFirstLoading ? (
591
- <ShimmerView />
592
- ) : loadingState ? (
593
- <View
594
- style={styles.loadingContainer}
595
- >
596
- <LottieView
597
- source={require('../assets/animations/boxpayLogo.json')}
598
- autoPlay
599
- loop
600
- style={styles.lottieStyle}
601
- />
602
- <Text>Loading...</Text>
603
- </View>
604
- ) : (
605
- <View style={styles.screenView}>
606
- <ScrollView
607
- contentContainerStyle={{ flexGrow: 1 }}
608
- keyboardShouldPersistTaps="handled"
609
- >
610
- <View style={{ flex: 1 }}>
611
- <Header
612
- onBackPress={onExitCheckout}
613
- showDesc={true}
614
- showSecure={true}
615
- text="Payment Details"
616
- />
617
- <AddressComponent address={address} navigateToAddressScreen= {() => navigation.navigate("AddressScreen", {})}/>
618
-
619
- {recommendedInstrumentsArray.length > 0 && (
620
- <>
621
- <View
622
- style={styles.container}
623
- >
624
- <Text
625
- style={styles.headingText}
626
- >
627
- Recommended
628
- </Text>
629
- </View>
630
- <View
631
- style={styles.paymentContainer}
632
- >
633
- <PaymentSelectorView
634
- providerList={recommendedInstrumentsArray}
635
- onProceedForward={(displayValue, instrumentValue, type) =>
636
- handleUpiCollectPayment(
637
- displayValue,
638
- instrumentValue,
639
- type
640
- )
641
- }
642
- errorImage={require('../assets/images/ic_upi.png')}
643
- isLastUsed={true}
644
- onClickRadio={(selectedInstrumentRef) => {
645
- handleRecommendedSectionClick(selectedInstrumentRef);
646
- }}
647
- />
648
- </View>
649
- </>
650
- )}
651
-
652
- <UpiScreen
653
- handleUpiPayment={(selectedIntent) =>
654
- handlePaymentIntent(selectedIntent)
655
- }
656
- handleCollectPayment={(displayValue, instrumentValue, type) =>
657
- handleUpiCollectPayment(displayValue, instrumentValue, type)
658
- }
659
- savedUpiArray={savedUpiArray}
660
- onClickRadio={handleSavedUpiSectionClick}
661
- />
662
-
663
- {savedCardArray.length != 0 && (
664
- <View>
665
- <Text
666
- style={styles.headingText}
667
- >
668
- Credit & Debit Cards
669
- </Text>
670
- <View
671
- style={styles.paymentContainer}
672
- >
673
- <SavedCardComponentView
674
- savedCards={savedCardArray}
675
- onProceedForward={(instrumentValue) => {
676
- handleUpiCollectPayment('', instrumentValue, 'Card');
677
- }}
678
- errorImage={require('../assets/images/ic_card.png')}
679
- onClickAddCard={() => navigation.navigate("CardScreen", {})}
680
- onClickRadio={(selectedInstrumentRef) =>
681
- handleSavedCardSectionClick(selectedInstrumentRef)
682
- }
683
- />
684
- </View>
685
- </View>
686
- )}
687
- <MorePaymentMethods savedCards={savedCardArray}/>
688
- <View>
689
- <Text
690
- style={styles.headingText}
691
- >
692
- Order Summary
693
- </Text>
694
-
695
- <OrderDetails
696
- subTotalAmount={subTotalAmountRef.current}
697
- shippingAmount={shippingAmountRef.current}
698
- totalAmount={amount}
699
- itemsArray={orderItemsArrayRef.current}
700
- taxAmount={taxAmountRef.current}
701
- />
702
- </View>
703
-
704
- {/* Secured by BoxPay - Fixed at Bottom */}
705
- <View
706
- style={styles.footerContainer}
707
- >
708
- <Text
709
- style={styles.footerText}
710
- >
711
- Secured by
712
- </Text>
713
- <Image
714
- source={require('../assets/images/splash-icon.png')}
715
- style={styles.footerImage}
716
- />
717
- </View>
718
- </View>
719
- </ScrollView>
720
- </View>
721
- )}
722
-
723
- {/* Modals for Different Payment Statuses */}
724
- {failedModalOpen && (
725
- <PaymentFailed
726
- onClick={() => setFailedModalState(false)}
727
- errorMessage={paymentFailedMessage.current}
728
- />
729
- )}
730
-
731
- {successModalOpen && (
732
- <PaymentSuccess
733
- onClick={onExitCheckout}
734
- transactionId={transactionId}
735
- method="UPI"
736
- localDateTime={successfulTimeStamp}
737
- />
738
- )}
739
-
740
- {sessionExpireModalOpen && <SessionExpire onClick={onExitCheckout} />}
741
-
742
- {showWebView && (
743
- <View
744
- style={styles.webViewScreenStyle}
745
- >
746
- <WebViewScreen
747
- url={paymentUrl}
748
- html={paymentHtml}
749
- onBackPress={() => {
750
- callFetchStatusApi();
751
- setShowWebView(false);
752
- }}
753
- />
754
- </View>
755
- )}
756
27
  <CheckoutContainer/>
757
28
  </SafeAreaView>
758
29
  );