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.
- package/lib/module/FountainPayProvider.js +108 -18
- package/lib/module/FountainPayProvider.js.map +1 -1
- package/lib/module/core/api/client.js +13 -1
- package/lib/module/core/api/client.js.map +1 -1
- package/lib/module/core/api/index.js +66 -24
- package/lib/module/core/api/index.js.map +1 -1
- package/lib/module/engine/BLEReceiverService.js.map +1 -1
- package/lib/module/engine/BLESenderService.js.map +1 -1
- package/lib/module/engine/FPEngine.js +164 -43
- package/lib/module/engine/FPEngine.js.map +1 -1
- package/lib/module/engine/NearbyUsersService.js +1 -1
- package/lib/module/engine/NearbyUsersService.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/store/FPStore.js +155 -0
- package/lib/module/store/FPStore.js.map +1 -0
- package/lib/module/ui/components/AnimatedDots.js +3 -3
- package/lib/module/ui/components/AnimatedDots.js.map +1 -1
- package/lib/module/ui/components/ConfirmScreen.js +137 -123
- package/lib/module/ui/components/ConfirmScreen.js.map +1 -1
- package/lib/module/ui/components/FPButton.js.map +1 -1
- package/lib/module/ui/components/LoadingAnimation/InLoading.js +3 -3
- package/lib/module/ui/components/LoadingAnimation/InLoading.js.map +1 -1
- package/lib/module/ui/components/LoadingAnimation/index.js +3 -3
- package/lib/module/ui/components/LoadingAnimation/index.js.map +1 -1
- package/lib/module/ui/components/OtpInput/OTPInputView.js +11 -11
- package/lib/module/ui/components/OtpInput/OTPInputView.js.map +1 -1
- package/lib/module/ui/components/OtpInput/Styles.js +1 -1
- package/lib/module/ui/components/OtpInput/helpers/codeToArray.js +1 -1
- package/lib/module/ui/components/OtpInput/helpers/device.js.map +1 -1
- package/lib/module/ui/components/OtpInput/helpers/styles.js.map +1 -1
- package/lib/module/ui/components/OtpInput/index.js +3 -1
- package/lib/module/ui/components/OtpInput/index.js.map +1 -1
- package/lib/module/ui/components/PulseAnimation.js +2 -2
- package/lib/module/ui/components/PulseAnimation.js.map +1 -1
- package/lib/module/ui/modals/FPPaymentRequestModal.js +8 -7
- package/lib/module/ui/modals/FPPaymentRequestModal.js.map +1 -1
- package/lib/module/ui/modals/FPShell.js +2 -0
- package/lib/module/ui/modals/FPShell.js.map +1 -1
- package/lib/module/ui/screens/ReceiveScreen.js +8 -9
- package/lib/module/ui/screens/ReceiveScreen.js.map +1 -1
- package/lib/module/ui/screens/SendScreen.js +43 -94
- package/lib/module/ui/screens/SendScreen.js.map +1 -1
- package/lib/module/ui/screens/styles.js +15 -3
- package/lib/module/ui/screens/styles.js.map +1 -1
- package/lib/module/ui/screens/sub/receivePayment/Nfc/index.js +4 -4
- package/lib/module/ui/screens/sub/receivePayment/Nfc/index.js.map +1 -1
- package/lib/module/ui/screens/sub/receivePayment/Qr/index.js +5 -5
- package/lib/module/ui/screens/sub/receivePayment/Qr/index.js.map +1 -1
- package/lib/module/ui/screens/sub/receivePayment/Transfer/index.js +10 -11
- package/lib/module/ui/screens/sub/receivePayment/Transfer/index.js.map +1 -1
- package/lib/module/ui/screens/sub/sendPayment/BluetoothSubScreen.js +31 -8
- package/lib/module/ui/screens/sub/sendPayment/BluetoothSubScreen.js.map +1 -1
- package/lib/module/ui/screens/sub/sendPayment/NFCSubScreen.js +12 -8
- package/lib/module/ui/screens/sub/sendPayment/NFCSubScreen.js.map +1 -1
- package/lib/module/ui/screens/sub/sendPayment/NQRSubScreen.js +17 -5
- package/lib/module/ui/screens/sub/sendPayment/NQRSubScreen.js.map +1 -1
- package/lib/module/ui/screens/sub/sendPayment/ProximitySubScreen.js +67 -35
- package/lib/module/ui/screens/sub/sendPayment/ProximitySubScreen.js.map +1 -1
- package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js +110 -34
- package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js.map +1 -1
- package/lib/module/ui/theme/index.js.map +1 -1
- package/lib/typescript/src/FountainPayProvider.d.ts +1 -1
- package/lib/typescript/src/FountainPayProvider.d.ts.map +1 -1
- package/lib/typescript/src/core/api/client.d.ts.map +1 -1
- package/lib/typescript/src/core/api/index.d.ts +42 -26
- package/lib/typescript/src/core/api/index.d.ts.map +1 -1
- package/lib/typescript/src/core/types/index.d.ts +53 -28
- package/lib/typescript/src/core/types/index.d.ts.map +1 -1
- package/lib/typescript/src/engine/BLEReceiverService.d.ts +2 -0
- package/lib/typescript/src/engine/BLEReceiverService.d.ts.map +1 -1
- package/lib/typescript/src/engine/BLESenderService.d.ts.map +1 -1
- package/lib/typescript/src/engine/FPEngine.d.ts +5 -3
- package/lib/typescript/src/engine/FPEngine.d.ts.map +1 -1
- package/lib/typescript/src/engine/useIsForeground.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/store/FPStore.d.ts +60 -0
- package/lib/typescript/src/store/FPStore.d.ts.map +1 -0
- package/lib/typescript/src/ui/components/AnimatedDots.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/ConfirmScreen.d.ts +5 -5
- package/lib/typescript/src/ui/components/ConfirmScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/FPButton.d.ts +1 -1
- package/lib/typescript/src/ui/components/FPButton.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/LoadingAnimation/InLoading.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/LoadingAnimation/index.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/OtpInput/OTPInputView.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/OtpInput/helpers/codeToArray.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/OtpInput/helpers/device.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/OtpInput/helpers/styles.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/OtpInput/helpers/types.d.ts +1 -2
- package/lib/typescript/src/ui/components/OtpInput/helpers/types.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/OtpInput/index.d.ts +3 -1
- package/lib/typescript/src/ui/components/OtpInput/index.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/PulseAnimation.d.ts.map +1 -1
- package/lib/typescript/src/ui/modals/FPPaymentRequestModal.d.ts.map +1 -1
- package/lib/typescript/src/ui/modals/FPShell.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/ReceiveScreen.d.ts +1 -1
- package/lib/typescript/src/ui/screens/ReceiveScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/SendScreen.d.ts +1 -1
- package/lib/typescript/src/ui/screens/SendScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/styles.d.ts +197 -0
- package/lib/typescript/src/ui/screens/styles.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/sub/receivePayment/Nfc/index.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/sub/receivePayment/Qr/index.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/sub/receivePayment/Transfer/index.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/BluetoothSubScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/NFCSubScreen.d.ts +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/NFCSubScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/NQRSubScreen.d.ts +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/NQRSubScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/ProximitySubScreen.d.ts +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/ProximitySubScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/TransferSubScreen.d.ts +1 -1
- package/lib/typescript/src/ui/screens/sub/sendPayment/TransferSubScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/theme/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/FountainPayProvider.tsx +163 -24
- package/src/core/api/client.ts +26 -4
- package/src/core/api/index.ts +170 -49
- package/src/core/types/index.ts +81 -48
- package/src/engine/BLEReceiverService.ts +86 -28
- package/src/engine/BLESenderService.ts +133 -69
- package/src/engine/FPEngine.ts +316 -97
- package/src/engine/NearbyUsersService.ts +6 -6
- package/src/engine/useIsForeground.ts +12 -12
- package/src/index.ts +10 -4
- package/src/store/FPStore.ts +216 -0
- package/src/ui/components/AnimatedDots.tsx +4 -5
- package/src/ui/components/ConfirmScreen.tsx +182 -169
- package/src/ui/components/FPButton.tsx +50 -9
- package/src/ui/components/LoadingAnimation/InLoading.tsx +23 -27
- package/src/ui/components/LoadingAnimation/index.tsx +3 -7
- package/src/ui/components/OtpInput/OTPInputView.tsx +254 -205
- package/src/ui/components/OtpInput/Styles.ts +1 -1
- package/src/ui/components/OtpInput/helpers/codeToArray.ts +2 -2
- package/src/ui/components/OtpInput/helpers/device.ts +4 -3
- package/src/ui/components/OtpInput/helpers/styles.ts +13 -14
- package/src/ui/components/OtpInput/helpers/types.ts +83 -79
- package/src/ui/components/OtpInput/index.tsx +18 -15
- package/src/ui/components/PulseAnimation.tsx +3 -5
- package/src/ui/modals/FPPaymentRequestModal.tsx +111 -28
- package/src/ui/modals/FPShell.tsx +60 -34
- package/src/ui/screens/ReceiveScreen.tsx +245 -84
- package/src/ui/screens/SendScreen.tsx +419 -167
- package/src/ui/screens/styles.ts +17 -5
- package/src/ui/screens/sub/receivePayment/Nfc/index.tsx +17 -25
- package/src/ui/screens/sub/receivePayment/Qr/index.tsx +21 -20
- package/src/ui/screens/sub/receivePayment/Transfer/index.tsx +34 -28
- package/src/ui/screens/sub/sendPayment/BluetoothSubScreen.tsx +135 -67
- package/src/ui/screens/sub/sendPayment/NFCSubScreen.tsx +188 -112
- package/src/ui/screens/sub/sendPayment/NQRSubScreen.tsx +102 -69
- package/src/ui/screens/sub/sendPayment/ProximitySubScreen.tsx +225 -99
- package/src/ui/screens/sub/sendPayment/TransferSubScreen.tsx +209 -89
- package/src/ui/theme/index.ts +14 -2
|
@@ -10,10 +10,16 @@
|
|
|
10
10
|
// <YourApp />
|
|
11
11
|
// </FountainPayProvider>
|
|
12
12
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
-
import
|
|
14
|
-
type ReactNode,
|
|
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
|
-
|
|
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({
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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(
|
|
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(
|
|
85
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
114
|
-
console.log(
|
|
115
|
-
|
|
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(
|
|
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
|
|
277
|
+
return user;
|
|
278
|
+
},
|
|
279
|
+
get balance(): number | null {
|
|
280
|
+
return balance;
|
|
141
281
|
},
|
|
142
282
|
};
|
|
143
|
-
|
|
144
|
-
}, [apiKey]);
|
|
283
|
+
}, [apiKey, isAuthenticated, authError, account, user, balance]);
|
|
145
284
|
|
|
146
285
|
return (
|
|
147
286
|
<FountainPayContext.Provider value={instance}>
|
package/src/core/api/client.ts
CHANGED
|
@@ -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 =
|
|
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(
|
|
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) {
|
|
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)
|
|
64
|
+
if (!_client)
|
|
65
|
+
throw new Error(
|
|
66
|
+
'[FountainPay] SDK not initialized. Call pay.initializeSDK() first.'
|
|
67
|
+
);
|
|
46
68
|
return _client;
|
|
47
69
|
}
|
package/src/core/api/index.ts
CHANGED
|
@@ -1,76 +1,197 @@
|
|
|
1
1
|
// FountainPay SDK — All API calls
|
|
2
|
-
import { http } from
|
|
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
|
-
|
|
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
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
19
|
-
|
|
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()
|
|
82
|
+
http()
|
|
83
|
+
.get<FPBankItem[]>('/get-banks')
|
|
84
|
+
.then((r) => r.data),
|
|
25
85
|
|
|
26
86
|
verifyAccount: (accountNumber: string, bankCode: string) =>
|
|
27
|
-
http()
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
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: {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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()
|
|
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: (
|
|
52
|
-
|
|
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(
|
|
181
|
+
http().patch(`/broadcast-proximity/${sessionId}`, {
|
|
182
|
+
latitude: lat,
|
|
183
|
+
longitude: lng,
|
|
184
|
+
}),
|
|
56
185
|
|
|
57
186
|
unregister: (sessionId: string) =>
|
|
58
|
-
http().delete(
|
|
59
|
-
|
|
60
|
-
discover: (lat: number, lng: number,
|
|
61
|
-
http()
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
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
|
};
|