react-native-fpay 0.4.19 → 0.4.21
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/lib/module/FountainPayProvider.js +50 -126
- package/lib/module/FountainPayProvider.js.map +1 -1
- package/lib/module/core/api/client.js +1 -1
- package/lib/module/core/api/index.js +16 -12
- package/lib/module/core/api/index.js.map +1 -1
- package/lib/module/core/types/index.js +1 -1
- package/lib/module/core/types/index.js.map +1 -1
- package/lib/module/engine/FPEngine.js +27 -16
- package/lib/module/engine/FPEngine.js.map +1 -1
- package/lib/module/store/FPStore.js +11 -4
- package/lib/module/store/FPStore.js.map +1 -1
- package/lib/module/ui/components/ConfirmScreen.js +2 -2
- package/lib/module/ui/components/ConfirmScreen.js.map +1 -1
- package/lib/module/ui/modals/FPCreatePin.js +234 -0
- package/lib/module/ui/modals/FPCreatePin.js.map +1 -0
- package/lib/module/ui/modals/FPShell.js +7 -3
- package/lib/module/ui/modals/FPShell.js.map +1 -1
- package/lib/module/ui/modals/FPValidateBvn.js +258 -0
- package/lib/module/ui/modals/FPValidateBvn.js.map +1 -0
- package/lib/module/ui/screens/ResultScreen.js +4 -17
- package/lib/module/ui/screens/ResultScreen.js.map +1 -1
- package/lib/module/ui/screens/SendScreen.js +24 -9
- package/lib/module/ui/screens/SendScreen.js.map +1 -1
- package/lib/module/ui/screens/sub/sendPayment/ProximitySubScreen.js +3 -3
- package/lib/module/ui/screens/sub/sendPayment/ProximitySubScreen.js.map +1 -1
- package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js +8 -1
- package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js.map +1 -1
- package/lib/typescript/src/FountainPayProvider.d.ts +3 -4
- package/lib/typescript/src/FountainPayProvider.d.ts.map +1 -1
- package/lib/typescript/src/core/api/index.d.ts +20 -20
- package/lib/typescript/src/core/api/index.d.ts.map +1 -1
- package/lib/typescript/src/core/types/index.d.ts +16 -6
- package/lib/typescript/src/core/types/index.d.ts.map +1 -1
- package/lib/typescript/src/engine/FPEngine.d.ts +3 -0
- package/lib/typescript/src/engine/FPEngine.d.ts.map +1 -1
- package/lib/typescript/src/store/FPStore.d.ts +8 -5
- package/lib/typescript/src/store/FPStore.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/ConfirmScreen.d.ts +1 -2
- package/lib/typescript/src/ui/components/ConfirmScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/modals/FPCreatePin.d.ts +3 -0
- package/lib/typescript/src/ui/modals/FPCreatePin.d.ts.map +1 -0
- package/lib/typescript/src/ui/modals/FPShell.d.ts.map +1 -1
- package/lib/typescript/src/ui/modals/FPValidateBvn.d.ts +3 -0
- package/lib/typescript/src/ui/modals/FPValidateBvn.d.ts.map +1 -0
- package/lib/typescript/src/ui/screens/ResultScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/SendScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/TransferSubScreen.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/FountainPayProvider.tsx +59 -149
- package/src/core/api/client.ts +1 -1
- package/src/core/api/index.ts +56 -52
- package/src/core/types/index.ts +18 -5
- package/src/engine/FPEngine.ts +34 -17
- package/src/store/FPStore.ts +15 -8
- package/src/ui/components/ConfirmScreen.tsx +4 -3
- package/src/ui/modals/FPCreatePin.tsx +206 -0
- package/src/ui/modals/FPShell.tsx +16 -2
- package/src/ui/modals/FPValidateBvn.tsx +229 -0
- package/src/ui/screens/ResultScreen.tsx +6 -10
- package/src/ui/screens/SendScreen.tsx +60 -36
- package/src/ui/screens/sub/sendPayment/ProximitySubScreen.tsx +3 -3
- package/src/ui/screens/sub/sendPayment/TransferSubScreen.tsx +7 -1
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
// the SAME instance — no re-initialization, no prop drilling.
|
|
7
7
|
//
|
|
8
8
|
// Usage:
|
|
9
|
-
// <FountainPayProvider
|
|
9
|
+
// <FountainPayProvider appId="...">
|
|
10
10
|
// <YourApp />
|
|
11
11
|
// </FountainPayProvider>
|
|
12
12
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -32,7 +32,7 @@ import type {
|
|
|
32
32
|
FPAccount,
|
|
33
33
|
FPBalance,
|
|
34
34
|
} from './core/types';
|
|
35
|
-
import { authenticateAPI, transferAPI } from './core/api';
|
|
35
|
+
import { accountAPI, authenticateAPI, transferAPI } from './core/api';
|
|
36
36
|
|
|
37
37
|
// ── Context ───────────────────────────────────────────────────────────────────
|
|
38
38
|
|
|
@@ -54,26 +54,23 @@ export function useFountainPay(): FPInstance {
|
|
|
54
54
|
if (!instance) {
|
|
55
55
|
throw new Error(
|
|
56
56
|
'[FountainPay] useFountainPay() must be called inside <FountainPayProvider>.\n' +
|
|
57
|
-
'Make sure you have wrapped your app root with <FountainPayProvider
|
|
57
|
+
'Make sure you have wrapped your app root with <FountainPayProvider appId="...">.'
|
|
58
58
|
);
|
|
59
59
|
}
|
|
60
60
|
return instance;
|
|
61
61
|
}
|
|
62
|
-
|
|
63
62
|
// ── Provider ──────────────────────────────────────────────────────────────────
|
|
64
63
|
|
|
65
64
|
interface ProviderProps {
|
|
66
|
-
|
|
67
|
-
accessToken?: string;
|
|
65
|
+
appId: string;
|
|
68
66
|
options?: FPSDKOptions;
|
|
69
67
|
children: ReactNode;
|
|
70
|
-
onAuthReady?: () => void;
|
|
68
|
+
onAuthReady?: (account?: any) => void;
|
|
71
69
|
onAuthError?: (error: string) => void;
|
|
72
70
|
}
|
|
73
71
|
|
|
74
72
|
export function FountainPayProvider({
|
|
75
|
-
|
|
76
|
-
accessToken,
|
|
73
|
+
appId,
|
|
77
74
|
options,
|
|
78
75
|
children,
|
|
79
76
|
onAuthReady,
|
|
@@ -89,9 +86,8 @@ export function FountainPayProvider({
|
|
|
89
86
|
const account = useFPStore((s) => s.account);
|
|
90
87
|
const user = useFPStore((s) => s.user);
|
|
91
88
|
const balance = useFPStore((s) => s.balance);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
89
|
+
const resetToken = useFPStore((s) => s.clearAccessToken);
|
|
90
|
+
const clearUser = useFPStore((s) => s.clearUser);
|
|
95
91
|
|
|
96
92
|
|
|
97
93
|
useEffect(() => {
|
|
@@ -100,11 +96,8 @@ export function FountainPayProvider({
|
|
|
100
96
|
// Make sure client is initialized before any API call
|
|
101
97
|
console.log('[FountainPay] Provider mounted. HTTP client ready.', options);
|
|
102
98
|
if (!clientBooted.current) {
|
|
103
|
-
if (
|
|
104
|
-
getFPStore().
|
|
105
|
-
}
|
|
106
|
-
if (apiKey) {
|
|
107
|
-
getFPStore().setApiKey(apiKey); // ← store it
|
|
99
|
+
if (appId) {
|
|
100
|
+
getFPStore().setAppId(appId); // ← store it
|
|
108
101
|
}
|
|
109
102
|
|
|
110
103
|
initClient({
|
|
@@ -118,109 +111,59 @@ export function FountainPayProvider({
|
|
|
118
111
|
const authenticate = async () => {
|
|
119
112
|
// await resetToken();
|
|
120
113
|
// await clearUser();
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
onAuthError?.('accessToken is required for AGENT mode');
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
try {
|
|
131
|
-
console.log('[FountainPay] Agent mode — validating token...');
|
|
132
|
-
|
|
133
|
-
// Store the token first so the HTTP interceptor picks it up
|
|
134
|
-
getFPStore().setAccessToken(accessToken);
|
|
135
|
-
|
|
136
|
-
// Fetch agent profile from backend
|
|
137
|
-
const response = await authenticateAPI.validateToken();
|
|
138
|
-
if (cancelled) return;
|
|
139
|
-
|
|
140
|
-
if (response.status) {
|
|
141
|
-
const agent = response.payload;
|
|
142
|
-
|
|
143
|
-
// Build FPUserInfo from agent model
|
|
144
|
-
const user: FPUserInfo = {
|
|
145
|
-
firstName: agent.firstName,
|
|
146
|
-
lastName: agent.lastName,
|
|
147
|
-
email: agent.email,
|
|
148
|
-
phone: agent.phone ?? '',
|
|
149
|
-
bvn: agent.bvn,
|
|
150
|
-
userId: agent.id,
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
// Build FPAccount from agent model
|
|
154
|
-
const account: FPAccount = {
|
|
155
|
-
id: agent.id,
|
|
156
|
-
firstName: agent.firstName,
|
|
157
|
-
lastName: agent.lastName,
|
|
158
|
-
phone: agent.phone,
|
|
159
|
-
accountName: `${agent.firstName} ${agent.lastName}`.toUpperCase(),
|
|
160
|
-
accountNumber: agent.accountNumber,
|
|
161
|
-
bankName: agent.bankName,
|
|
162
|
-
bankCode: agent.bankCode, // populate if backend returns it
|
|
163
|
-
};
|
|
164
|
-
|
|
165
|
-
// Store everything — no need to call _resolveAccount
|
|
166
|
-
getFPStore().setUser(user);
|
|
167
|
-
getFPStore().setPsspId(agent.id);
|
|
168
|
-
getFPStore().setAccount(account);
|
|
169
|
-
|
|
170
|
-
await getFPStore().setAccessToken(accessToken, 86400);
|
|
171
|
-
|
|
172
|
-
const banks: any = await transferAPI.getBanks();
|
|
173
|
-
if (banks.status) {
|
|
174
|
-
getFPStore().setBanks(banks.payload);
|
|
175
|
-
console.log('[FountainPay] Banks cached:', banks.payload.length);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
setAuthenticated(true);
|
|
179
|
-
console.log('[FountainPay] Agent validated:', agent.firstName, agent.lastName);
|
|
180
|
-
|
|
181
|
-
onAuthReady?.();
|
|
182
|
-
} else {
|
|
183
|
-
getFPStore().clearAccessToken();
|
|
184
|
-
setAuthenticated(false, response.message);
|
|
185
|
-
onAuthError?.(response.message);
|
|
186
|
-
}
|
|
187
|
-
} catch (err: any) {
|
|
188
|
-
if (cancelled) return;
|
|
189
|
-
getFPStore().clearAccessToken();
|
|
190
|
-
setAuthenticated(false, err.message);
|
|
191
|
-
onAuthError?.(err.message);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
return; // ← don't fall through to PSSP auth
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
if (isTokenValid()) {
|
|
198
|
-
console.log('[FountainPay] Valid token found — skipping auth.');
|
|
199
|
-
setAuthenticated(true);
|
|
200
|
-
onAuthReady?.();
|
|
114
|
+
if (!appId) {
|
|
115
|
+
console.log('[FountainPay] No appId — new user flow. Waiting for initializeSDK.');
|
|
116
|
+
// Boot client without token — initializeSDK will handle everything
|
|
117
|
+
setAuthenticated(false);
|
|
118
|
+
onAuthReady?.(null);
|
|
201
119
|
return;
|
|
202
120
|
}
|
|
203
121
|
|
|
204
122
|
try {
|
|
205
123
|
console.log('[FountainPay] Verifying API key...');
|
|
206
|
-
const response = await authenticateAPI.login(
|
|
124
|
+
const response = await authenticateAPI.login(appId);
|
|
207
125
|
if (cancelled) return;
|
|
208
126
|
|
|
209
127
|
if (response.status) {
|
|
210
128
|
console.log('[FountainPay] Auth successful.');
|
|
211
|
-
|
|
212
|
-
getFPStore().setAccessToken(
|
|
213
|
-
response.payload.access_token,
|
|
214
|
-
response.payload.expires_in
|
|
215
|
-
);
|
|
129
|
+
const { access_token, expires_in } = response.payload;
|
|
216
130
|
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
131
|
+
// Store token
|
|
132
|
+
getFPStore().setAccessToken(access_token, expires_in ?? 86400);
|
|
133
|
+
|
|
134
|
+
const agentDetails = await authenticateAPI.profile();
|
|
135
|
+
if (agentDetails.status) {
|
|
136
|
+
|
|
221
137
|
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
// Build and store user
|
|
141
|
+
const user: any = agentDetails;
|
|
142
|
+
getFPStore().setUser(user);
|
|
143
|
+
getFPStore().setPsspId(agentDetails.uuid);
|
|
144
|
+
|
|
145
|
+
const agentAccount: any = await accountAPI.getAccount();
|
|
146
|
+
// Build and store account
|
|
147
|
+
const account: FPAccount = {
|
|
148
|
+
id: agentAccount.uuid,
|
|
149
|
+
ownerId: agentAccount.ownerId,
|
|
150
|
+
ownerType: agentAccount.ownerType,
|
|
151
|
+
accountName: agentAccount.accountName,
|
|
152
|
+
accountNumber: agentAccount.accountNumber,
|
|
153
|
+
bankName: agentAccount.bankName,
|
|
154
|
+
bankCode: agentAccount.bankCode,
|
|
155
|
+
currency: agentAccount.currency
|
|
156
|
+
};
|
|
157
|
+
getFPStore().setAccount(account);
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
const banks: any = await transferAPI.getBanks();
|
|
161
|
+
if (banks.status) getFPStore().setBanks(banks.payload);
|
|
162
|
+
} catch { /* non-fatal */ }
|
|
163
|
+
|
|
164
|
+
|
|
222
165
|
setAuthenticated(true);
|
|
223
|
-
onAuthReady?.();
|
|
166
|
+
onAuthReady?.(account);
|
|
224
167
|
} else {
|
|
225
168
|
console.error('[FountainPay] Auth failed:', response.message);
|
|
226
169
|
setAuthenticated(false, response.message);
|
|
@@ -234,62 +177,29 @@ export function FountainPayProvider({
|
|
|
234
177
|
}
|
|
235
178
|
};
|
|
236
179
|
|
|
237
|
-
console.log('Calling authentication');
|
|
180
|
+
console.log('Calling authentication with appId:', appId);
|
|
238
181
|
authenticate();
|
|
239
182
|
return () => {
|
|
240
183
|
cancelled = true;
|
|
241
184
|
};
|
|
242
|
-
}, [
|
|
243
|
-
|
|
244
|
-
useEffect(() => {
|
|
245
|
-
if (options?.userType !== 'AGENT') return;
|
|
246
|
-
if (!isAuthenticated) return;
|
|
247
|
-
|
|
248
|
-
const autoInitialize = async () => {
|
|
249
|
-
const store = getFPStore();
|
|
250
|
-
if (!store.user || !store.account) return;
|
|
251
|
-
|
|
252
|
-
console.log('[FountainPay] Agent mode — auto-initializing from stored data...');
|
|
253
|
-
await FPEngine.initialize(
|
|
254
|
-
store.user,
|
|
255
|
-
options ?? {},
|
|
256
|
-
{} // empty callbacks — host app sets these via initializeSDK if they want
|
|
257
|
-
);
|
|
258
|
-
console.log('[FountainPay] Agent auto-initialized.');
|
|
259
|
-
};
|
|
185
|
+
}, [appId]);
|
|
260
186
|
|
|
261
|
-
autoInitialize();
|
|
262
|
-
}, [isAuthenticated, options?.userType]);
|
|
263
187
|
|
|
264
|
-
// Build the instance once per provider lifetime.
|
|
265
|
-
// All components that call useFountainPay() share this exact object.
|
|
266
188
|
const instance = useMemo<FPInstance>(() => {
|
|
267
189
|
console.log(
|
|
268
|
-
'[FountainPay] Creating shared FPInstance for
|
|
269
|
-
|
|
190
|
+
'[FountainPay] Creating shared FPInstance for appId:',
|
|
191
|
+
appId?.toString().slice(0, 8) + '...'
|
|
270
192
|
);
|
|
271
193
|
|
|
272
194
|
return {
|
|
273
|
-
|
|
274
|
-
* Call once after the user logs in.
|
|
275
|
-
* Starts BLE advertising, proximity broadcast, and the payment listener.
|
|
276
|
-
*/
|
|
195
|
+
|
|
277
196
|
async initializeSDK(
|
|
278
197
|
user: FPUserInfo,
|
|
279
198
|
callbacks?: FPCallbacks
|
|
280
199
|
): Promise<void> {
|
|
281
|
-
console.log(
|
|
282
|
-
'[FountainPay] initializeSDK() called for user:',
|
|
283
|
-
user.firstName
|
|
284
|
-
);
|
|
200
|
+
console.log( '[FountainPay] initializeSDK() called for user:', user.firstName);
|
|
285
201
|
|
|
286
|
-
|
|
287
|
-
if (callbacks) {
|
|
288
|
-
FPEngine.updateCallbacks(callbacks); // just register callbacks
|
|
289
|
-
}
|
|
290
|
-
console.log('[FountainPay] Agent already initialized — callbacks updated.');
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
202
|
+
|
|
293
203
|
try {
|
|
294
204
|
|
|
295
205
|
await FPEngine.initialize(user, options ?? {}, {
|
|
@@ -390,7 +300,7 @@ export function FountainPayProvider({
|
|
|
390
300
|
return balance;
|
|
391
301
|
},
|
|
392
302
|
};
|
|
393
|
-
}, [
|
|
303
|
+
}, [appId, isAuthenticated, authError, account, user, balance]);
|
|
394
304
|
|
|
395
305
|
return (
|
|
396
306
|
<FountainPayContext.Provider value={instance}>
|
package/src/core/api/client.ts
CHANGED
|
@@ -7,7 +7,7 @@ import type { FPError } from '../types';
|
|
|
7
7
|
import { getFPStore } from '../../store/FPStore';
|
|
8
8
|
|
|
9
9
|
const DEFAULT_BASE_URL =
|
|
10
|
-
'https://kenisha-happiest-nan.ngrok-free.dev/modal/sdk/v1/
|
|
10
|
+
'https://kenisha-happiest-nan.ngrok-free.dev/modal/sdk/v1/fpay/';
|
|
11
11
|
|
|
12
12
|
let _client: AxiosInstance | null = null;
|
|
13
13
|
let _isRefreshing = false;
|
package/src/core/api/index.ts
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
// FountainPay SDK — All API calls
|
|
2
2
|
import { http } from './client';
|
|
3
|
-
import
|
|
4
|
-
FPBankItem,
|
|
5
|
-
FPTransaction,
|
|
6
|
-
FPNQRData,
|
|
7
|
-
FPTxStatus,
|
|
8
|
-
FPProximityPeer,
|
|
9
|
-
FPSendPaymentRequest,
|
|
10
|
-
FPUserInfo,
|
|
11
|
-
FPAccount,
|
|
12
|
-
FPSendWalletPaymentRequest,
|
|
13
|
-
FPTransactionResponse,
|
|
14
|
-
FPBalance,
|
|
3
|
+
import {
|
|
4
|
+
type FPBankItem,
|
|
5
|
+
type FPTransaction,
|
|
6
|
+
type FPNQRData,
|
|
7
|
+
type FPTxStatus,
|
|
8
|
+
type FPProximityPeer,
|
|
9
|
+
type FPSendPaymentRequest,
|
|
10
|
+
type FPUserInfo,
|
|
11
|
+
type FPAccount,
|
|
12
|
+
type FPSendWalletPaymentRequest,
|
|
13
|
+
type FPTransactionResponse,
|
|
14
|
+
type FPBalance,
|
|
15
|
+
type HttpCallResponseFormat,
|
|
16
|
+
BUSINESSID,
|
|
15
17
|
} from '../types';
|
|
16
18
|
|
|
17
19
|
export const healthAPI = {
|
|
@@ -22,15 +24,15 @@ export const healthAPI = {
|
|
|
22
24
|
};
|
|
23
25
|
|
|
24
26
|
export const authenticateAPI = {
|
|
25
|
-
login: (
|
|
27
|
+
login: (appId: string) =>
|
|
26
28
|
http()
|
|
27
|
-
.post('/auth', {
|
|
29
|
+
.post('/auth', { user_id: appId })
|
|
28
30
|
.then((r) => r.data),
|
|
29
31
|
|
|
30
|
-
profile: (
|
|
32
|
+
profile: () =>
|
|
31
33
|
http()
|
|
32
|
-
.get(`/get-user-details
|
|
33
|
-
.then((r) => r.data),
|
|
34
|
+
.get(`/get-user-details`)
|
|
35
|
+
.then((r) => r.data.payload),
|
|
34
36
|
|
|
35
37
|
logout: () =>
|
|
36
38
|
http()
|
|
@@ -43,28 +45,38 @@ export const authenticateAPI = {
|
|
|
43
45
|
.then((r) => r.data),
|
|
44
46
|
|
|
45
47
|
validateToken: () =>
|
|
46
|
-
http().get<{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
http().get<{response: HttpCallResponseFormat}>('/auth/agent/validate-token').then(r => r.data),
|
|
49
|
+
|
|
50
|
+
sendSmsOtp: async(payload: any)=>
|
|
51
|
+
http()
|
|
52
|
+
.post<{
|
|
53
|
+
status: boolean;
|
|
54
|
+
message: string;
|
|
55
|
+
payload:any
|
|
56
|
+
}>("shared/send-sms-otp", payload)
|
|
57
|
+
.then((r)=>r.data),
|
|
58
|
+
|
|
59
|
+
verifyBvn: async() =>
|
|
60
|
+
http()
|
|
61
|
+
.get<{response: HttpCallResponseFormat}>("verify-bvn")
|
|
62
|
+
.then((r)=>r.data),
|
|
63
|
+
|
|
64
|
+
verifySms: async(payload: any)=>
|
|
65
|
+
http()
|
|
66
|
+
.post<{response: HttpCallResponseFormat}>("verify-bvn", payload)
|
|
67
|
+
.then((r)=>r.data),
|
|
68
|
+
|
|
69
|
+
updateProfile: async(payload: any)=>
|
|
70
|
+
http()
|
|
71
|
+
.put<{response: HttpCallResponseFormat}>("update-user-agent", payload)
|
|
72
|
+
.then((r)=>r.data),
|
|
62
73
|
};
|
|
63
74
|
|
|
64
75
|
export const accountAPI = {
|
|
65
76
|
generate: (user: FPUserInfo) =>
|
|
66
77
|
http()
|
|
67
|
-
.post<{ payload: FPAccount }>('/
|
|
78
|
+
.post<{ payload: FPAccount }>('/auth/create-agent', {
|
|
79
|
+
business_id: BUSINESSID,
|
|
68
80
|
first_name: user.firstName,
|
|
69
81
|
last_name: user.lastName,
|
|
70
82
|
phone_no: user.phone,
|
|
@@ -75,25 +87,16 @@ export const accountAPI = {
|
|
|
75
87
|
})
|
|
76
88
|
.then((r) => r.data.payload),
|
|
77
89
|
|
|
78
|
-
// Get user profile using PSSP id
|
|
79
|
-
getUser: (psspId: string) =>
|
|
80
|
-
http()
|
|
81
|
-
.get<{ payload: FPAccount }>(`/get-user-details/${psspId}`)
|
|
82
|
-
.then((r) => r.data.payload),
|
|
83
|
-
|
|
84
90
|
// Get account details using PSSP id
|
|
85
|
-
getAccount: (
|
|
91
|
+
getAccount: () =>
|
|
86
92
|
http()
|
|
87
|
-
.get<{ payload: FPAccount }>(`/get-accounts-details
|
|
93
|
+
.get<{ payload: FPAccount }>(`/get-accounts-details`)
|
|
88
94
|
.then((r) => r.data.payload),
|
|
89
95
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
`/get-balance/${psspId}`
|
|
95
|
-
)
|
|
96
|
-
.then((r) => r.data.payload as FPBalance),
|
|
96
|
+
getAgentBalance: () =>
|
|
97
|
+
http().get<{ payload: FPBalance }>(`/get-balance`)
|
|
98
|
+
.then(r => r.data.payload),
|
|
99
|
+
|
|
97
100
|
};
|
|
98
101
|
|
|
99
102
|
export const transferAPI = {
|
|
@@ -125,15 +128,16 @@ export const transferAPI = {
|
|
|
125
128
|
}>('/wallet-name-enquiry', { account_number: accountNumber })
|
|
126
129
|
.then((r) => r.data),
|
|
127
130
|
|
|
128
|
-
validateTransfer: (pin: string, userId: string) =>
|
|
131
|
+
validateTransfer: (pin: string, userId: string, receiverId: string) =>
|
|
129
132
|
http()
|
|
130
133
|
.post<{ status: boolean; message: string }>('/validate-transaction', {
|
|
131
134
|
pin,
|
|
132
|
-
|
|
135
|
+
sender_type: 'AGENT',
|
|
136
|
+
receiver_id: receiverId,
|
|
133
137
|
})
|
|
134
138
|
.then((r) => r.data),
|
|
135
139
|
|
|
136
|
-
sendToWallet: (payload:
|
|
140
|
+
sendToWallet: (payload: any, temptId: string) =>
|
|
137
141
|
http()
|
|
138
142
|
.post<{ payload: FPTransactionResponse }>('/wallet-transfer-funds', {
|
|
139
143
|
...payload,
|
package/src/core/types/index.ts
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
import type { Device } from 'react-native-ble-plx';
|
|
4
4
|
|
|
5
|
+
export const BUSINESSID = "1678aa7d-741a-4a4b-98dd-2fb406a3df3d";
|
|
6
|
+
|
|
5
7
|
export type FPCurrency = 'NGN' | 'USD' | 'GBP' | 'EUR' | string;
|
|
6
8
|
export type FPChannel = 'transfer' | 'nqr' | 'proximity' | 'bluetooth' | 'nfc';
|
|
7
9
|
export type FPTxStatus =
|
|
@@ -21,6 +23,7 @@ export interface FPUserInfo {
|
|
|
21
23
|
nin?: string;
|
|
22
24
|
dateOfBirth?: string;
|
|
23
25
|
userId: string;
|
|
26
|
+
terminalId?: string;
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
export interface FPSDKOptions {
|
|
@@ -31,10 +34,15 @@ export interface FPSDKOptions {
|
|
|
31
34
|
userType?: 'USER' | 'AGENT';
|
|
32
35
|
}
|
|
33
36
|
|
|
37
|
+
export interface FPInternalTransferRecipient {
|
|
38
|
+
id: string;
|
|
39
|
+
type: 'AGENT' | 'TERMINAL';
|
|
40
|
+
}
|
|
41
|
+
|
|
34
42
|
export interface FPTransferRecipient {
|
|
35
43
|
accountNumber: string;
|
|
36
44
|
accountName: string;
|
|
37
|
-
bankCode
|
|
45
|
+
bankCode?: string;
|
|
38
46
|
bankName: string;
|
|
39
47
|
}
|
|
40
48
|
|
|
@@ -84,6 +92,7 @@ export interface FPSendPaymentRequest {
|
|
|
84
92
|
channel: 'transfer' | 'proximity' | 'bluetooth' | 'nfc' | 'nqr';
|
|
85
93
|
currency?: string;
|
|
86
94
|
recipient:
|
|
95
|
+
| FPInternalTransferRecipient
|
|
87
96
|
| FPTransferRecipient
|
|
88
97
|
| FPNfcRecipient
|
|
89
98
|
| FPNqrRecipient
|
|
@@ -110,6 +119,11 @@ export interface FPNfcTransfer {
|
|
|
110
119
|
channel: 'nfc';
|
|
111
120
|
}
|
|
112
121
|
|
|
122
|
+
export interface HttpCallResponseFormat {
|
|
123
|
+
status: string;
|
|
124
|
+
message: string;
|
|
125
|
+
payload: any;
|
|
126
|
+
}
|
|
113
127
|
export interface FPTransactionResponse {
|
|
114
128
|
status: string;
|
|
115
129
|
message: string;
|
|
@@ -167,11 +181,10 @@ export interface FPBankItem {
|
|
|
167
181
|
|
|
168
182
|
export interface FPAccount {
|
|
169
183
|
id: string; // PSSP-assigned — stored internally, host app never needs this
|
|
184
|
+
ownerId: string;
|
|
185
|
+
ownerType: string;
|
|
170
186
|
accountNumber: string;
|
|
171
187
|
accountName: string;
|
|
172
|
-
firstName: string;
|
|
173
|
-
lastName?: string;
|
|
174
|
-
phone: string;
|
|
175
188
|
bankName?: string;
|
|
176
189
|
bankCode?: string;
|
|
177
190
|
balance?: FPBalance | null;
|
|
@@ -184,7 +197,7 @@ export interface FPCallbacks {
|
|
|
184
197
|
onPaymentDeclined?: (request: FPBluetoothPaymentRequest) => void;
|
|
185
198
|
onPaymentSent?: (transaction: FPTransaction) => void;
|
|
186
199
|
onError?: (error: FPError) => void;
|
|
187
|
-
onAccountReady?: (account:
|
|
200
|
+
onAccountReady?: (account: any) => void;
|
|
188
201
|
onAccountError?: (error: FPError, user: FPUserInfo) => void;
|
|
189
202
|
}
|
|
190
203
|
|
package/src/engine/FPEngine.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
12
12
|
import Geolocation from '@react-native-community/geolocation';
|
|
13
13
|
import { initClient } from '../core/api/client';
|
|
14
|
-
import { proximityAPI, accountAPI } from '../core/api';
|
|
14
|
+
import { proximityAPI, accountAPI, authenticateAPI } from '../core/api';
|
|
15
15
|
import type {
|
|
16
16
|
FPUserInfo,
|
|
17
17
|
FPSDKOptions,
|
|
@@ -124,7 +124,7 @@ async function _startProximityBroadcast(): Promise<void> {
|
|
|
124
124
|
const session = await proximityAPI.broadcast(psspId, {
|
|
125
125
|
latitude: loc.lat,
|
|
126
126
|
longitude: loc.lng,
|
|
127
|
-
user_type: '
|
|
127
|
+
user_type: 'AGENT',
|
|
128
128
|
});
|
|
129
129
|
|
|
130
130
|
// Save new position to store
|
|
@@ -161,7 +161,7 @@ async function _startProximityBroadcast(): Promise<void> {
|
|
|
161
161
|
await proximityAPI.broadcast(psspId, {
|
|
162
162
|
latitude: current.lat,
|
|
163
163
|
longitude: current.lng,
|
|
164
|
-
user_type: '
|
|
164
|
+
user_type: 'AGENT',
|
|
165
165
|
});
|
|
166
166
|
getFPStore().setLastBroadcastPosition({
|
|
167
167
|
latitude: current.lat,
|
|
@@ -307,15 +307,20 @@ async function _resolveAccount(
|
|
|
307
307
|
|
|
308
308
|
console.log('[FPay Engine] _resolveAccount callbacks:',
|
|
309
309
|
'onAccountReady:', !!callbacks.onAccountReady,
|
|
310
|
-
'onAccountError:', !!callbacks.onAccountError
|
|
310
|
+
'onAccountError:', !!callbacks.onAccountError,
|
|
311
|
+
'user: ', user,
|
|
312
|
+
'psspId:', psspId,
|
|
313
|
+
'user.userId:', user.userId,
|
|
314
|
+
'store.psspId:', store.psspId
|
|
311
315
|
);
|
|
312
316
|
|
|
313
317
|
try {
|
|
314
318
|
if (psspId) {
|
|
315
319
|
// ← use the saved value, not store.psspId
|
|
320
|
+
|
|
316
321
|
console.log('[FPay Engine] Existing PSSP id found — fetching account...');
|
|
317
322
|
try {
|
|
318
|
-
const account = await accountAPI.getAccount(
|
|
323
|
+
const account = await accountAPI.getAccount();
|
|
319
324
|
store.setAccount(account);
|
|
320
325
|
store.setUser(user);
|
|
321
326
|
console.log('[FPay Engine] Account loaded:', account);
|
|
@@ -332,7 +337,7 @@ async function _resolveAccount(
|
|
|
332
337
|
// Create new account
|
|
333
338
|
const account: any = await accountAPI.generate(user);
|
|
334
339
|
console.log('[FPay Engine] Account creation response:', account);
|
|
335
|
-
if (account) {
|
|
340
|
+
if (account) {
|
|
336
341
|
store.setPsspId(account.id);
|
|
337
342
|
store.setAccount(account);
|
|
338
343
|
store.setUser(user);
|
|
@@ -356,7 +361,8 @@ async function _fetchBalance(): Promise<void> {
|
|
|
356
361
|
}
|
|
357
362
|
|
|
358
363
|
try {
|
|
359
|
-
const balance: FPBalance = await accountAPI.
|
|
364
|
+
const balance: FPBalance = await accountAPI.getAgentBalance();
|
|
365
|
+
|
|
360
366
|
getFPStore().setBalance(balance);
|
|
361
367
|
console.log('[FPay Engine] Balance fetched:', balance);
|
|
362
368
|
} catch (err) {
|
|
@@ -433,16 +439,6 @@ export const FPEngine = {
|
|
|
433
439
|
_isReady = true;
|
|
434
440
|
console.log('[FPay Engine] Initialized. Advertising as:', displayName);
|
|
435
441
|
|
|
436
|
-
// AGENT — account already stored by provider, skip resolve
|
|
437
|
-
if (options.userType === 'AGENT') {
|
|
438
|
-
const account = getFPStore().account;
|
|
439
|
-
if (account) {
|
|
440
|
-
callbacks.onAccountReady?.(account);
|
|
441
|
-
_fetchBalance();
|
|
442
|
-
}
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
442
|
// Resolve account first — sets psspId in store
|
|
447
443
|
// Then broadcast proximity — needs psspId to be set
|
|
448
444
|
await _resolveAccount(user, callbacks);
|
|
@@ -587,6 +583,27 @@ export const FPEngine = {
|
|
|
587
583
|
await _fetchBalance();
|
|
588
584
|
},
|
|
589
585
|
|
|
586
|
+
async verifyBvn(): Promise<void> {
|
|
587
|
+
const response: any = await authenticateAPI.verifyBvn();
|
|
588
|
+
getFPStore().setTempId(response?.payload?.temp_id);
|
|
589
|
+
},
|
|
590
|
+
|
|
591
|
+
async verifySmsOtp(payload: any): Promise<void> {
|
|
592
|
+
const response: any = await authenticateAPI.verifySms(payload);
|
|
593
|
+
if(response.status){
|
|
594
|
+
await authenticateAPI.updateProfile({verifyBvn: true});
|
|
595
|
+
const profile = await authenticateAPI.profile();
|
|
596
|
+
getFPStore().setUser(profile);
|
|
597
|
+
getFPStore().clearTempId();
|
|
598
|
+
}
|
|
599
|
+
},
|
|
600
|
+
|
|
601
|
+
async createUserTransactionPin(payload: any): Promise<void> {
|
|
602
|
+
await authenticateAPI.updateProfile(payload);
|
|
603
|
+
const profile = await authenticateAPI.profile();
|
|
604
|
+
getFPStore().setUser(profile);
|
|
605
|
+
},
|
|
606
|
+
|
|
590
607
|
closeSend(): void {
|
|
591
608
|
_emitEvent('close_send');
|
|
592
609
|
},
|