react-native-fpay 0.3.4 → 0.3.6

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 (155) hide show
  1. package/lib/module/FountainPayProvider.js +106 -16
  2. package/lib/module/FountainPayProvider.js.map +1 -1
  3. package/lib/module/core/api/client.js +13 -1
  4. package/lib/module/core/api/client.js.map +1 -1
  5. package/lib/module/core/api/index.js +66 -24
  6. package/lib/module/core/api/index.js.map +1 -1
  7. package/lib/module/engine/BLEReceiverService.js.map +1 -1
  8. package/lib/module/engine/BLESenderService.js.map +1 -1
  9. package/lib/module/engine/FPEngine.js +164 -43
  10. package/lib/module/engine/FPEngine.js.map +1 -1
  11. package/lib/module/engine/NearbyUsersService.js +1 -1
  12. package/lib/module/engine/NearbyUsersService.js.map +1 -1
  13. package/lib/module/index.js +1 -0
  14. package/lib/module/index.js.map +1 -1
  15. package/lib/module/store/FPStore.js +155 -0
  16. package/lib/module/store/FPStore.js.map +1 -0
  17. package/lib/module/ui/components/AnimatedDots.js +3 -3
  18. package/lib/module/ui/components/AnimatedDots.js.map +1 -1
  19. package/lib/module/ui/components/ConfirmScreen.js +137 -123
  20. package/lib/module/ui/components/ConfirmScreen.js.map +1 -1
  21. package/lib/module/ui/components/FPButton.js.map +1 -1
  22. package/lib/module/ui/components/LoadingAnimation/InLoading.js +3 -3
  23. package/lib/module/ui/components/LoadingAnimation/InLoading.js.map +1 -1
  24. package/lib/module/ui/components/LoadingAnimation/index.js +3 -3
  25. package/lib/module/ui/components/LoadingAnimation/index.js.map +1 -1
  26. package/lib/module/ui/components/OtpInput/OTPInputView.js +11 -11
  27. package/lib/module/ui/components/OtpInput/OTPInputView.js.map +1 -1
  28. package/lib/module/ui/components/OtpInput/Styles.js +1 -1
  29. package/lib/module/ui/components/OtpInput/helpers/codeToArray.js +1 -1
  30. package/lib/module/ui/components/OtpInput/helpers/device.js.map +1 -1
  31. package/lib/module/ui/components/OtpInput/helpers/styles.js.map +1 -1
  32. package/lib/module/ui/components/OtpInput/index.js +3 -1
  33. package/lib/module/ui/components/OtpInput/index.js.map +1 -1
  34. package/lib/module/ui/components/PulseAnimation.js +2 -2
  35. package/lib/module/ui/components/PulseAnimation.js.map +1 -1
  36. package/lib/module/ui/modals/FPPaymentRequestModal.js +8 -7
  37. package/lib/module/ui/modals/FPPaymentRequestModal.js.map +1 -1
  38. package/lib/module/ui/modals/FPShell.js +2 -0
  39. package/lib/module/ui/modals/FPShell.js.map +1 -1
  40. package/lib/module/ui/screens/ReceiveScreen.js +8 -9
  41. package/lib/module/ui/screens/ReceiveScreen.js.map +1 -1
  42. package/lib/module/ui/screens/SendScreen.js +43 -94
  43. package/lib/module/ui/screens/SendScreen.js.map +1 -1
  44. package/lib/module/ui/screens/styles.js +15 -3
  45. package/lib/module/ui/screens/styles.js.map +1 -1
  46. package/lib/module/ui/screens/sub/receivePayment/Nfc/index.js +4 -4
  47. package/lib/module/ui/screens/sub/receivePayment/Nfc/index.js.map +1 -1
  48. package/lib/module/ui/screens/sub/receivePayment/Qr/index.js +5 -5
  49. package/lib/module/ui/screens/sub/receivePayment/Qr/index.js.map +1 -1
  50. package/lib/module/ui/screens/sub/receivePayment/Transfer/index.js +10 -11
  51. package/lib/module/ui/screens/sub/receivePayment/Transfer/index.js.map +1 -1
  52. package/lib/module/ui/screens/sub/sendPayment/BluetoothSubScreen.js +31 -8
  53. package/lib/module/ui/screens/sub/sendPayment/BluetoothSubScreen.js.map +1 -1
  54. package/lib/module/ui/screens/sub/sendPayment/NFCSubScreen.js +12 -8
  55. package/lib/module/ui/screens/sub/sendPayment/NFCSubScreen.js.map +1 -1
  56. package/lib/module/ui/screens/sub/sendPayment/NQRSubScreen.js +17 -5
  57. package/lib/module/ui/screens/sub/sendPayment/NQRSubScreen.js.map +1 -1
  58. package/lib/module/ui/screens/sub/sendPayment/ProximitySubScreen.js +67 -35
  59. package/lib/module/ui/screens/sub/sendPayment/ProximitySubScreen.js.map +1 -1
  60. package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js +110 -34
  61. package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js.map +1 -1
  62. package/lib/module/ui/theme/index.js.map +1 -1
  63. package/lib/typescript/src/FountainPayProvider.d.ts +1 -1
  64. package/lib/typescript/src/FountainPayProvider.d.ts.map +1 -1
  65. package/lib/typescript/src/core/api/client.d.ts.map +1 -1
  66. package/lib/typescript/src/core/api/index.d.ts +42 -26
  67. package/lib/typescript/src/core/api/index.d.ts.map +1 -1
  68. package/lib/typescript/src/core/types/index.d.ts +53 -28
  69. package/lib/typescript/src/core/types/index.d.ts.map +1 -1
  70. package/lib/typescript/src/engine/BLEReceiverService.d.ts +2 -0
  71. package/lib/typescript/src/engine/BLEReceiverService.d.ts.map +1 -1
  72. package/lib/typescript/src/engine/BLESenderService.d.ts.map +1 -1
  73. package/lib/typescript/src/engine/FPEngine.d.ts +5 -3
  74. package/lib/typescript/src/engine/FPEngine.d.ts.map +1 -1
  75. package/lib/typescript/src/engine/useIsForeground.d.ts.map +1 -1
  76. package/lib/typescript/src/index.d.ts +2 -1
  77. package/lib/typescript/src/index.d.ts.map +1 -1
  78. package/lib/typescript/src/store/FPStore.d.ts +60 -0
  79. package/lib/typescript/src/store/FPStore.d.ts.map +1 -0
  80. package/lib/typescript/src/ui/components/AnimatedDots.d.ts.map +1 -1
  81. package/lib/typescript/src/ui/components/ConfirmScreen.d.ts +5 -5
  82. package/lib/typescript/src/ui/components/ConfirmScreen.d.ts.map +1 -1
  83. package/lib/typescript/src/ui/components/FPButton.d.ts +1 -1
  84. package/lib/typescript/src/ui/components/FPButton.d.ts.map +1 -1
  85. package/lib/typescript/src/ui/components/LoadingAnimation/InLoading.d.ts.map +1 -1
  86. package/lib/typescript/src/ui/components/LoadingAnimation/index.d.ts.map +1 -1
  87. package/lib/typescript/src/ui/components/OtpInput/OTPInputView.d.ts.map +1 -1
  88. package/lib/typescript/src/ui/components/OtpInput/helpers/codeToArray.d.ts.map +1 -1
  89. package/lib/typescript/src/ui/components/OtpInput/helpers/device.d.ts.map +1 -1
  90. package/lib/typescript/src/ui/components/OtpInput/helpers/styles.d.ts.map +1 -1
  91. package/lib/typescript/src/ui/components/OtpInput/helpers/types.d.ts +1 -2
  92. package/lib/typescript/src/ui/components/OtpInput/helpers/types.d.ts.map +1 -1
  93. package/lib/typescript/src/ui/components/OtpInput/index.d.ts +3 -1
  94. package/lib/typescript/src/ui/components/OtpInput/index.d.ts.map +1 -1
  95. package/lib/typescript/src/ui/components/PulseAnimation.d.ts.map +1 -1
  96. package/lib/typescript/src/ui/modals/FPPaymentRequestModal.d.ts.map +1 -1
  97. package/lib/typescript/src/ui/modals/FPShell.d.ts.map +1 -1
  98. package/lib/typescript/src/ui/screens/ReceiveScreen.d.ts +1 -1
  99. package/lib/typescript/src/ui/screens/ReceiveScreen.d.ts.map +1 -1
  100. package/lib/typescript/src/ui/screens/SendScreen.d.ts +1 -1
  101. package/lib/typescript/src/ui/screens/SendScreen.d.ts.map +1 -1
  102. package/lib/typescript/src/ui/screens/styles.d.ts +197 -0
  103. package/lib/typescript/src/ui/screens/styles.d.ts.map +1 -1
  104. package/lib/typescript/src/ui/screens/sub/receivePayment/Nfc/index.d.ts.map +1 -1
  105. package/lib/typescript/src/ui/screens/sub/receivePayment/Qr/index.d.ts.map +1 -1
  106. package/lib/typescript/src/ui/screens/sub/receivePayment/Transfer/index.d.ts.map +1 -1
  107. package/lib/typescript/src/ui/screens/sub/sendPayment/BluetoothSubScreen.d.ts.map +1 -1
  108. package/lib/typescript/src/ui/screens/sub/sendPayment/NFCSubScreen.d.ts +1 -1
  109. package/lib/typescript/src/ui/screens/sub/sendPayment/NFCSubScreen.d.ts.map +1 -1
  110. package/lib/typescript/src/ui/screens/sub/sendPayment/NQRSubScreen.d.ts +1 -1
  111. package/lib/typescript/src/ui/screens/sub/sendPayment/NQRSubScreen.d.ts.map +1 -1
  112. package/lib/typescript/src/ui/screens/sub/sendPayment/ProximitySubScreen.d.ts +1 -1
  113. package/lib/typescript/src/ui/screens/sub/sendPayment/ProximitySubScreen.d.ts.map +1 -1
  114. package/lib/typescript/src/ui/screens/sub/sendPayment/TransferSubScreen.d.ts +1 -1
  115. package/lib/typescript/src/ui/screens/sub/sendPayment/TransferSubScreen.d.ts.map +1 -1
  116. package/lib/typescript/src/ui/theme/index.d.ts.map +1 -1
  117. package/package.json +4 -5
  118. package/src/FountainPayProvider.tsx +164 -23
  119. package/src/core/api/client.ts +26 -4
  120. package/src/core/api/index.ts +170 -49
  121. package/src/core/types/index.ts +81 -48
  122. package/src/engine/BLEReceiverService.ts +86 -28
  123. package/src/engine/BLESenderService.ts +133 -69
  124. package/src/engine/FPEngine.ts +316 -97
  125. package/src/engine/NearbyUsersService.ts +6 -6
  126. package/src/engine/useIsForeground.ts +12 -12
  127. package/src/index.ts +10 -4
  128. package/src/store/FPStore.ts +216 -0
  129. package/src/ui/components/AnimatedDots.tsx +4 -5
  130. package/src/ui/components/ConfirmScreen.tsx +182 -169
  131. package/src/ui/components/FPButton.tsx +50 -9
  132. package/src/ui/components/LoadingAnimation/InLoading.tsx +23 -27
  133. package/src/ui/components/LoadingAnimation/index.tsx +3 -7
  134. package/src/ui/components/OtpInput/OTPInputView.tsx +254 -205
  135. package/src/ui/components/OtpInput/Styles.ts +1 -1
  136. package/src/ui/components/OtpInput/helpers/codeToArray.ts +2 -2
  137. package/src/ui/components/OtpInput/helpers/device.ts +4 -3
  138. package/src/ui/components/OtpInput/helpers/styles.ts +13 -14
  139. package/src/ui/components/OtpInput/helpers/types.ts +83 -79
  140. package/src/ui/components/OtpInput/index.tsx +18 -15
  141. package/src/ui/components/PulseAnimation.tsx +3 -5
  142. package/src/ui/modals/FPPaymentRequestModal.tsx +111 -28
  143. package/src/ui/modals/FPShell.tsx +60 -34
  144. package/src/ui/screens/ReceiveScreen.tsx +245 -84
  145. package/src/ui/screens/SendScreen.tsx +419 -167
  146. package/src/ui/screens/styles.ts +17 -5
  147. package/src/ui/screens/sub/receivePayment/Nfc/index.tsx +17 -25
  148. package/src/ui/screens/sub/receivePayment/Qr/index.tsx +21 -20
  149. package/src/ui/screens/sub/receivePayment/Transfer/index.tsx +34 -28
  150. package/src/ui/screens/sub/sendPayment/BluetoothSubScreen.tsx +135 -67
  151. package/src/ui/screens/sub/sendPayment/NFCSubScreen.tsx +188 -112
  152. package/src/ui/screens/sub/sendPayment/NQRSubScreen.tsx +102 -69
  153. package/src/ui/screens/sub/sendPayment/ProximitySubScreen.tsx +225 -99
  154. package/src/ui/screens/sub/sendPayment/TransferSubScreen.tsx +209 -89
  155. package/src/ui/theme/index.ts +14 -2
@@ -11,9 +11,16 @@
11
11
  // </FountainPayProvider>
12
12
  // ─────────────────────────────────────────────────────────────────────────────
13
13
  import React, {
14
- type ReactNode, createContext, useContext, useMemo, useRef,
14
+ type ReactNode,
15
+ createContext,
16
+ useContext,
17
+ useEffect,
18
+ useMemo,
19
+ useRef,
20
+ useState,
15
21
  } from 'react';
16
22
  import { FPShell } from './ui/modals/FPShell';
23
+ import { useFPStore, getFPStore, isTokenValid } from './store/FPStore';
17
24
  import { FPEngine } from './engine/FPEngine';
18
25
  import { initClient } from './core/api/client';
19
26
  import type {
@@ -22,10 +29,11 @@ import type {
22
29
  FPSDKOptions,
23
30
  FPCallbacks,
24
31
  FPCurrency,
25
- FPGenerateAccountRequest,
26
- FPVirtualAccount,
27
32
  FPTransferRecipient,
33
+ FPAccount,
28
34
  } from './core/types';
35
+ import { authenticateAPI, transferAPI } from './core/api';
36
+ import { Alert } from 'react-native';
29
37
 
30
38
  // ── Context ───────────────────────────────────────────────────────────────────
31
39
 
@@ -47,7 +55,7 @@ export function useFountainPay(): FPInstance {
47
55
  if (!instance) {
48
56
  throw new Error(
49
57
  '[FountainPay] useFountainPay() must be called inside <FountainPayProvider>.\n' +
50
- 'Make sure you have wrapped your app root with <FountainPayProvider apiKey="...">.'
58
+ 'Make sure you have wrapped your app root with <FountainPayProvider apiKey="...">.'
51
59
  );
52
60
  }
53
61
  return instance;
@@ -61,30 +69,126 @@ interface ProviderProps {
61
69
  children: ReactNode;
62
70
  }
63
71
 
64
- export function FountainPayProvider({ apiKey, options, children }: ProviderProps) {
72
+ export function FountainPayProvider({
73
+ apiKey,
74
+ options,
75
+ children,
76
+ }: ProviderProps) {
65
77
  // Boot the HTTP client as soon as the provider mounts —
66
78
  // this means generateAccountNumber works even before initializeSDK
67
79
  const clientBooted = useRef(false);
68
- if (!clientBooted.current) {
69
- initClient(apiKey, { baseUrl: options?.baseUrl, environment: options?.environment });
70
- clientBooted.current = true;
71
- console.log('[FountainPay] Provider mounted. HTTP client ready.');
72
- }
80
+
81
+ const isAuthenticated = useFPStore((s) => s.isAuthenticated);
82
+ const authError = useFPStore((s) => s.authError);
83
+ const setAuthenticated = useFPStore((s) => s.setAuthenticated);
84
+ const account = useFPStore((s) => s.account);
85
+ const user = useFPStore((s) => s.user);
86
+ const balance = useFPStore((s) => s.balance);
87
+
88
+ console.log('[FPStore] user:', user);
89
+ console.log('[FPStore] account:', account);
90
+
91
+ useEffect(() => {
92
+ let cancelled = false;
93
+
94
+ // Make sure client is initialized before any API call
95
+ console.log('[FountainPay] Provider mounted. HTTP client ready.', options);
96
+ if (!clientBooted.current) {
97
+ initClient(apiKey, {
98
+ baseUrl: options?.baseUrl,
99
+ environment: options?.environment,
100
+ });
101
+ clientBooted.current = true;
102
+ console.log(
103
+ '[FountainPay] Provider mounted. HTTP client ready.: ',
104
+ options
105
+ );
106
+ }
107
+
108
+ const authenticate = async () => {
109
+ if (isTokenValid()) {
110
+ console.log('[FountainPay] Valid token found — skipping auth.');
111
+ setAuthenticated(true);
112
+ return;
113
+ }
114
+
115
+ try {
116
+ console.log('[FountainPay] Verifying API key...');
117
+ const response = await authenticateAPI.login(apiKey);
118
+ if (cancelled) return;
119
+
120
+ if (response.status) {
121
+ console.log('[FountainPay] Auth successful.');
122
+ if (response.payload?.access_token) {
123
+ getFPStore().setAccessToken(
124
+ response.payload.access_token,
125
+ response.payload.expires_in
126
+ );
127
+
128
+ const banks: any = await transferAPI.getBanks();
129
+ if (banks.status) {
130
+ getFPStore().setBanks(banks.payload);
131
+ }
132
+ }
133
+ setAuthenticated(true);
134
+ } else {
135
+ console.error('[FountainPay] Auth failed:', response.message);
136
+ setAuthenticated(false, response.message);
137
+ }
138
+ } catch (err: any) {
139
+ if (cancelled) return;
140
+ console.error('[FountainPay] Auth error:', err.message);
141
+ setAuthenticated(false, err.message);
142
+ }
143
+ };
144
+
145
+ console.log('Calling authentication');
146
+ authenticate();
147
+ return () => {
148
+ cancelled = true;
149
+ };
150
+ }, [apiKey]);
73
151
 
74
152
  // Build the instance once per provider lifetime.
75
153
  // All components that call useFountainPay() share this exact object.
76
154
  const instance = useMemo<FPInstance>(() => {
77
- console.log('[FountainPay] Creating shared FPInstance for apiKey:', apiKey.slice(0, 8) + '...');
155
+ console.log(
156
+ '[FountainPay] Creating shared FPInstance for apiKey:',
157
+ apiKey.slice(0, 8) + '...'
158
+ );
78
159
 
79
160
  return {
80
161
  /**
81
162
  * Call once after the user logs in.
82
163
  * Starts BLE advertising, proximity broadcast, and the payment listener.
83
164
  */
84
- async initializeSDK(user: FPUserInfo, callbacks?: FPCallbacks): Promise<void> {
85
- console.log('[FountainPay] initializeSDK() called for user:', user.name);
165
+ async initializeSDK(
166
+ user: FPUserInfo,
167
+ callbacks?: FPCallbacks
168
+ ): Promise<void> {
169
+ console.log(
170
+ '[FountainPay] initializeSDK() called for user:',
171
+ user.firstName
172
+ );
86
173
  try {
87
- await FPEngine.initialize(apiKey, user, options ?? {}, callbacks ?? {});
174
+ await FPEngine.initialize(
175
+ apiKey,
176
+ user,
177
+ options ?? {},
178
+ callbacks ?? {}
179
+ );
180
+ await FPEngine.initialize(apiKey, user, options ?? {}, {
181
+ ...callbacks,
182
+ onPaymentSent: async (tx) => {
183
+ callbacks?.onPaymentSent?.(tx);
184
+ await FPEngine.refreshBalance();
185
+ FPEngine.closeSend(); // ← close on success
186
+ },
187
+ onError: (err) => {
188
+ callbacks?.onError?.(err);
189
+ FPEngine.closeSend(); // ← close on error
190
+ },
191
+ });
88
192
  console.log('[FountainPay] initializeSDK() complete. SDK is ready.');
89
193
  } catch (err) {
90
194
  console.error('[FountainPay] initializeSDK() FAILED:', err);
@@ -93,13 +197,31 @@ export function FountainPayProvider({ apiKey, options, children }: ProviderProps
93
197
  },
94
198
 
95
199
  setAccountDetails(account: FPTransferRecipient): void {
96
- console.log('[FountainPay] setAccountDetails() called for user:', account.accountName);
200
+ console.log(
201
+ '[FountainPay] setAccountDetails() called for user:',
202
+ account.accountName
203
+ );
97
204
  FPEngine.setAccountDetails(account);
98
205
  },
99
206
 
100
207
  /** Open the Send Money bottom sheet. */
101
208
  send(amount: number, currency: FPCurrency): void {
102
209
  console.log('[FountainPay] send() called:', amount, currency);
210
+ console.log('[FountainPay] send() called:', amount, currency);
211
+ console.log('[FountainPay] balance in store:', getFPStore().balance);
212
+ console.log('[FountainPay] balance type:', typeof getFPStore().balance);
213
+
214
+ const balance = getFPStore().balance ?? 0;
215
+ console.log('Balance: ', balance);
216
+ if (Number(amount) > Number(balance)) {
217
+ console.error('[FountainPay] Insufficient balance.');
218
+ FPEngine.getCallbacks().onError?.({
219
+ code: 'INSUFFICIENT_BALANCE',
220
+ message: `Insufficient balance. Available: ${balance}`,
221
+ });
222
+ return; // ← stops here, FPShell never opens
223
+ }
224
+
103
225
  FPEngine.showSend(amount, currency);
104
226
  },
105
227
 
@@ -110,9 +232,12 @@ export function FountainPayProvider({ apiKey, options, children }: ProviderProps
110
232
  },
111
233
 
112
234
  /** Generate a virtual account number (no UI shown). */
113
- async generateAccountNumber(request: FPGenerateAccountRequest): Promise<FPVirtualAccount> {
114
- console.log('[FountainPay] generateAccountNumber() called:', request.accountName);
115
- return FPEngine.generateAccount(request);
235
+ async generateAccountNumber(user: FPUserInfo): Promise<FPAccount> {
236
+ console.log(
237
+ '[FountainPay] generateAccountNumber() called:',
238
+ user.firstName
239
+ );
240
+ return FPEngine.generateAccount(user);
116
241
  },
117
242
 
118
243
  /**
@@ -121,7 +246,9 @@ export function FountainPayProvider({ apiKey, options, children }: ProviderProps
121
246
  * modal will appear automatically.
122
247
  */
123
248
  listen(): void {
124
- console.log('[FountainPay] listen() called — activating BT payment listener.');
249
+ console.log(
250
+ '[FountainPay] listen() called — activating BT payment listener.'
251
+ );
125
252
  FPEngine.startListening();
126
253
  },
127
254
 
@@ -132,16 +259,30 @@ export function FountainPayProvider({ apiKey, options, children }: ProviderProps
132
259
  console.log('[FountainPay] All services stopped.');
133
260
  },
134
261
 
262
+ async refreshBalance(): Promise<void> {
263
+ await FPEngine.refreshBalance();
264
+ },
265
+
135
266
  get isReady(): boolean {
136
267
  return FPEngine.isReady();
137
268
  },
138
-
269
+ get isAuthenticated(): boolean {
270
+ return isAuthenticated;
271
+ },
272
+ get authError(): string | null {
273
+ return authError;
274
+ },
275
+ get account(): FPAccount | null {
276
+ return account;
277
+ },
139
278
  get currentUser(): FPUserInfo | null {
140
- return FPEngine.getUser();
279
+ return user;
280
+ },
281
+ get balance(): number | null {
282
+ return balance;
141
283
  },
142
284
  };
143
- // Re-create instance only if the apiKey changes (which should never happen at runtime)
144
- }, [apiKey]);
285
+ }, [apiKey, isAuthenticated, authError, account, user, balance]);
145
286
 
146
287
  return (
147
288
  <FountainPayContext.Provider value={instance}>
@@ -4,24 +4,40 @@
4
4
 
5
5
  import axios, { type AxiosInstance } from 'axios';
6
6
  import type { FPError } from '../types';
7
+ import { getFPStore } from '../../store/FPStore';
7
8
 
8
- const DEFAULT_BASE_URL = 'https://api.fountainpay.ng/sdk/detect/';
9
+ const DEFAULT_BASE_URL =
10
+ 'https://30a6-102-89-83-67.ngrok-free.app/sdk/v1/fpip/';
9
11
 
10
12
  let _client: AxiosInstance | null = null;
11
13
 
12
- export function initClient(apiKey: string, options: { baseUrl?: string; environment?: string } = {}): void {
14
+ export function initClient(
15
+ apiKey: string,
16
+ options: { baseUrl?: string; environment?: string } = {}
17
+ ): void {
13
18
  _client = axios.create({
14
19
  baseURL: options.baseUrl ?? DEFAULT_BASE_URL,
15
20
  timeout: 30000,
16
21
  headers: {
17
22
  'Content-Type': 'application/json',
18
23
  'x-api-key': apiKey,
24
+ 'x-api-client': 'modal',
19
25
  'x-sdk': 'react-native-fountainpay-sdk',
20
26
  'x-sdk-version': '1.0.0',
21
27
  'x-env': options.environment ?? 'production',
22
28
  },
23
29
  });
24
30
 
31
+ // Attach Authorization header on every request — reads token fresh from
32
+ // store each time so it's always current after login
33
+ _client.interceptors.request.use((config) => {
34
+ const accessToken = getFPStore().accessToken;
35
+ if (accessToken) {
36
+ config.headers.Authorization = `Bearer ${accessToken}`;
37
+ }
38
+ return config;
39
+ });
40
+
25
41
  _client.interceptors.response.use(
26
42
  (r) => r,
27
43
  (err) => {
@@ -34,7 +50,10 @@ export function initClient(apiKey: string, options: { baseUrl?: string; environm
34
50
  e.code = d.code ?? `HTTP_${err.response.status}`;
35
51
  e.message = d.message ?? err.message;
36
52
  e.statusCode = err.response.status;
37
- if (err.response.status === 401) { e.code = 'INVALID_API_KEY'; e.message = 'Invalid API key.'; }
53
+ if (err.response.status === 401) {
54
+ e.code = 'INVALID_API_KEY';
55
+ e.message = 'Invalid API key.';
56
+ }
38
57
  }
39
58
  return Promise.reject(e);
40
59
  }
@@ -42,6 +61,9 @@ export function initClient(apiKey: string, options: { baseUrl?: string; environm
42
61
  }
43
62
 
44
63
  export function http(): AxiosInstance {
45
- if (!_client) throw new Error('[FountainPay] SDK not initialized. Call pay.initializeSDK() first.');
64
+ if (!_client)
65
+ throw new Error(
66
+ '[FountainPay] SDK not initialized. Call pay.initializeSDK() first.'
67
+ );
46
68
  return _client;
47
69
  }
@@ -1,76 +1,197 @@
1
1
  // FountainPay SDK — All API calls
2
- import { http } from "./client";
2
+ import { http } from './client';
3
3
  import type {
4
- FPVirtualAccount,
5
- FPGenerateAccountRequest,
6
4
  FPBankItem,
7
- FPTransaction,
8
- FPNQRData,
9
- FPTxStatus,
5
+ FPTransaction,
6
+ FPNQRData,
7
+ FPTxStatus,
10
8
  FPProximityPeer,
11
9
  FPSendPaymentRequest,
12
- } from "../types";
10
+ FPUserInfo,
11
+ FPAccount,
12
+ FPSendWalletPaymentRequest,
13
+ FPTransactionResponse,
14
+ } from '../types';
15
+
16
+ export const healthAPI = {
17
+ ping: () =>
18
+ http()
19
+ .get('/health')
20
+ .then((r) => r.data),
21
+ };
22
+
23
+ export const authenticateAPI = {
24
+ login: (apiKey: string) =>
25
+ http()
26
+ .post('/auth', { api_key: apiKey })
27
+ .then((r) => r.data),
28
+
29
+ profile: (userId: string) =>
30
+ http()
31
+ .get(`/get-user-details/${userId}`)
32
+ .then((r) => r.data),
13
33
 
14
- export const walletAPI = {
15
- generate: (req: FPGenerateAccountRequest) =>
16
- http().post<FPVirtualAccount>("/wallet/generate", req).then(r => r.data),
34
+ logout: () =>
35
+ http()
36
+ .post('/auth/logout')
37
+ .then((r) => r.data),
38
+
39
+ validateOtp: (otp: string, email: string) =>
40
+ http()
41
+ .post<{ Response: any }>('/verify-otp', { otp, email })
42
+ .then((r) => r.data),
43
+ };
17
44
 
18
- getBalance: (walletId: string) =>
19
- http().get<{ balance: number; currency: string }>("/wallet/" + walletId + "/balance").then(r => r.data),
45
+ export const accountAPI = {
46
+ generate: (user: FPUserInfo) =>
47
+ http()
48
+ .post<{ payload: FPAccount }>('/generate-virtual-account', {
49
+ first_name: user.firstName,
50
+ last_name: user.lastName,
51
+ phone_no: user.phone,
52
+ email: user.email,
53
+ bvn: user.bvn ?? '',
54
+ nin: user.nin ?? '',
55
+ dateOfBirth: user.dateOfBirth ?? '',
56
+ })
57
+ .then((r) => r.data.payload),
58
+
59
+ // Get user profile using PSSP id
60
+ getUser: (psspId: string) =>
61
+ http()
62
+ .get<{ payload: FPAccount }>(`/get-user-details/${psspId}`)
63
+ .then((r) => r.data.payload),
64
+
65
+ // Get account details using PSSP id
66
+ getAccount: (psspId: string) =>
67
+ http()
68
+ .get<{ payload: FPAccount }>(`/get-accounts-details/${psspId}`)
69
+ .then((r) => r.data.payload),
70
+
71
+ // Get balance using PSSP id
72
+ getBalance: (psspId: string) =>
73
+ http()
74
+ .get<{ payload: { balance: number; currency: string } }>(
75
+ `/get-balance/${psspId}`
76
+ )
77
+ .then((r) => r.data.payload),
20
78
  };
21
79
 
22
80
  export const transferAPI = {
23
81
  getBanks: () =>
24
- http().get<FPBankItem[]>("/banks").then(r => r.data),
82
+ http()
83
+ .get<FPBankItem[]>('/get-banks')
84
+ .then((r) => r.data),
25
85
 
26
86
  verifyAccount: (accountNumber: string, bankCode: string) =>
27
- http().post<{ accountName: string; accountNumber: string; bankName: string; bankCode: string }>(
28
- "/transfer/verify-account", { accountNumber, bankCode }
29
- ).then(r => r.data),
30
-
31
- send: (
32
- payload: FPSendPaymentRequest
33
- ) =>
34
- http().post<FPTransaction>("/transfer/initiate", payload).then(r => r.data),
87
+ http()
88
+ .post<{
89
+ accountName: string;
90
+ accountNumber: string;
91
+ bankName: string;
92
+ bankCode: string;
93
+ }>('/name-enquiry', {
94
+ account_no: accountNumber,
95
+ institution_code: bankCode,
96
+ })
97
+ .then((r) => r.data),
98
+
99
+ verifyWalletAccount: (accountNumber: string) =>
100
+ http()
101
+ .post<{
102
+ accountName: string;
103
+ accountNumber: string;
104
+ bankName: string;
105
+ bankCode: string;
106
+ }>('/wallet-name-enquiry', { account_number: accountNumber })
107
+ .then((r) => r.data),
108
+
109
+ validateTransfer: (pin: string, userId: string) =>
110
+ http()
111
+ .post<{ status: boolean; message: string }>('/validate-transaction', {
112
+ pin,
113
+ user_id: userId,
114
+ })
115
+ .then((r) => r.data),
116
+
117
+ sendToWallet: (payload: FPSendWalletPaymentRequest, temptId: string) =>
118
+ http()
119
+ .post<{ payload: FPTransactionResponse }>('/wallet-transfer-funds', {
120
+ ...payload,
121
+ temp_id: temptId,
122
+ })
123
+ .then((r) => r.data.payload),
124
+
125
+ // Send to external bank account
126
+ sendToBank: (payload: FPSendPaymentRequest, temptId: string) =>
127
+ http()
128
+ .post<{ payload: FPTransactionResponse }>('/transfer-funds', {
129
+ ...payload,
130
+ temp_id: temptId,
131
+ })
132
+ .then((r) => r.data.payload),
133
+
134
+ status: (reference: string) =>
135
+ http()
136
+ .get<{ status: FPTxStatus; reference: string }>(
137
+ '/query-transaction-status/' + reference
138
+ )
139
+ .then((r) => r.data),
140
+
141
+ verify: (reference: string) =>
142
+ http()
143
+ .get<{ FPTransactionResponse: any }>('/transaction/verify/' + reference)
144
+ .then((r) => r.data),
35
145
  };
36
146
 
37
147
  export const nqrAPI = {
38
- generate: (payload: { amount?: number; reference?: string; currency?: string; expiresInMinutes?: number }) =>
39
- http().post<FPNQRData>("/payment/nqr/generate", payload).then(r => r.data),
40
-
41
- pay: (payload: FPSendPaymentRequest) =>
42
- http().post<FPTransaction>("/payment/nqr/pay", payload).then(r => r.data),
148
+ generate: (payload: {
149
+ amount?: number;
150
+ reference?: string;
151
+ currency?: string;
152
+ expiresInMinutes?: number;
153
+ }) =>
154
+ http()
155
+ .post<FPNQRData>('/generate-nqr', payload)
156
+ .then((r) => r.data),
157
+
158
+ pay: (payload: FPSendPaymentRequest, temptId: string) =>
159
+ http()
160
+ .post<FPTransactionResponse>('/pay-nqr', { ...payload, temp_id: temptId })
161
+ .then((r) => r.data),
43
162
  };
44
163
 
45
164
  export const nfcAPI = {
46
- pay: (payload: FPSendPaymentRequest) =>
47
- http().post<FPTransaction>("/payment/nfc/pay", payload).then(r => r.data),
165
+ pay: (payload: FPSendPaymentRequest, temptId: string) =>
166
+ http()
167
+ .post<FPTransactionResponse>('/pay-nfc', { ...payload, temp_id: temptId })
168
+ .then((r) => r.data),
48
169
  };
49
170
 
50
171
  export const proximityAPI = {
51
- broadcast: (payload: { latitude: number; longitude: number; user: string; email: string; accountName: string; accountNumber: string; bankCode: string; bankName: string }) =>
52
- http().post<{ sessionId: string }>("/proximity/broadcast", payload).then(r => r.data),
172
+ broadcast: (
173
+ psspId: string,
174
+ payload: { latitude: number; longitude: number; user_type: string }
175
+ ) =>
176
+ http()
177
+ .post<{ sessionId: string }>(`/broadcast-proximity/${psspId}`, payload)
178
+ .then((r) => r.data),
53
179
 
54
180
  heartbeat: (sessionId: string, lat: number, lng: number) =>
55
- http().patch("/proximity/broadcast/" + sessionId, { latitude: lat, longitude: lng }),
181
+ http().patch(`/broadcast-proximity/${sessionId}`, {
182
+ latitude: lat,
183
+ longitude: lng,
184
+ }),
56
185
 
57
186
  unregister: (sessionId: string) =>
58
- http().delete("/proximity/broadcast/" + sessionId),
59
-
60
- discover: (lat: number, lng: number, radiusMeters: number) =>
61
- http().post<{ peers: FPProximityPeer[] }>(
62
- "/proximity/discover", { latitude: lat, longitude: lng, radiusMeters }
63
- ).then(r => r.data.peers),
64
- };
65
-
66
-
67
- export const transactionAPI = {
68
- status: (reference: string) =>
69
- http().get<{ status: FPTxStatus; reference: string }>("/transaction/verify/" + reference).then(r => r.data),
70
-
71
- verify: (reference: string) =>
72
- http().get<{ FPTransaction: any }>("/transaction/verify/" + reference).then(r => r.data),
73
-
74
- validateOtp: (otp: string, email: string) =>
75
- http().post<{Response: any}>("/verify-otp", {otp, email}).then(r=>r.data)
187
+ http().delete('/broadcast-proximity/' + sessionId),
188
+
189
+ discover: (psspId: string, lat: number, lng: number, radius_meters: number) =>
190
+ http()
191
+ .post<{ peers: FPProximityPeer[] }>(`/discover-proximity/${psspId}`, {
192
+ latitude: lat,
193
+ longitude: lng,
194
+ radius_meters,
195
+ })
196
+ .then((r) => r.data),
76
197
  };