react-native-fpay 0.4.29 → 0.4.31

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.
Files changed (79) hide show
  1. package/lib/module/FountainPayProvider.js +5 -0
  2. package/lib/module/FountainPayProvider.js.map +1 -1
  3. package/lib/module/core/api/index.js +59 -0
  4. package/lib/module/core/api/index.js.map +1 -1
  5. package/lib/module/core/types/index.js +32 -0
  6. package/lib/module/core/types/index.js.map +1 -1
  7. package/lib/module/engine/FPEngine.js +9 -0
  8. package/lib/module/engine/FPEngine.js.map +1 -1
  9. package/lib/module/hooks/useLocation.js +66 -0
  10. package/lib/module/hooks/useLocation.js.map +1 -0
  11. package/lib/module/ui/components/ConfirmScreen.js +43 -51
  12. package/lib/module/ui/components/ConfirmScreen.js.map +1 -1
  13. package/lib/module/ui/components/RecurringToggle.js +94 -0
  14. package/lib/module/ui/components/RecurringToggle.js.map +1 -0
  15. package/lib/module/ui/modals/FPShell.js +19 -0
  16. package/lib/module/ui/modals/FPShell.js.map +1 -1
  17. package/lib/module/ui/screens/BillsScreen.js +186 -0
  18. package/lib/module/ui/screens/BillsScreen.js.map +1 -0
  19. package/lib/module/ui/screens/ResultScreen.js +113 -28
  20. package/lib/module/ui/screens/ResultScreen.js.map +1 -1
  21. package/lib/module/ui/screens/SendScreen.js +85 -16
  22. package/lib/module/ui/screens/SendScreen.js.map +1 -1
  23. package/lib/module/ui/screens/sub/billPayment/AirtimeScreen.js +257 -0
  24. package/lib/module/ui/screens/sub/billPayment/AirtimeScreen.js.map +1 -0
  25. package/lib/module/ui/screens/sub/billPayment/CableScreen.js +264 -0
  26. package/lib/module/ui/screens/sub/billPayment/CableScreen.js.map +1 -0
  27. package/lib/module/ui/screens/sub/billPayment/DataScreen.js +273 -0
  28. package/lib/module/ui/screens/sub/billPayment/DataScreen.js.map +1 -0
  29. package/lib/module/ui/screens/sub/billPayment/ElectricityScreen.js +337 -0
  30. package/lib/module/ui/screens/sub/billPayment/ElectricityScreen.js.map +1 -0
  31. package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js +1 -1
  32. package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js.map +1 -1
  33. package/lib/typescript/src/FountainPayProvider.d.ts.map +1 -1
  34. package/lib/typescript/src/core/api/index.d.ts +52 -63
  35. package/lib/typescript/src/core/api/index.d.ts.map +1 -1
  36. package/lib/typescript/src/core/types/index.d.ts +159 -6
  37. package/lib/typescript/src/core/types/index.d.ts.map +1 -1
  38. package/lib/typescript/src/engine/FPEngine.d.ts +4 -2
  39. package/lib/typescript/src/engine/FPEngine.d.ts.map +1 -1
  40. package/lib/typescript/src/hooks/useLocation.d.ts +12 -0
  41. package/lib/typescript/src/hooks/useLocation.d.ts.map +1 -0
  42. package/lib/typescript/src/index.d.ts +1 -1
  43. package/lib/typescript/src/index.d.ts.map +1 -1
  44. package/lib/typescript/src/ui/components/ConfirmScreen.d.ts +25 -4
  45. package/lib/typescript/src/ui/components/ConfirmScreen.d.ts.map +1 -1
  46. package/lib/typescript/src/ui/components/RecurringToggle.d.ts +7 -0
  47. package/lib/typescript/src/ui/components/RecurringToggle.d.ts.map +1 -0
  48. package/lib/typescript/src/ui/modals/FPShell.d.ts.map +1 -1
  49. package/lib/typescript/src/ui/screens/BillsScreen.d.ts +10 -0
  50. package/lib/typescript/src/ui/screens/BillsScreen.d.ts.map +1 -0
  51. package/lib/typescript/src/ui/screens/ResultScreen.d.ts +20 -3
  52. package/lib/typescript/src/ui/screens/ResultScreen.d.ts.map +1 -1
  53. package/lib/typescript/src/ui/screens/SendScreen.d.ts.map +1 -1
  54. package/lib/typescript/src/ui/screens/sub/billPayment/AirtimeScreen.d.ts +15 -0
  55. package/lib/typescript/src/ui/screens/sub/billPayment/AirtimeScreen.d.ts.map +1 -0
  56. package/lib/typescript/src/ui/screens/sub/billPayment/CableScreen.d.ts +14 -0
  57. package/lib/typescript/src/ui/screens/sub/billPayment/CableScreen.d.ts.map +1 -0
  58. package/lib/typescript/src/ui/screens/sub/billPayment/DataScreen.d.ts +14 -0
  59. package/lib/typescript/src/ui/screens/sub/billPayment/DataScreen.d.ts.map +1 -0
  60. package/lib/typescript/src/ui/screens/sub/billPayment/ElectricityScreen.d.ts +16 -0
  61. package/lib/typescript/src/ui/screens/sub/billPayment/ElectricityScreen.d.ts.map +1 -0
  62. package/package.json +2 -2
  63. package/src/FountainPayProvider.tsx +7 -0
  64. package/src/core/api/index.ts +149 -27
  65. package/src/core/types/index.ts +194 -11
  66. package/src/engine/FPEngine.ts +12 -1
  67. package/src/hooks/useLocation.ts +81 -0
  68. package/src/index.ts +9 -1
  69. package/src/ui/components/ConfirmScreen.tsx +47 -54
  70. package/src/ui/components/RecurringToggle.tsx +106 -0
  71. package/src/ui/modals/FPShell.tsx +26 -3
  72. package/src/ui/screens/BillsScreen.tsx +197 -0
  73. package/src/ui/screens/ResultScreen.tsx +129 -28
  74. package/src/ui/screens/SendScreen.tsx +124 -68
  75. package/src/ui/screens/sub/billPayment/AirtimeScreen.tsx +252 -0
  76. package/src/ui/screens/sub/billPayment/CableScreen.tsx +274 -0
  77. package/src/ui/screens/sub/billPayment/DataScreen.tsx +263 -0
  78. package/src/ui/screens/sub/billPayment/ElectricityScreen.tsx +344 -0
  79. package/src/ui/screens/sub/sendPayment/TransferSubScreen.tsx +1 -1
@@ -1,11 +1,13 @@
1
- import { useEffect, useRef, useState } from 'react';
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+ import type { FC } from 'react';
2
3
  import { Animated, Easing, TouchableOpacity } from 'react-native';
3
4
  import Svg, { Path, Circle } from 'react-native-svg';
4
5
  import styled from 'styled-components/native';
5
6
  import { C, F, R, S } from '../theme';
6
- import type { FPTransaction } from '../../core/types';
7
- import { transferAPI } from '../../core/api';
7
+ import type { SubscriptionFreq } from '../../core/types';
8
+ import { subscriptionAPI, transferAPI } from '../../core/api';
8
9
  import Gradients from '../components/Gradients';
10
+ import RecurringToggle from '../components/RecurringToggle';
9
11
 
10
12
  // ── Icons ─────────────────────────────────────────────────────
11
13
 
@@ -187,7 +189,7 @@ function CountdownRing({ duration }: { duration: number }) {
187
189
 
188
190
  // ── Row ──────────────────────────────────────────────────────
189
191
 
190
- function Row({ label, value }: { label: string; value: string }) {
192
+ const Row: FC<{ label: string; value: string }> = ({ label, value }) => {
191
193
  return (
192
194
  <RowWrap>
193
195
  <RowLabel>{label}</RowLabel>
@@ -198,37 +200,77 @@ function Row({ label, value }: { label: string; value: string }) {
198
200
 
199
201
  // ── Main ─────────────────────────────────────────────────────
200
202
 
203
+ /**
204
+ * Generalized props — ResultScreen no longer assumes a "recipient" or that
205
+ * the underlying transaction came through transferAPI.
206
+ * - reference: used to poll status (via statusFetcher, defaults to transferAPI.status)
207
+ * - summaryRows: extra rows to render in the detail card (e.g. "To", "Channel")
208
+ * beyond the always-present Reference/Date/Status rows
209
+ * - allowRecurring: SendScreen keeps the existing recurring-payment upsell;
210
+ * domains with no concept of "this recipient" (bills) pass false
211
+ * - statusFetcher: which endpoint to poll — defaults to the shared
212
+ * agencyTransaction-backed transferAPI.status, which bill transactions
213
+ * also live in
214
+ */
201
215
  interface Props {
202
- transaction: FPTransaction | any;
216
+ reference: string;
217
+ summaryRows?: { label: string; value: string }[];
218
+ allowRecurring?: boolean;
219
+ statusFetcher?: (reference: string) => Promise<any>;
203
220
  onClose: () => void;
204
221
  }
205
222
 
206
- export function ResultScreen({ transaction, onClose }: Props) {
223
+ export function ResultScreen({
224
+ reference,
225
+ summaryRows,
226
+ allowRecurring = true,
227
+ statusFetcher = transferAPI.status,
228
+ onClose,
229
+ }: Props) {
207
230
  const [loading, setLoading] = useState<boolean>(false);
208
231
  const [transactionDetail, setTransactionDetail] = useState<any>(null)
209
232
  const opacAnim = useRef(new Animated.Value(1)).current; // ← start visible
210
233
  const slideAnim = useRef(new Animated.Value(0)).current; // ← start in place
211
234
  const scaleAnim = useRef(new Animated.Value(1)).current; // ← start full size
212
235
 
236
+ const [recurringEnabled, setRecurringEnabled] = useState(false);
237
+ const [recurringFrequency, setRecurringFrequency] = useState<SubscriptionFreq>('MONTHLY');
238
+
239
+
213
240
  const isSuccess = transactionDetail?.status.toLowerCase() === 'successful';
214
241
  const accentColor = isSuccess ? C.green : C.red;
215
242
  const bgColor = isSuccess ? '#E3FCEF' : '#FFEBE6';
216
243
 
244
+ const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
245
+ const startTimeRef = useRef<number>(Date.now());
246
+ const remainingTimeRef = useRef<number>(COUNTDOWN_SECONDS * 1000);
247
+ const isPausedRef = useRef<boolean>(false);
248
+
249
+ const startTimer = useCallback((duration: number) => {
250
+ if (timerRef.current) clearTimeout(timerRef.current);
251
+ startTimeRef.current = Date.now();
252
+ timerRef.current = setTimeout(onClose, duration);
253
+ }, [onClose]);
254
+
255
+ const pauseTimer = useCallback(() => {
256
+ if (isPausedRef.current) return;
257
+ isPausedRef.current = true;
258
+ if (timerRef.current) clearTimeout(timerRef.current);
259
+ // Calculate how much time is left
260
+ const elapsed = Date.now() - startTimeRef.current;
261
+ remainingTimeRef.current = Math.max(remainingTimeRef.current - elapsed, 0);
262
+ }, []);
263
+
264
+ const resumeTimer = useCallback(() => {
265
+ if (!isPausedRef.current) return;
266
+ isPausedRef.current = false;
267
+ startTimer(remainingTimeRef.current);
268
+ }, [startTimer]);
269
+
217
270
  const formatted = `${transactionDetail?.currency || 'NGN'} ${Number(transactionDetail?.amount).toLocaleString('en-NG', {
218
271
  minimumFractionDigits: 2,
219
272
  })}`;
220
273
 
221
- const recipient = transaction?.recipient as any;
222
- const recipientName = recipient?.accountName ?? recipient?.name ?? '—';
223
-
224
- const channelLabel: Record<string, string> = {
225
- transfer: 'Bank Transfer',
226
- bluetooth: 'Bluetooth',
227
- proximity: 'Nearby',
228
- nqr: 'QR Code',
229
- nfc: 'NFC Tap',
230
- };
231
-
232
274
  const dateStr = transactionDetail?.createdAt
233
275
  ? new Date(transactionDetail?.createdAt).toLocaleString('en-NG')
234
276
  : '—';
@@ -237,7 +279,7 @@ export function ResultScreen({ transaction, onClose }: Props) {
237
279
  setLoading(true);
238
280
  setTransactionDetail(null);
239
281
  try{
240
- const response = await transferAPI.status(transaction.reference) as any;
282
+ const response = await statusFetcher(reference) as any;
241
283
  console.log("Transaction payload: ", response);
242
284
  if(response.status){
243
285
  setTransactionDetail(response.payload);
@@ -250,19 +292,70 @@ export function ResultScreen({ transaction, onClose }: Props) {
250
292
 
251
293
  }
252
294
 
295
+ const calculateNextDate=(current: Date | string, frequency: SubscriptionFreq): Date=> {
296
+ const date = new Date(current);
297
+
298
+ switch (frequency) {
299
+ case 'DAILY':
300
+ date.setDate(date.getDate() + 1);
301
+ break;
302
+ case 'WEEKLY':
303
+ date.setDate(date.getDate() + 7);
304
+ break;
305
+ case 'MONTHLY':
306
+ date.setMonth(date.getMonth() + 1);
307
+ break;
308
+ case 'YEARLY':
309
+ date.setFullYear(date.getFullYear() + 1);
310
+ break;
311
+ default:
312
+ throw new Error(`Unknown frequency: ${frequency}`);
313
+ }
314
+
315
+ return date;
316
+ }
317
+
318
+ const handlePayment = async () => {
319
+ pauseTimer();
320
+ try {
321
+ await subscriptionAPI.create({
322
+ serviceName: summaryRows?.find(r => r.label === 'To')?.value ?? 'Payment',
323
+ serviceCategory: 'Payment', // default category
324
+ amount: transactionDetail.amount, // from your existing payment data
325
+ currency: transactionDetail.currency,
326
+ frequency: recurringFrequency,
327
+ accountNumber: transactionDetail.senderAccountNumber,
328
+ receiverAccountNumber: transactionDetail.destAccountNumber,
329
+ logoUrl: transactionDetail.recipientLogo ?? '',
330
+ nextPaymentDate: calculateNextDate(new Date(), recurringFrequency).toISOString(),
331
+ });
332
+ } catch {
333
+ console.warn('Subscription registration failed silently');
334
+ } finally {
335
+ resumeTimer();
336
+ }
337
+ };
338
+
253
339
 
254
340
 
341
+ // useEffect(() => {
342
+ // const timer = setTimeout(onClose, COUNTDOWN_SECONDS * 1000);
343
+ // return () => clearTimeout(timer);
344
+ // }, [onClose]);
345
+
255
346
  useEffect(() => {
256
- const timer = setTimeout(onClose, COUNTDOWN_SECONDS * 1000);
257
- return () => clearTimeout(timer);
258
- }, [onClose]);
347
+ startTimer(remainingTimeRef.current);
348
+ return () => {
349
+ if (timerRef.current) clearTimeout(timerRef.current);
350
+ };
351
+ }, [startTimer])
259
352
 
260
353
 
261
354
  useEffect(()=>{
262
- if(transaction){
355
+ if(reference){
263
356
  loadTransaction();
264
357
  }
265
- }, [transaction]);
358
+ }, [reference]);
266
359
 
267
360
 
268
361
  if (loading && !transactionDetail) {
@@ -286,13 +379,22 @@ export function ResultScreen({ transaction, onClose }: Props) {
286
379
  <Amount>{formatted}</Amount>
287
380
 
288
381
  <Card>
289
- <Row label="To" value={recipientName} />
290
- <Row label="Channel" value={channelLabel[transactionDetail?.channel] ?? transaction?.channel} />
382
+ {summaryRows?.map((row) => (
383
+ <Row key={row.label} label={row.label} value={row.value} />
384
+ ))}
291
385
  <Row label="Reference" value={transactionDetail?.reference} />
292
386
  <Row label="Date" value={dateStr} />
293
387
  <Row label="Status" value={transactionDetail?.status?.toUpperCase()} />
294
388
  </Card>
295
-
389
+ {allowRecurring && (
390
+ <RecurringToggle
391
+ onToggle={(enabled, freq) => {
392
+ setRecurringEnabled(enabled);
393
+ setRecurringFrequency(freq);
394
+ handlePayment();
395
+ }}
396
+ />
397
+ )}
296
398
  <Footer>
297
399
  <CountdownRing duration={COUNTDOWN_SECONDS * 1000} />
298
400
  <CloseBtn onPress={onClose} activeOpacity={0.8}>
@@ -301,5 +403,4 @@ export function ResultScreen({ transaction, onClose }: Props) {
301
403
  </Footer>
302
404
  </Container>
303
405
  );
304
- }
305
-
406
+ }
@@ -35,6 +35,7 @@ import ConfirmScreen from '../components/ConfirmScreen';
35
35
  import LoadingAnimation from '../components/LoadingAnimation';
36
36
  import { getFPStore } from '../../store/FPStore';
37
37
  import { ResultScreen } from './ResultScreen';
38
+ import { useLocation } from '../../hooks/useLocation';
38
39
 
39
40
  const { height } = Dimensions.get('window');
40
41
 
@@ -315,21 +316,22 @@ const SendScreen = ({
315
316
  const [channel, setChannel] = useState<Channel>('TRANSFER');
316
317
  const [loading, setLoading] = useState<boolean>(false);
317
318
  const [showConfirmationModal, setShowConfirmationModal] = useState<boolean>(false);
319
+ const { requestLocation } = useLocation();
318
320
 
319
321
  const [completedTx, setCompletedTx] = useState<FPTransaction | null>(null);
320
322
 
321
- const [transactionPayload, setTransactionPayload] = useState<FPSendPaymentRequest | FPSendWalletPaymentRequest>({} as FPSendPaymentRequest | FPSendWalletPaymentRequest);
323
+ const [transactionPayload, setTransactionPayload] = useState<FPSendWalletPaymentRequest>({} as FPSendWalletPaymentRequest);
322
324
 
323
325
  const formatted = `${currency} ${amount.toLocaleString('en-NG', { minimumFractionDigits: 2 })}`;
324
326
 
325
327
  // { id: result.reference, reference: result.reference, type: 'debit', channel: 'transfer', amount: result.amount, currency: result.currency, status: result.status, recipient: { accountName: result.recipient.accountName }, createdAt: result.createdAt }
326
328
 
327
329
  const handleContinue = (
328
- tx: FPSendPaymentRequest | FPSendWalletPaymentRequest | null
330
+ tx: FPSendWalletPaymentRequest | null
329
331
  ) => {
330
332
  console.log('Transaction Payload: ', tx);
331
333
  setTransactionPayload(
332
- tx as FPSendPaymentRequest | FPSendWalletPaymentRequest
334
+ tx as FPSendWalletPaymentRequest
333
335
  );
334
336
  setShowConfirmationModal(true);
335
337
  };
@@ -341,74 +343,89 @@ const SendScreen = ({
341
343
 
342
344
  const handleProcessingTransaction = async (temptId: string) => {
343
345
  try {
344
- setLoading(true);
345
- setShowConfirmationModal(false);
346
- let response: any = null;
347
-
348
- const recipient = transactionPayload?.recipient as any;
349
-
350
- switch (transactionPayload?.channel) {
351
- case 'transfer':
352
- case 'bluetooth':
353
- case 'proximity': {
354
- // Internal transfer recipient has id + type (AGENT/TERMINAL)
355
- if (recipient?.id && recipient?.type && ['AGENT', 'TERMINAL'].includes(recipient.type)) {
356
- response = await transferAPI.sendToWallet(
357
- {
358
- ...transactionPayload,
359
- recipient: {
360
- account_number: recipient.accountNumber,
361
- agent_id: recipient.id,
362
- type: recipient.type,
363
- terminal_id: recipient?.terminalId || '',
346
+ setLoading(true);
347
+ setShowConfirmationModal(false);
348
+ let response: any = null;
349
+
350
+ const recipient = transactionPayload?.recipient as any;
351
+ const isTerminalTransaction = transactionPayload.sender_type === 'AGENT' || recipient.type === 'TERMINAL';
352
+ let movement: { latitude: number; longitude: number } | undefined;
353
+
354
+ if (isTerminalTransaction) {
355
+ // Always fetch fresh location for terminal transactions
356
+ const loc = await requestLocation();
357
+
358
+ if (loc) {
359
+ movement = {
360
+ latitude: loc.latitude,
361
+ longitude: loc.longitude,
362
+ // No address — Django will reverse-geocode
363
+ };
364
+ }
365
+ }
366
+ const newTransactionPayload ={...transactionPayload, movement}
367
+ switch (newTransactionPayload?.channel) {
368
+ case 'transfer':
369
+ case 'bluetooth':
370
+ case 'proximity': {
371
+ // Internal transfer — recipient has id + type (AGENT/TERMINAL)
372
+ if (recipient?.id && recipient?.type && ['AGENT', 'TERMINAL'].includes(recipient.type)) {
373
+ response = await transferAPI.sendToWallet(
374
+ {
375
+ ...newTransactionPayload,
376
+ recipient: {
377
+ account_number: recipient.accountNumber,
378
+ agent_id: recipient.id,
379
+ type: recipient.type,
380
+ terminal_id: recipient?.terminalId || '',
381
+ },
364
382
  },
365
- },
366
- temptId
367
- );
383
+ temptId
384
+ );
385
+ }
386
+ // Bank transfer — recipient has accountNumber + bankCode
387
+ else if (recipient?.bankCode) {
388
+ response = await transferAPI.sendToBank(
389
+ newTransactionPayload as any,
390
+ temptId
391
+ );
392
+ }
393
+ // Wallet transfer — recipient has accountNumber + userId/agentId
394
+ else {
395
+ response = await transferAPI.sendToWallet(
396
+ newTransactionPayload as FPSendWalletPaymentRequest,
397
+ temptId
398
+ );
399
+ }
400
+ break;
368
401
  }
369
- // Bank transfer — recipient has accountNumber + bankCode
370
- else if (recipient?.bankCode) {
371
- response = await transferAPI.sendToBank(
372
- transactionPayload as FPSendPaymentRequest,
402
+
403
+ case 'nqr':
404
+ response = await nqrAPI.pay(
405
+ {
406
+ ...newTransactionPayload,
407
+ narration: `Send ${formatted} to ${recipient?.accountName ?? ''}`,
408
+ amount: parseFloat(newTransactionPayload.amount)
409
+ },
373
410
  temptId
374
411
  );
375
- }
376
- // Wallet transfer — recipient has accountNumber + userId/agentId
377
- else {
378
- response = await transferAPI.sendToWallet(
379
- transactionPayload as FPSendWalletPaymentRequest,
412
+ break;
413
+
414
+ case 'nfc':
415
+ response = await nfcAPI.pay(
416
+ {
417
+ ...newTransactionPayload,
418
+ narration: `Send ${formatted} to ${recipient?.accountName ?? ''}`,
419
+ amount: parseFloat(newTransactionPayload.amount)
420
+ },
380
421
  temptId
381
422
  );
382
- }
383
- break;
384
- }
423
+ break;
385
424
 
386
- case 'nqr':
387
- response = await nqrAPI.pay(
388
- {
389
- ...transactionPayload,
390
- sender: user ?? undefined,
391
- narration: `Send ${formatted} to ${recipient?.accountName ?? ''}`,
392
- },
393
- temptId
394
- );
395
- break;
396
-
397
- case 'nfc':
398
- response = await nfcAPI.pay(
399
- {
400
- ...transactionPayload,
401
- sender: user ?? undefined,
402
- narration: `Send ${formatted} to ${recipient?.accountName ?? ''}`,
403
- },
404
- temptId
405
- );
406
- break;
407
-
408
- default:
409
- onError?.({ message: 'Invalid channel' } as FPError);
410
- return;
411
- }
425
+ default:
426
+ onError?.({ message: 'Invalid channel' } as FPError);
427
+ return;
428
+ }
412
429
 
413
430
 
414
431
  if (!response?.status) {
@@ -431,10 +448,25 @@ const SendScreen = ({
431
448
  };
432
449
 
433
450
  if (completedTx) {
451
+ const mergedTx = { ...transactionPayload, ...completedTx } as any;
452
+ const recipient = mergedTx?.recipient as any;
453
+ const recipientName = recipient?.accountName ?? recipient?.name ?? '—';
454
+ const channelLabel: Record<string, string> = {
455
+ transfer: 'Bank Transfer',
456
+ bluetooth: 'Bluetooth',
457
+ proximity: 'Nearby',
458
+ nqr: 'QR Code',
459
+ nfc: 'NFC Tap',
460
+ };
434
461
 
435
462
  return (
436
463
  <ResultScreen
437
- transaction={{...transactionPayload, ...completedTx}}
464
+ reference={mergedTx.reference}
465
+ summaryRows={[
466
+ { label: 'To', value: recipientName },
467
+ { label: 'Channel', value: channelLabel[mergedTx?.channel] ?? mergedTx?.channel },
468
+ ]}
469
+ allowRecurring
438
470
  onClose={handleResultClose}
439
471
  />
440
472
  );
@@ -549,8 +581,32 @@ const SendScreen = ({
549
581
  </SheetHeader>
550
582
 
551
583
  <ConfirmScreen
552
- userId={getFPStore().psspId || ''}
553
- transaction={transactionPayload}
584
+ amount={Number(transactionPayload?.amount || 0)}
585
+ currency={transactionPayload?.currency}
586
+ subtitle="Double check the transfer details before you proceed. Please note that successful transfers cannot be reversed."
587
+ summaryRows={(() => {
588
+ const recipient = transactionPayload?.recipient as any;
589
+ const recipientName = recipient?.accountName ?? '';
590
+ const accountNumber = recipient?.accountNumber ?? '';
591
+ const bankName = (recipient as any)?.bankName;
592
+ const rows = [{ label: 'Name', value: recipientName }];
593
+ if (transactionPayload?.isBank) {
594
+ if (transactionPayload?.channel === 'transfer') {
595
+ rows.push({ label: 'Bank', value: bankName });
596
+ rows.push({ label: 'Account No.', value: accountNumber });
597
+ }
598
+ } else {
599
+ rows.push({ label: 'Account Number', value: accountNumber });
600
+ }
601
+ return rows;
602
+ })()}
603
+ validate={(pin: string) =>
604
+ transferAPI.validateTransfer(
605
+ pin,
606
+ getFPStore().psspId || '',
607
+ (transactionPayload?.recipient as any)?.id
608
+ )
609
+ }
554
610
  onContinue={handleProcessingTransaction}
555
611
  />
556
612
  </SheetScrollView>
@@ -560,4 +616,4 @@ const SendScreen = ({
560
616
  );
561
617
  };
562
618
 
563
- export default SendScreen;
619
+ export default SendScreen;