react-native-fpay 0.3.5 → 0.3.7

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 +108 -18
  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 -4
  118. package/src/FountainPayProvider.tsx +163 -24
  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
@@ -10,10 +10,16 @@
10
10
  // <YourApp />
11
11
  // </FountainPayProvider>
12
12
  // ─────────────────────────────────────────────────────────────────────────────
13
- import React, {
14
- type ReactNode, createContext, useContext, useMemo, useRef,
13
+ import {
14
+ type ReactNode,
15
+ createContext,
16
+ useContext,
17
+ useEffect,
18
+ useMemo,
19
+ useRef,
15
20
  } from 'react';
16
21
  import { FPShell } from './ui/modals/FPShell';
22
+ import { useFPStore, getFPStore, isTokenValid } from './store/FPStore';
17
23
  import { FPEngine } from './engine/FPEngine';
18
24
  import { initClient } from './core/api/client';
19
25
  import type {
@@ -22,10 +28,10 @@ import type {
22
28
  FPSDKOptions,
23
29
  FPCallbacks,
24
30
  FPCurrency,
25
- FPGenerateAccountRequest,
26
- FPVirtualAccount,
27
31
  FPTransferRecipient,
32
+ FPAccount,
28
33
  } from './core/types';
34
+ import { authenticateAPI, transferAPI } from './core/api';
29
35
 
30
36
  // ── Context ───────────────────────────────────────────────────────────────────
31
37
 
@@ -47,7 +53,7 @@ export function useFountainPay(): FPInstance {
47
53
  if (!instance) {
48
54
  throw new Error(
49
55
  '[FountainPay] useFountainPay() must be called inside <FountainPayProvider>.\n' +
50
- 'Make sure you have wrapped your app root with <FountainPayProvider apiKey="...">.'
56
+ 'Make sure you have wrapped your app root with <FountainPayProvider apiKey="...">.'
51
57
  );
52
58
  }
53
59
  return instance;
@@ -61,30 +67,126 @@ interface ProviderProps {
61
67
  children: ReactNode;
62
68
  }
63
69
 
64
- export function FountainPayProvider({ apiKey, options, children }: ProviderProps) {
70
+ export function FountainPayProvider({
71
+ apiKey,
72
+ options,
73
+ children,
74
+ }: ProviderProps) {
65
75
  // Boot the HTTP client as soon as the provider mounts —
66
76
  // this means generateAccountNumber works even before initializeSDK
67
77
  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
- }
78
+
79
+ const isAuthenticated = useFPStore((s) => s.isAuthenticated);
80
+ const authError = useFPStore((s) => s.authError);
81
+ const setAuthenticated = useFPStore((s) => s.setAuthenticated);
82
+ const account = useFPStore((s) => s.account);
83
+ const user = useFPStore((s) => s.user);
84
+ const balance = useFPStore((s) => s.balance);
85
+
86
+ console.log('[FPStore] user:', user);
87
+ console.log('[FPStore] account:', account);
88
+
89
+ useEffect(() => {
90
+ let cancelled = false;
91
+
92
+ // Make sure client is initialized before any API call
93
+ console.log('[FountainPay] Provider mounted. HTTP client ready.', options);
94
+ if (!clientBooted.current) {
95
+ initClient(apiKey, {
96
+ baseUrl: options?.baseUrl,
97
+ environment: options?.environment,
98
+ });
99
+ clientBooted.current = true;
100
+ console.log(
101
+ '[FountainPay] Provider mounted. HTTP client ready.: ',
102
+ options
103
+ );
104
+ }
105
+
106
+ const authenticate = async () => {
107
+ if (isTokenValid()) {
108
+ console.log('[FountainPay] Valid token found — skipping auth.');
109
+ setAuthenticated(true);
110
+ return;
111
+ }
112
+
113
+ try {
114
+ console.log('[FountainPay] Verifying API key...');
115
+ const response = await authenticateAPI.login(apiKey);
116
+ if (cancelled) return;
117
+
118
+ if (response.status) {
119
+ console.log('[FountainPay] Auth successful.');
120
+ if (response.payload?.access_token) {
121
+ getFPStore().setAccessToken(
122
+ response.payload.access_token,
123
+ response.payload.expires_in
124
+ );
125
+
126
+ const banks: any = await transferAPI.getBanks();
127
+ if (banks.status) {
128
+ getFPStore().setBanks(banks.payload);
129
+ }
130
+ }
131
+ setAuthenticated(true);
132
+ } else {
133
+ console.error('[FountainPay] Auth failed:', response.message);
134
+ setAuthenticated(false, response.message);
135
+ }
136
+ } catch (err: any) {
137
+ if (cancelled) return;
138
+ console.error('[FountainPay] Auth error:', err.message);
139
+ setAuthenticated(false, err.message);
140
+ }
141
+ };
142
+
143
+ console.log('Calling authentication');
144
+ authenticate();
145
+ return () => {
146
+ cancelled = true;
147
+ };
148
+ }, [apiKey]);
73
149
 
74
150
  // Build the instance once per provider lifetime.
75
151
  // All components that call useFountainPay() share this exact object.
76
152
  const instance = useMemo<FPInstance>(() => {
77
- console.log('[FountainPay] Creating shared FPInstance for apiKey:', apiKey.slice(0, 8) + '...');
153
+ console.log(
154
+ '[FountainPay] Creating shared FPInstance for apiKey:',
155
+ apiKey.slice(0, 8) + '...'
156
+ );
78
157
 
79
158
  return {
80
159
  /**
81
160
  * Call once after the user logs in.
82
161
  * Starts BLE advertising, proximity broadcast, and the payment listener.
83
162
  */
84
- async initializeSDK(user: FPUserInfo, callbacks?: FPCallbacks): Promise<void> {
85
- console.log('[FountainPay] initializeSDK() called for user:', user.name);
163
+ async initializeSDK(
164
+ user: FPUserInfo,
165
+ callbacks?: FPCallbacks
166
+ ): Promise<void> {
167
+ console.log(
168
+ '[FountainPay] initializeSDK() called for user:',
169
+ user.firstName
170
+ );
86
171
  try {
87
- await FPEngine.initialize(apiKey, user, options ?? {}, callbacks ?? {});
172
+ await FPEngine.initialize(
173
+ apiKey,
174
+ user,
175
+ options ?? {},
176
+ callbacks ?? {}
177
+ );
178
+ await FPEngine.initialize(apiKey, user, options ?? {}, {
179
+ ...callbacks,
180
+ onPaymentSent: async (tx) => {
181
+ callbacks?.onPaymentSent?.(tx);
182
+ await FPEngine.refreshBalance();
183
+ FPEngine.closeSend(); // ← close on success
184
+ },
185
+ onError: (err) => {
186
+ callbacks?.onError?.(err);
187
+ FPEngine.closeSend(); // ← close on error
188
+ },
189
+ });
88
190
  console.log('[FountainPay] initializeSDK() complete. SDK is ready.');
89
191
  } catch (err) {
90
192
  console.error('[FountainPay] initializeSDK() FAILED:', err);
@@ -93,13 +195,31 @@ export function FountainPayProvider({ apiKey, options, children }: ProviderProps
93
195
  },
94
196
 
95
197
  setAccountDetails(account: FPTransferRecipient): void {
96
- console.log('[FountainPay] setAccountDetails() called for user:', account.accountName);
198
+ console.log(
199
+ '[FountainPay] setAccountDetails() called for user:',
200
+ account.accountName
201
+ );
97
202
  FPEngine.setAccountDetails(account);
98
203
  },
99
204
 
100
205
  /** Open the Send Money bottom sheet. */
101
206
  send(amount: number, currency: FPCurrency): void {
102
207
  console.log('[FountainPay] send() called:', amount, currency);
208
+ console.log('[FountainPay] send() called:', amount, currency);
209
+ console.log('[FountainPay] balance in store:', getFPStore().balance);
210
+ console.log('[FountainPay] balance type:', typeof getFPStore().balance);
211
+
212
+ const balance = getFPStore().balance ?? 0;
213
+ console.log('Balance: ', balance);
214
+ if (Number(amount) > Number(balance)) {
215
+ console.error('[FountainPay] Insufficient balance.');
216
+ FPEngine.getCallbacks().onError?.({
217
+ code: 'INSUFFICIENT_BALANCE',
218
+ message: `Insufficient balance. Available: ${balance}`,
219
+ });
220
+ return; // ← stops here, FPShell never opens
221
+ }
222
+
103
223
  FPEngine.showSend(amount, currency);
104
224
  },
105
225
 
@@ -110,9 +230,12 @@ export function FountainPayProvider({ apiKey, options, children }: ProviderProps
110
230
  },
111
231
 
112
232
  /** 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);
233
+ async generateAccountNumber(user: FPUserInfo): Promise<FPAccount> {
234
+ console.log(
235
+ '[FountainPay] generateAccountNumber() called:',
236
+ user.firstName
237
+ );
238
+ return FPEngine.generateAccount(user);
116
239
  },
117
240
 
118
241
  /**
@@ -121,7 +244,9 @@ export function FountainPayProvider({ apiKey, options, children }: ProviderProps
121
244
  * modal will appear automatically.
122
245
  */
123
246
  listen(): void {
124
- console.log('[FountainPay] listen() called — activating BT payment listener.');
247
+ console.log(
248
+ '[FountainPay] listen() called — activating BT payment listener.'
249
+ );
125
250
  FPEngine.startListening();
126
251
  },
127
252
 
@@ -132,16 +257,30 @@ export function FountainPayProvider({ apiKey, options, children }: ProviderProps
132
257
  console.log('[FountainPay] All services stopped.');
133
258
  },
134
259
 
260
+ async refreshBalance(): Promise<void> {
261
+ await FPEngine.refreshBalance();
262
+ },
263
+
135
264
  get isReady(): boolean {
136
265
  return FPEngine.isReady();
137
266
  },
138
-
267
+ get isAuthenticated(): boolean {
268
+ return isAuthenticated;
269
+ },
270
+ get authError(): string | null {
271
+ return authError;
272
+ },
273
+ get account(): FPAccount | null {
274
+ return account;
275
+ },
139
276
  get currentUser(): FPUserInfo | null {
140
- return FPEngine.getUser();
277
+ return user;
278
+ },
279
+ get balance(): number | null {
280
+ return balance;
141
281
  },
142
282
  };
143
- // Re-create instance only if the apiKey changes (which should never happen at runtime)
144
- }, [apiKey]);
283
+ }, [apiKey, isAuthenticated, authError, account, user, balance]);
145
284
 
146
285
  return (
147
286
  <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
  };