react-native-fpay 0.4.33 → 0.4.35
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/core/api/client.js +1 -1
- package/lib/module/core/api/client.js.map +1 -1
- package/lib/module/core/api/index.js +86 -21
- package/lib/module/core/api/index.js.map +1 -1
- package/lib/module/ui/components/ConfirmScreen.js +32 -4
- package/lib/module/ui/components/ConfirmScreen.js.map +1 -1
- package/lib/module/ui/screens/BillsScreen.js +30 -14
- package/lib/module/ui/screens/BillsScreen.js.map +1 -1
- package/lib/module/ui/screens/styles.js +2 -1
- package/lib/module/ui/screens/styles.js.map +1 -1
- package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js +10 -8
- package/lib/module/ui/screens/sub/sendPayment/TransferSubScreen.js.map +1 -1
- package/lib/typescript/src/core/api/client.d.ts.map +1 -1
- package/lib/typescript/src/core/api/index.d.ts +154 -46
- package/lib/typescript/src/core/api/index.d.ts.map +1 -1
- package/lib/typescript/src/ui/components/ConfirmScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/BillsScreen.d.ts +1 -1
- package/lib/typescript/src/ui/screens/BillsScreen.d.ts.map +1 -1
- package/lib/typescript/src/ui/screens/styles.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/core/api/client.ts +1 -2
- package/src/core/api/index.ts +197 -86
- package/src/ui/components/ConfirmScreen.tsx +37 -36
- package/src/ui/screens/BillsScreen.tsx +85 -26
- package/src/ui/screens/styles.ts +2 -1
- package/src/ui/screens/sub/sendPayment/TransferSubScreen.tsx +9 -8
|
@@ -1,10 +1,3 @@
|
|
|
1
|
-
// ─────────────────────────────────────────────
|
|
2
|
-
// Bills Screen
|
|
3
|
-
// Renders the category-specific sub-screen
|
|
4
|
-
// (Airtime / Data / Electricity / Cable), then
|
|
5
|
-
// runs the same Confirm (PIN) → Loading →
|
|
6
|
-
// Result flow SendScreen uses, generalized.
|
|
7
|
-
// ─────────────────────────────────────────────
|
|
8
1
|
import { useState } from 'react';
|
|
9
2
|
import { View, TouchableOpacity, Text } from 'react-native';
|
|
10
3
|
import styled from 'styled-components/native';
|
|
@@ -18,6 +11,7 @@ import { ResultScreen } from './ResultScreen';
|
|
|
18
11
|
import LoadingAnimation from '../components/LoadingAnimation';
|
|
19
12
|
import { billsAPI } from '../../core/api';
|
|
20
13
|
import { getFPStore } from '../../store/FPStore';
|
|
14
|
+
import { useLocation } from '../../hooks/useLocation';
|
|
21
15
|
import { C, F, S } from '../theme';
|
|
22
16
|
import type {
|
|
23
17
|
FPBillCategory,
|
|
@@ -28,6 +22,7 @@ import type {
|
|
|
28
22
|
FPUserInfo,
|
|
29
23
|
FPSummaryRow,
|
|
30
24
|
} from '../../core/types';
|
|
25
|
+
import type { FPBillPurchaseContext } from '../../core/api';
|
|
31
26
|
|
|
32
27
|
const Container = styled(View)`
|
|
33
28
|
flex: 1;
|
|
@@ -39,7 +34,6 @@ const Header = styled(View)`
|
|
|
39
34
|
align-items: center;
|
|
40
35
|
justify-content: space-between;
|
|
41
36
|
padding: ${S.md}px ${S.lg}px;
|
|
42
|
-
margin-top: 30px;
|
|
43
37
|
`;
|
|
44
38
|
|
|
45
39
|
const HeaderTitle = styled(Text)`
|
|
@@ -73,14 +67,29 @@ interface Props extends Pick<FPCallbacks, 'onError'> {
|
|
|
73
67
|
|
|
74
68
|
type FlowStage = 'FORM' | 'CONFIRM' | 'RESULT';
|
|
75
69
|
|
|
76
|
-
export default function BillsScreen({
|
|
70
|
+
export default function BillsScreen({
|
|
71
|
+
category,
|
|
72
|
+
amount,
|
|
73
|
+
user,
|
|
74
|
+
onClose,
|
|
75
|
+
onError,
|
|
76
|
+
}: Props) {
|
|
77
77
|
const [stage, setStage] = useState<FlowStage>('FORM');
|
|
78
78
|
const [loading, setLoading] = useState(false);
|
|
79
|
-
const [pendingPayload, setPendingPayload] =
|
|
80
|
-
|
|
81
|
-
const [
|
|
79
|
+
const [pendingPayload, setPendingPayload] =
|
|
80
|
+
useState<FPBillPurchaseRequest | null>(null);
|
|
81
|
+
const [pendingSummaryRows, setPendingSummaryRows] = useState<FPSummaryRow[]>(
|
|
82
|
+
[]
|
|
83
|
+
);
|
|
84
|
+
const [completedTx, setCompletedTx] = useState<FPBillTransaction | null>(
|
|
85
|
+
null
|
|
86
|
+
);
|
|
87
|
+
const { requestLocation } = useLocation();
|
|
82
88
|
|
|
83
|
-
const handleFormContinue = (
|
|
89
|
+
const handleFormContinue = (
|
|
90
|
+
payload: FPBillPurchaseRequest,
|
|
91
|
+
summaryRows: FPSummaryRow[]
|
|
92
|
+
) => {
|
|
84
93
|
setPendingPayload(payload);
|
|
85
94
|
setPendingSummaryRows(summaryRows);
|
|
86
95
|
setStage('CONFIRM');
|
|
@@ -96,26 +105,59 @@ export default function BillsScreen({ category, amount, user, onClose, onError }
|
|
|
96
105
|
if (!pendingPayload) return;
|
|
97
106
|
setLoading(true);
|
|
98
107
|
try {
|
|
108
|
+
const isTerminalTransaction = !!user?.terminalId;
|
|
109
|
+
let geoLocation: { latitude: number; longitude: number } | undefined;
|
|
110
|
+
if (isTerminalTransaction) {
|
|
111
|
+
const loc = await requestLocation();
|
|
112
|
+
if (loc) {
|
|
113
|
+
geoLocation = { latitude: loc.latitude, longitude: loc.longitude };
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const ctx: FPBillPurchaseContext = {
|
|
118
|
+
agentId: getFPStore().psspId || '',
|
|
119
|
+
terminalId: user?.terminalId,
|
|
120
|
+
geoLocation,
|
|
121
|
+
currency: 'NGN',
|
|
122
|
+
tnxRef: `bill_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
|
|
123
|
+
forSelf:
|
|
124
|
+
pendingPayload.category === 'ELECTRICITY'
|
|
125
|
+
? pendingPayload.forSelf
|
|
126
|
+
: true,
|
|
127
|
+
agentName: user ? `${user.firstName} ${user.lastName}` : undefined,
|
|
128
|
+
agentEmail: user?.email,
|
|
129
|
+
agentPhone: user?.phone,
|
|
130
|
+
};
|
|
131
|
+
|
|
99
132
|
let response;
|
|
100
133
|
switch (pendingPayload.category) {
|
|
101
134
|
case 'AIRTIME':
|
|
102
|
-
response = await billsAPI.purchaseAirtime(
|
|
135
|
+
response = await billsAPI.purchaseAirtime(
|
|
136
|
+
pendingPayload,
|
|
137
|
+
ctx,
|
|
138
|
+
tempId
|
|
139
|
+
);
|
|
103
140
|
break;
|
|
104
141
|
case 'DATA':
|
|
105
|
-
response = await billsAPI.purchaseData(pendingPayload, tempId);
|
|
142
|
+
response = await billsAPI.purchaseData(pendingPayload, ctx, tempId);
|
|
106
143
|
break;
|
|
107
144
|
case 'ELECTRICITY':
|
|
108
|
-
response = await billsAPI.purchaseElectricity(
|
|
145
|
+
response = await billsAPI.purchaseElectricity(
|
|
146
|
+
pendingPayload,
|
|
147
|
+
ctx,
|
|
148
|
+
tempId
|
|
149
|
+
);
|
|
109
150
|
break;
|
|
110
151
|
case 'CABLE':
|
|
111
|
-
response = await billsAPI.purchaseCable(pendingPayload, tempId);
|
|
152
|
+
response = await billsAPI.purchaseCable(pendingPayload, ctx, tempId);
|
|
112
153
|
break;
|
|
113
154
|
}
|
|
114
155
|
|
|
115
156
|
if (!response?.status) {
|
|
116
|
-
onError?.({
|
|
117
|
-
|
|
118
|
-
|
|
157
|
+
onError?.({
|
|
158
|
+
code: 'PURCHASE_FAILED',
|
|
159
|
+
message: response?.message ?? 'Purchase failed',
|
|
160
|
+
} as FPError);
|
|
119
161
|
}
|
|
120
162
|
setCompletedTx(response?.payload ?? null);
|
|
121
163
|
setStage('RESULT');
|
|
@@ -129,9 +171,20 @@ export default function BillsScreen({ category, amount, user, onClose, onError }
|
|
|
129
171
|
const renderForm = () => {
|
|
130
172
|
switch (category) {
|
|
131
173
|
case 'AIRTIME':
|
|
132
|
-
return
|
|
174
|
+
return (
|
|
175
|
+
<AirtimeSubScreen
|
|
176
|
+
amount={amount}
|
|
177
|
+
onProcessTransaction={handleFormContinue}
|
|
178
|
+
onError={onError}
|
|
179
|
+
/>
|
|
180
|
+
);
|
|
133
181
|
case 'DATA':
|
|
134
|
-
return
|
|
182
|
+
return (
|
|
183
|
+
<DataSubScreen
|
|
184
|
+
onProcessTransaction={handleFormContinue}
|
|
185
|
+
onError={onError}
|
|
186
|
+
/>
|
|
187
|
+
);
|
|
135
188
|
case 'ELECTRICITY':
|
|
136
189
|
return (
|
|
137
190
|
<ElectricitySubScreen
|
|
@@ -142,7 +195,12 @@ export default function BillsScreen({ category, amount, user, onClose, onError }
|
|
|
142
195
|
/>
|
|
143
196
|
);
|
|
144
197
|
case 'CABLE':
|
|
145
|
-
return
|
|
198
|
+
return (
|
|
199
|
+
<CableSubScreen
|
|
200
|
+
onProcessTransaction={handleFormContinue}
|
|
201
|
+
onError={onError}
|
|
202
|
+
/>
|
|
203
|
+
);
|
|
146
204
|
}
|
|
147
205
|
};
|
|
148
206
|
|
|
@@ -155,7 +213,6 @@ export default function BillsScreen({ category, amount, user, onClose, onError }
|
|
|
155
213
|
statusFetcher={billsAPI.status}
|
|
156
214
|
onClose={handleResultClose}
|
|
157
215
|
/>
|
|
158
|
-
|
|
159
216
|
);
|
|
160
217
|
}
|
|
161
218
|
|
|
@@ -188,11 +245,13 @@ export default function BillsScreen({ category, amount, user, onClose, onError }
|
|
|
188
245
|
currency="₦"
|
|
189
246
|
subtitle="Double check the details before you proceed. Please note that successful bill payments cannot be reversed."
|
|
190
247
|
summaryRows={pendingSummaryRows}
|
|
191
|
-
validate={(pin: string) =>
|
|
248
|
+
validate={(pin: string) =>
|
|
249
|
+
billsAPI.validateBillPin(pin, getFPStore().psspId || '')
|
|
250
|
+
}
|
|
192
251
|
onContinue={handlePinAuthorized}
|
|
193
252
|
/>
|
|
194
253
|
</>
|
|
195
254
|
)}
|
|
196
255
|
</Container>
|
|
197
256
|
);
|
|
198
|
-
}
|
|
257
|
+
}
|
package/src/ui/screens/styles.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Text, TouchableOpacity } from 'react-native';
|
|
2
2
|
import styled from 'styled-components/native';
|
|
3
|
+
import { C } from '../theme';
|
|
3
4
|
|
|
4
5
|
export const ButtonContainer = styled.View`
|
|
5
6
|
width: 100%;
|
|
@@ -84,7 +85,7 @@ export const AccountText = styled.Text`
|
|
|
84
85
|
`;
|
|
85
86
|
|
|
86
87
|
export const Label = styled.Text`
|
|
87
|
-
color:
|
|
88
|
+
color: ${C.muted};
|
|
88
89
|
font-size: 14px;
|
|
89
90
|
font-weight: 600;
|
|
90
91
|
margin-bottom: 12px;
|
|
@@ -33,12 +33,13 @@ import {
|
|
|
33
33
|
StyledTextInput,
|
|
34
34
|
} from '../../styles';
|
|
35
35
|
import { getFPStore } from '../../../../store/FPStore';
|
|
36
|
+
import { C } from '../../../theme';
|
|
36
37
|
|
|
37
38
|
const { height } = Dimensions.get('window');
|
|
38
39
|
|
|
39
40
|
const Container = styled(View)`
|
|
40
41
|
flex: 1;
|
|
41
|
-
background-color:
|
|
42
|
+
background-color: ${C.white};
|
|
42
43
|
`;
|
|
43
44
|
|
|
44
45
|
const FormContainer = styled(View)`
|
|
@@ -66,7 +67,7 @@ const Header = styled(View)`
|
|
|
66
67
|
|
|
67
68
|
const HeaderButton = styled(TouchableOpacity)`
|
|
68
69
|
padding: 8px;
|
|
69
|
-
background-color:
|
|
70
|
+
background-color: ${C.surface};
|
|
70
71
|
width: 40px;
|
|
71
72
|
height: 40px;
|
|
72
73
|
border-radius: 50%;
|
|
@@ -165,7 +166,7 @@ const SwitchGroup = styled(View)`
|
|
|
165
166
|
|
|
166
167
|
const SwitchLabel = styled(Text)`
|
|
167
168
|
font-size: 14px;
|
|
168
|
-
color:
|
|
169
|
+
color: ${C.muted};
|
|
169
170
|
margin-left: 12px;
|
|
170
171
|
`;
|
|
171
172
|
|
|
@@ -308,14 +309,14 @@ export function TransferSubScreen({
|
|
|
308
309
|
{/* Header */}
|
|
309
310
|
<Header>
|
|
310
311
|
<HeaderButton onPress={onClose}>
|
|
311
|
-
<Ionicons name="close" size={24} />
|
|
312
|
+
<Ionicons name="close" size={24} color={C.ink} />
|
|
312
313
|
</HeaderButton>
|
|
313
314
|
|
|
314
315
|
<HeaderCenter>
|
|
315
|
-
<Text style={{ fontWeight: 'bold', fontSize: 16, color:
|
|
316
|
+
<Text style={{ fontWeight: 'bold', fontSize: 16, color: C.ink }}>
|
|
316
317
|
Bank
|
|
317
318
|
</Text>
|
|
318
|
-
<Text style={{ fontSize: 10, color:
|
|
319
|
+
<Text style={{ fontSize: 10, color: C.ink }}>Transfer</Text>
|
|
319
320
|
</HeaderCenter>
|
|
320
321
|
|
|
321
322
|
<HeaderRight />
|
|
@@ -323,11 +324,11 @@ export function TransferSubScreen({
|
|
|
323
324
|
<FormContainer>
|
|
324
325
|
<InputContainer>
|
|
325
326
|
<SwitchGroup>
|
|
326
|
-
<Label>Account
|
|
327
|
+
<Label>{isBank ? 'Bank Account Number' : 'Wallet Number'}</Label>
|
|
327
328
|
<ListGroup>
|
|
328
329
|
<SwitchLabel>To Banks</SwitchLabel>
|
|
329
330
|
<Switch
|
|
330
|
-
trackColor={{ false: '#767577', true:
|
|
331
|
+
trackColor={{ false: '#767577', true: C.ink }}
|
|
331
332
|
thumbColor={isBank ? '#003333' : '#f4f3f4'}
|
|
332
333
|
ios_backgroundColor="#3e3e3e"
|
|
333
334
|
value={isBank}
|