react-native-timacare 1.0.23 → 2.0.1
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/commonjs/navigation/primary-navigator.js +1 -1
- package/lib/commonjs/navigation/primary-navigator.js.flow +9 -0
- package/lib/commonjs/navigation/primary-navigator.js.map +1 -1
- package/lib/commonjs/screens/detail-loan/DetailLoanTima.js +2 -0
- package/lib/commonjs/screens/detail-loan/DetailLoanTima.js.flow +342 -0
- package/lib/commonjs/screens/detail-loan/DetailLoanTima.js.map +1 -0
- package/lib/commonjs/screens/detail-loan/Info.js +1 -1
- package/lib/commonjs/screens/detail-loan/Info.js.flow +4 -2
- package/lib/commonjs/screens/detail-loan/Info.js.map +1 -1
- package/lib/commonjs/screens/detail-loan/index.js +1 -1
- package/lib/commonjs/screens/detail-loan/index.js.flow +2 -1
- package/lib/commonjs/screens/detail-loan/index.js.map +1 -1
- package/lib/commonjs/screens/home/index.js +1 -1
- package/lib/commonjs/screens/home/index.js.flow +281 -226
- package/lib/commonjs/screens/home/index.js.map +1 -1
- package/lib/commonjs/screens/liveness/LivenessStore.js +1 -1
- package/lib/commonjs/screens/liveness/LivenessStore.js.flow +30 -1
- package/lib/commonjs/screens/liveness/LivenessStore.js.map +1 -1
- package/lib/commonjs/screens/mrz-scanner/index.js +2 -0
- package/lib/commonjs/screens/mrz-scanner/index.js.flow +394 -0
- package/lib/commonjs/screens/mrz-scanner/index.js.map +1 -0
- package/lib/commonjs/screens/mrz-scanner/store.js +2 -0
- package/lib/commonjs/screens/mrz-scanner/store.js.flow +35 -0
- package/lib/commonjs/screens/mrz-scanner/store.js.map +1 -0
- package/lib/commonjs/screens/register/Store.js +1 -1
- package/lib/commonjs/screens/register/Store.js.flow +1 -1
- package/lib/commonjs/screens/terms/TermScreen.js +1 -1
- package/lib/commonjs/screens/terms/TermScreen.js.flow +114 -1
- package/lib/commonjs/screens/terms/TermScreen.js.map +1 -1
- package/lib/commonjs/services/api/api-config.js +1 -1
- package/lib/commonjs/services/api/api-config.js.flow +2 -2
- package/lib/commonjs/services/api/api-config.js.map +1 -1
- package/lib/commonjs/services/api/api.js +1 -1
- package/lib/commonjs/services/api/api.js.flow +56 -0
- package/lib/commonjs/services/api/api.js.map +1 -1
- package/lib/module/navigation/primary-navigator.js +1 -1
- package/lib/module/navigation/primary-navigator.js.map +1 -1
- package/lib/module/screens/detail-loan/DetailLoanTima.js +2 -0
- package/lib/module/screens/detail-loan/DetailLoanTima.js.map +1 -0
- package/lib/module/screens/detail-loan/Info.js +1 -1
- package/lib/module/screens/detail-loan/Info.js.map +1 -1
- package/lib/module/screens/detail-loan/index.js +1 -1
- package/lib/module/screens/detail-loan/index.js.map +1 -1
- package/lib/module/screens/home/index.js +1 -1
- package/lib/module/screens/home/index.js.map +1 -1
- package/lib/module/screens/liveness/LivenessStore.js +1 -1
- package/lib/module/screens/liveness/LivenessStore.js.map +1 -1
- package/lib/module/screens/mrz-scanner/index.js +2 -0
- package/lib/module/screens/mrz-scanner/index.js.map +1 -0
- package/lib/module/screens/mrz-scanner/store.js +2 -0
- package/lib/module/screens/mrz-scanner/store.js.map +1 -0
- package/lib/module/screens/register/Store.js +1 -1
- package/lib/module/screens/terms/TermScreen.js +1 -1
- package/lib/module/screens/terms/TermScreen.js.map +1 -1
- package/lib/module/services/api/api-config.js +1 -1
- package/lib/module/services/api/api-config.js.map +1 -1
- package/lib/module/services/api/api.js +1 -1
- package/lib/module/services/api/api.js.map +1 -1
- package/lib/typescript/navigation/primary-navigator.d.ts +2 -0
- package/lib/typescript/navigation/primary-navigator.d.ts.map +1 -1
- package/lib/typescript/screens/detail-loan/DetailLoanTima.d.ts +2 -0
- package/lib/typescript/screens/detail-loan/DetailLoanTima.d.ts.map +1 -0
- package/lib/typescript/screens/detail-loan/Info.d.ts.map +1 -1
- package/lib/typescript/screens/detail-loan/index.d.ts.map +1 -1
- package/lib/typescript/screens/home/index.d.ts.map +1 -1
- package/lib/typescript/screens/liveness/LivenessStore.d.ts +2 -0
- package/lib/typescript/screens/liveness/LivenessStore.d.ts.map +1 -1
- package/lib/typescript/screens/mrz-scanner/index.d.ts +3 -0
- package/lib/typescript/screens/mrz-scanner/index.d.ts.map +1 -0
- package/lib/typescript/screens/mrz-scanner/store.d.ts +8 -0
- package/lib/typescript/screens/mrz-scanner/store.d.ts.map +1 -0
- package/lib/typescript/screens/terms/TermScreen.d.ts.map +1 -1
- package/lib/typescript/services/api/api.d.ts +48 -0
- package/lib/typescript/services/api/api.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/navigation/primary-navigator.tsx +9 -0
- package/src/screens/detail-loan/DetailLoanTima.tsx +342 -0
- package/src/screens/detail-loan/Info.tsx +4 -2
- package/src/screens/detail-loan/index.tsx +2 -1
- package/src/screens/home/index.tsx +281 -226
- package/src/screens/liveness/LivenessStore.tsx +30 -1
- package/src/screens/mrz-scanner/index.tsx +394 -0
- package/src/screens/mrz-scanner/store.ts +35 -0
- package/src/screens/register/Store.tsx +1 -1
- package/src/screens/terms/TermScreen.tsx +114 -1
- package/src/services/api/api-config.ts +2 -2
- package/src/services/api/api.ts +56 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
//@ts-nocheck
|
|
2
|
-
import { observable, action } from 'mobx';
|
|
2
|
+
import { observable, action, makeAutoObservable } from 'mobx';
|
|
3
3
|
import { useState } from 'react';
|
|
4
4
|
import { Api } from '../../services/api';
|
|
5
5
|
import { myLog } from '../../utils/log';
|
|
@@ -24,6 +24,10 @@ class Store {
|
|
|
24
24
|
|
|
25
25
|
@observable ekycSuccess = false;
|
|
26
26
|
|
|
27
|
+
constructor() {
|
|
28
|
+
makeAutoObservable(this);
|
|
29
|
+
}
|
|
30
|
+
|
|
27
31
|
@action
|
|
28
32
|
async uploadLiveness(body, onSuccess?, onFailure?) {
|
|
29
33
|
this.isLoading = true;
|
|
@@ -59,6 +63,31 @@ class Store {
|
|
|
59
63
|
}
|
|
60
64
|
}
|
|
61
65
|
}
|
|
66
|
+
|
|
67
|
+
@action
|
|
68
|
+
async confirmLicense(loanId, onSuccess) {
|
|
69
|
+
try {
|
|
70
|
+
const response = await Api.getInstance().confirmRule(loanId);
|
|
71
|
+
if (response.kind === 'ok') {
|
|
72
|
+
if (response.data.meta.errorCode === 200) {
|
|
73
|
+
if (onSuccess) onSuccess();
|
|
74
|
+
} else {
|
|
75
|
+
Alert.alert('Thông báo', response.data.meta.errorMessage, [
|
|
76
|
+
{
|
|
77
|
+
text: 'Xác nhận',
|
|
78
|
+
onPress: () => {
|
|
79
|
+
if (onSuccess) onSuccess();
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
]);
|
|
83
|
+
}
|
|
84
|
+
} else {
|
|
85
|
+
Alert.alert('Thông báo', 'Có lỗi không mong muốn xảy ra');
|
|
86
|
+
}
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.log();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
62
91
|
}
|
|
63
92
|
const livenessStore = new Store();
|
|
64
93
|
export default livenessStore;
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import React, { useState, useEffect, useRef } from 'react';
|
|
3
|
+
import {
|
|
4
|
+
View,
|
|
5
|
+
Text,
|
|
6
|
+
Button,
|
|
7
|
+
StyleSheet,
|
|
8
|
+
PermissionsAndroid,
|
|
9
|
+
Platform,
|
|
10
|
+
Alert,
|
|
11
|
+
SafeAreaView,
|
|
12
|
+
TouchableOpacity,
|
|
13
|
+
NativeModules,
|
|
14
|
+
} from 'react-native';
|
|
15
|
+
import { StackActions, useNavigation } from '@react-navigation/native';
|
|
16
|
+
import { RNCamera } from 'react-native-camera';
|
|
17
|
+
import TextRecognition from 'react-native-text-recognition';
|
|
18
|
+
import {
|
|
19
|
+
openSettings,
|
|
20
|
+
PERMISSIONS,
|
|
21
|
+
request,
|
|
22
|
+
RESULTS,
|
|
23
|
+
} from 'react-native-permissions';
|
|
24
|
+
import { MText } from '../../components/MText';
|
|
25
|
+
import MButton from '../../components/MButton';
|
|
26
|
+
import { IconBackWhite } from '../../assets/icons';
|
|
27
|
+
import { commonStyles } from '../CommonStyles';
|
|
28
|
+
import nfcStore from './store';
|
|
29
|
+
|
|
30
|
+
const { NFCReader } = NativeModules;
|
|
31
|
+
|
|
32
|
+
const MRZScanner = (props: any) => {
|
|
33
|
+
const navigation = useNavigation();
|
|
34
|
+
const loan = props?.route?.params?.loan;
|
|
35
|
+
|
|
36
|
+
const [hasCameraPermission, setHasCameraPermission] = useState(null);
|
|
37
|
+
const [mrzData, setMrzData] = useState('');
|
|
38
|
+
const [passPermission, setPassPermission] = useState(false);
|
|
39
|
+
const cameraRef = useRef(null);
|
|
40
|
+
|
|
41
|
+
const requestPermissions = () => {
|
|
42
|
+
request(
|
|
43
|
+
Platform.OS === 'ios'
|
|
44
|
+
? PERMISSIONS.IOS.CAMERA
|
|
45
|
+
: PERMISSIONS.ANDROID.CAMERA
|
|
46
|
+
).then((result) => {
|
|
47
|
+
switch (result) {
|
|
48
|
+
case RESULTS.UNAVAILABLE:
|
|
49
|
+
console.log(
|
|
50
|
+
'This feature is not available (on this device / in this context)'
|
|
51
|
+
);
|
|
52
|
+
Alert.alert(
|
|
53
|
+
'Thông báo',
|
|
54
|
+
'Máy ảnh trên thiết bị không tương thích.\nVui lòng kiểm tra lại thiết bị!',
|
|
55
|
+
[{ text: 'Đồng ý' }]
|
|
56
|
+
);
|
|
57
|
+
break;
|
|
58
|
+
case RESULTS.DENIED:
|
|
59
|
+
console.log(
|
|
60
|
+
'The permission has not been requested / is denied but requestable'
|
|
61
|
+
);
|
|
62
|
+
Alert.alert(
|
|
63
|
+
'Thông báo',
|
|
64
|
+
'Bạn đã từ chối quyền máy ảnh. Vui lòng cấp quyền máy ảnh để tiếp tục!',
|
|
65
|
+
[
|
|
66
|
+
{
|
|
67
|
+
text: 'Đồng ý',
|
|
68
|
+
onPress: () => {
|
|
69
|
+
if (Platform.OS === 'ios') {
|
|
70
|
+
openSettings();
|
|
71
|
+
} else {
|
|
72
|
+
requestPermissions();
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
]
|
|
77
|
+
);
|
|
78
|
+
break;
|
|
79
|
+
case RESULTS.LIMITED:
|
|
80
|
+
console.log('The permission is limited: some actions are possible');
|
|
81
|
+
Alert.alert(
|
|
82
|
+
'Thông báo',
|
|
83
|
+
'Quyền máy ảnh bị hạn chế. Vui lòng kiểm tra lại để tiếp tục!',
|
|
84
|
+
[
|
|
85
|
+
{
|
|
86
|
+
text: 'Đồng ý',
|
|
87
|
+
onPress: () => {
|
|
88
|
+
if (Platform.OS === 'ios') {
|
|
89
|
+
openSettings();
|
|
90
|
+
} else {
|
|
91
|
+
requestPermissions();
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
]
|
|
96
|
+
);
|
|
97
|
+
break;
|
|
98
|
+
case RESULTS.GRANTED:
|
|
99
|
+
console.log('The permission is granted');
|
|
100
|
+
setPassPermission(true);
|
|
101
|
+
break;
|
|
102
|
+
case RESULTS.BLOCKED:
|
|
103
|
+
console.log('The permission is denied and not requestable anymore');
|
|
104
|
+
Alert.alert(
|
|
105
|
+
'Thông báo',
|
|
106
|
+
'Bạn đã từ chối quyền máy ảnh. Vui lòng cấp quyền máy ảnh để tiếp tục!',
|
|
107
|
+
[
|
|
108
|
+
{
|
|
109
|
+
text: 'Đồng ý',
|
|
110
|
+
onPress: () => {
|
|
111
|
+
if (Platform.OS === 'ios') {
|
|
112
|
+
openSettings();
|
|
113
|
+
} else {
|
|
114
|
+
openSettings();
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
]
|
|
119
|
+
);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
useEffect(() => {
|
|
126
|
+
requestPermissions();
|
|
127
|
+
}, []);
|
|
128
|
+
|
|
129
|
+
const convertToDate = (input, end) => {
|
|
130
|
+
let yearPrefix = input.substring(0, 2);
|
|
131
|
+
let year = end
|
|
132
|
+
? '20' + yearPrefix
|
|
133
|
+
: parseInt(yearPrefix) > 20
|
|
134
|
+
? '19' + yearPrefix
|
|
135
|
+
: '20' + yearPrefix;
|
|
136
|
+
let month = input.substring(2, 4);
|
|
137
|
+
let day = input.substring(4, 6);
|
|
138
|
+
|
|
139
|
+
return year + '-' + month + '-' + day;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const extractMRZInfo = (text) => {
|
|
143
|
+
let documentNumber = '';
|
|
144
|
+
let birthDate = '';
|
|
145
|
+
let expirationDate = '';
|
|
146
|
+
const regex1 = /VNM(\d{9})/;
|
|
147
|
+
const match1 = text.match(regex1);
|
|
148
|
+
|
|
149
|
+
// If a match is found, return the 9 digits, otherwise return null
|
|
150
|
+
if (match1) {
|
|
151
|
+
documentNumber = match1[1];
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
console.log('documentNumber', documentNumber);
|
|
155
|
+
|
|
156
|
+
// Regular expression to match 'VNM' followed by 9 digits, then two 6-digit numbers
|
|
157
|
+
const regex = /(\d{6}).[MF](\d{6})/;
|
|
158
|
+
|
|
159
|
+
// Search for the pattern in the text
|
|
160
|
+
const match = text.replace(/ /g, '').match(regex);
|
|
161
|
+
|
|
162
|
+
// If a match is found, return the captured groups, otherwise return null
|
|
163
|
+
if (match) {
|
|
164
|
+
console.log({
|
|
165
|
+
documentNumber: documentNumber,
|
|
166
|
+
birthDate: match[1],
|
|
167
|
+
expirationDate: match[2],
|
|
168
|
+
});
|
|
169
|
+
(birthDate = match[1]), (expirationDate = match[2]);
|
|
170
|
+
} else {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
if (documentNumber && birthDate && expirationDate) {
|
|
174
|
+
console.log(convertToDate(birthDate, false));
|
|
175
|
+
console.log(convertToDate(expirationDate, true));
|
|
176
|
+
try {
|
|
177
|
+
NFCReader.startNFCReader(
|
|
178
|
+
documentNumber,
|
|
179
|
+
convertToDate(birthDate, false),
|
|
180
|
+
convertToDate(expirationDate, true),
|
|
181
|
+
(error, response) => {
|
|
182
|
+
try {
|
|
183
|
+
const convertData = JSON.parse(response);
|
|
184
|
+
const body = {
|
|
185
|
+
LoanBriefId: loan?.id,
|
|
186
|
+
RawSod: convertData?.sod,
|
|
187
|
+
RawDg1: convertData?.dg1,
|
|
188
|
+
RawDg2: convertData?.dg2,
|
|
189
|
+
RawDg13: convertData?.dg13,
|
|
190
|
+
RawDg14: convertData?.dg14,
|
|
191
|
+
RawDg15: convertData?.dg15,
|
|
192
|
+
};
|
|
193
|
+
nfcStore.addNfcData(body, () => {
|
|
194
|
+
navigation.dispatch(
|
|
195
|
+
StackActions.push(ScreenNames.FullSubmit, {
|
|
196
|
+
loan: loan,
|
|
197
|
+
})
|
|
198
|
+
);
|
|
199
|
+
});
|
|
200
|
+
} catch (e) {
|
|
201
|
+
console.log(e);
|
|
202
|
+
Alert.alert('Lỗi', e);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
);
|
|
206
|
+
} catch (e) {
|
|
207
|
+
console.log(e);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
const handleTextRecognition = async (imagePath) => {
|
|
213
|
+
const result = await TextRecognition.recognize(imagePath);
|
|
214
|
+
const mrzText = result.join('');
|
|
215
|
+
setMrzData(mrzText);
|
|
216
|
+
console.log(extractMRZInfo(mrzText));
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const takePicture = async () => {
|
|
220
|
+
if (cameraRef.current) {
|
|
221
|
+
const options = { quality: 0.8, base64: true };
|
|
222
|
+
const data = await cameraRef.current.takePictureAsync(options);
|
|
223
|
+
await handleTextRecognition(data.uri);
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
return (
|
|
228
|
+
<View style={styles.container}>
|
|
229
|
+
<RNCamera
|
|
230
|
+
ref={cameraRef}
|
|
231
|
+
style={styles.camera}
|
|
232
|
+
type={RNCamera.Constants.Type.back}
|
|
233
|
+
captureAudio={false}
|
|
234
|
+
></RNCamera>
|
|
235
|
+
<View style={styles.overlay}>
|
|
236
|
+
<View style={styles.overlayTop} />
|
|
237
|
+
<View style={styles.overlayCenter}>
|
|
238
|
+
<View style={styles.overlayLeft} />
|
|
239
|
+
<View style={styles.overlayRect}></View>
|
|
240
|
+
<View style={styles.overlayRight} />
|
|
241
|
+
</View>
|
|
242
|
+
<View style={styles.overlayBottom} />
|
|
243
|
+
</View>
|
|
244
|
+
|
|
245
|
+
<View style={{ position: 'absolute', top: 0, left: 0 }}>
|
|
246
|
+
<SafeAreaView style={{ flex: 1 }}>
|
|
247
|
+
<View
|
|
248
|
+
style={[
|
|
249
|
+
commonStyles.row,
|
|
250
|
+
commonStyles.alignCenter,
|
|
251
|
+
{ height: 56, paddingHorizontal: 16 },
|
|
252
|
+
]}
|
|
253
|
+
>
|
|
254
|
+
<MButton
|
|
255
|
+
onPress={() => {
|
|
256
|
+
navigation.goBack();
|
|
257
|
+
}}
|
|
258
|
+
style={[{ width: 48, height: 48, justifyContent: 'center' }]}
|
|
259
|
+
>
|
|
260
|
+
<IconBackWhite />
|
|
261
|
+
</MButton>
|
|
262
|
+
<View style={{ flex: 1, paddingRight: 48 }}>
|
|
263
|
+
<MText
|
|
264
|
+
style={{
|
|
265
|
+
color: 'white',
|
|
266
|
+
fontSize: 16,
|
|
267
|
+
textAlign: 'center',
|
|
268
|
+
padding: 16,
|
|
269
|
+
fontWeight: '600',
|
|
270
|
+
}}
|
|
271
|
+
>
|
|
272
|
+
EKYC
|
|
273
|
+
</MText>
|
|
274
|
+
</View>
|
|
275
|
+
</View>
|
|
276
|
+
<MText
|
|
277
|
+
style={{
|
|
278
|
+
color: 'white',
|
|
279
|
+
fontSize: 16,
|
|
280
|
+
textAlign: 'center',
|
|
281
|
+
padding: 16,
|
|
282
|
+
}}
|
|
283
|
+
>
|
|
284
|
+
Dùng camera để quét chuỗi ký tự mặt sau thẻ CCCD gắn chip ở phía
|
|
285
|
+
dưới
|
|
286
|
+
</MText>
|
|
287
|
+
</SafeAreaView>
|
|
288
|
+
</View>
|
|
289
|
+
<View style={styles.buttonContainer}>
|
|
290
|
+
<MText
|
|
291
|
+
style={{
|
|
292
|
+
color: 'white',
|
|
293
|
+
fontSize: 14,
|
|
294
|
+
textAlign: 'center',
|
|
295
|
+
padding: 16,
|
|
296
|
+
}}
|
|
297
|
+
>
|
|
298
|
+
Vui lòng đặt giấy tờ nằm vừa khung hình chữ nhật, chụp đủ ánh sáng và
|
|
299
|
+
rõ nét.
|
|
300
|
+
</MText>
|
|
301
|
+
<TouchableOpacity
|
|
302
|
+
onPress={() => takePicture()}
|
|
303
|
+
style={styles.captureButton}
|
|
304
|
+
></TouchableOpacity>
|
|
305
|
+
</View>
|
|
306
|
+
</View>
|
|
307
|
+
);
|
|
308
|
+
};
|
|
309
|
+
const styles = StyleSheet.create({
|
|
310
|
+
container: {
|
|
311
|
+
flex: 1,
|
|
312
|
+
},
|
|
313
|
+
camera: {
|
|
314
|
+
flex: 1,
|
|
315
|
+
},
|
|
316
|
+
buttonContainer: {
|
|
317
|
+
flex: 0,
|
|
318
|
+
flexDirection: 'column',
|
|
319
|
+
justifyContent: 'center',
|
|
320
|
+
alignItems: 'center',
|
|
321
|
+
position: 'absolute',
|
|
322
|
+
bottom: 40,
|
|
323
|
+
left: 0,
|
|
324
|
+
right: 0,
|
|
325
|
+
},
|
|
326
|
+
captureButton: {
|
|
327
|
+
width: 56,
|
|
328
|
+
height: 56,
|
|
329
|
+
borderRadius: 35,
|
|
330
|
+
backgroundColor: 'white',
|
|
331
|
+
justifyContent: 'center',
|
|
332
|
+
alignItems: 'center',
|
|
333
|
+
},
|
|
334
|
+
innerCaptureButton: {
|
|
335
|
+
width: 60,
|
|
336
|
+
height: 60,
|
|
337
|
+
borderRadius: 30,
|
|
338
|
+
backgroundColor: 'red',
|
|
339
|
+
},
|
|
340
|
+
overlay: {
|
|
341
|
+
position: 'absolute',
|
|
342
|
+
top: 0,
|
|
343
|
+
left: 0,
|
|
344
|
+
right: 0,
|
|
345
|
+
bottom: 0,
|
|
346
|
+
justifyContent: 'center',
|
|
347
|
+
alignItems: 'center',
|
|
348
|
+
},
|
|
349
|
+
overlayTop: {
|
|
350
|
+
flex: 1,
|
|
351
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
352
|
+
width: '100%',
|
|
353
|
+
},
|
|
354
|
+
overlayCenter: {
|
|
355
|
+
flexDirection: 'row',
|
|
356
|
+
},
|
|
357
|
+
overlayLeft: {
|
|
358
|
+
flex: 1,
|
|
359
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
360
|
+
},
|
|
361
|
+
overlayRect: {
|
|
362
|
+
width: '90%',
|
|
363
|
+
height: 100,
|
|
364
|
+
borderColor: 'white',
|
|
365
|
+
borderWidth: 2,
|
|
366
|
+
justifyContent: 'center',
|
|
367
|
+
alignItems: 'center',
|
|
368
|
+
},
|
|
369
|
+
instructionText: {
|
|
370
|
+
color: 'white',
|
|
371
|
+
textAlign: 'center',
|
|
372
|
+
paddingHorizontal: 10,
|
|
373
|
+
fontSize: 14,
|
|
374
|
+
position: 'absolute',
|
|
375
|
+
top: -50,
|
|
376
|
+
},
|
|
377
|
+
overlayRight: {
|
|
378
|
+
flex: 1,
|
|
379
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
380
|
+
},
|
|
381
|
+
overlayBottom: {
|
|
382
|
+
flex: 1,
|
|
383
|
+
backgroundColor: 'rgba(0, 0, 0, 0.5)',
|
|
384
|
+
width: '100%',
|
|
385
|
+
},
|
|
386
|
+
mrzContainer: {
|
|
387
|
+
padding: 10,
|
|
388
|
+
},
|
|
389
|
+
mrzText: {
|
|
390
|
+
fontSize: 16,
|
|
391
|
+
},
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
export default MRZScanner;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
//@ts-nocheck
|
|
2
|
+
import { makeAutoObservable } from "mobx"
|
|
3
|
+
import { Api } from '../../services/api';
|
|
4
|
+
class Store {
|
|
5
|
+
isLoading = false
|
|
6
|
+
|
|
7
|
+
constructor() {
|
|
8
|
+
makeAutoObservable(this)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
async addNfcData(body: any, onSuccess?: Function, onError?: Function) {
|
|
12
|
+
this.isLoading = true
|
|
13
|
+
try {
|
|
14
|
+
const response = await Api.getInstance().addNfcData(body)
|
|
15
|
+
this.isLoading = false
|
|
16
|
+
if (response.kind === "ok") {
|
|
17
|
+
if (response.data.meta.errorCode === 200) {
|
|
18
|
+
if (onSuccess) onSuccess()
|
|
19
|
+
} else {
|
|
20
|
+
Alert.alert("Thông báo", response.data.meta?.errorMessage)
|
|
21
|
+
if (onError) onError()
|
|
22
|
+
}
|
|
23
|
+
} else {
|
|
24
|
+
Alert.alert("Thông báo", "Có lỗi xảy ra. Vui lòng thử lại sau")
|
|
25
|
+
if (onError) onError()
|
|
26
|
+
}
|
|
27
|
+
} catch (error) {
|
|
28
|
+
console.log(error)
|
|
29
|
+
this.isLoading = false
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const nfcStore = new Store()
|
|
35
|
+
export default nfcStore
|
|
@@ -9,9 +9,14 @@ import MButton from '../../components/MButton';
|
|
|
9
9
|
import { MText } from '../../components/MText';
|
|
10
10
|
import { color } from '../../theme';
|
|
11
11
|
import { IconBack } from '../../assets/icons';
|
|
12
|
+
import Pdf from 'react-native-pdf';
|
|
13
|
+
import LinearGradient from 'react-native-linear-gradient';
|
|
14
|
+
import livenessStore from '../liveness/LivenessStore';
|
|
12
15
|
|
|
13
16
|
export const TermScreen = observer(function TermScreen(props) {
|
|
14
17
|
const navigation = useNavigation();
|
|
18
|
+
const [isAccept, setIsAccept] = useState(true);
|
|
19
|
+
const loan = props?.route?.params;
|
|
15
20
|
|
|
16
21
|
useEffect(() => {}, []);
|
|
17
22
|
|
|
@@ -59,10 +64,118 @@ export const TermScreen = observer(function TermScreen(props) {
|
|
|
59
64
|
</MText>
|
|
60
65
|
</View>
|
|
61
66
|
<View style={{ backgroundColor: color.border }} />
|
|
62
|
-
<WebView
|
|
67
|
+
{/* <WebView
|
|
63
68
|
source={{ uri: 'https://tima.vn/dieu-khoan.html' }}
|
|
64
69
|
style={{ flex: 1 }}
|
|
70
|
+
/> */}
|
|
71
|
+
<Pdf
|
|
72
|
+
source={{
|
|
73
|
+
uri: 'https://cdn.tima.vn/file-pdf/20240509_DIEU_KHOAN_VA_DIEU_KIEN_TIMA.pdf',
|
|
74
|
+
}}
|
|
75
|
+
style={[commonStyles.fill]}
|
|
65
76
|
/>
|
|
77
|
+
<View
|
|
78
|
+
style={{
|
|
79
|
+
backgroundColor: 'white',
|
|
80
|
+
paddingHorizontal: 24,
|
|
81
|
+
position: 'absolute',
|
|
82
|
+
bottom: 0,
|
|
83
|
+
left: 0,
|
|
84
|
+
right: 0,
|
|
85
|
+
paddingVertical: 16,
|
|
86
|
+
}}
|
|
87
|
+
>
|
|
88
|
+
<View
|
|
89
|
+
style={{
|
|
90
|
+
width: '100%',
|
|
91
|
+
alignItems: 'center',
|
|
92
|
+
flexDirection: 'row',
|
|
93
|
+
}}
|
|
94
|
+
>
|
|
95
|
+
<MButton
|
|
96
|
+
onPress={() => {
|
|
97
|
+
setIsAccept(!isAccept);
|
|
98
|
+
}}
|
|
99
|
+
>
|
|
100
|
+
{!isAccept ? <CheckBox /> : <CheckBoxActive />}
|
|
101
|
+
</MButton>
|
|
102
|
+
<MButton
|
|
103
|
+
style={{ flexDirection: 'row' }}
|
|
104
|
+
onPress={() => {
|
|
105
|
+
setIsAccept(!isAccept);
|
|
106
|
+
}}
|
|
107
|
+
>
|
|
108
|
+
<MText
|
|
109
|
+
style={{
|
|
110
|
+
marginLeft: 10,
|
|
111
|
+
color: '#1D1B1B',
|
|
112
|
+
fontSize: 14,
|
|
113
|
+
fontWeight: '400',
|
|
114
|
+
}}
|
|
115
|
+
>
|
|
116
|
+
Tôi đồng ý với các
|
|
117
|
+
</MText>
|
|
118
|
+
|
|
119
|
+
<MText
|
|
120
|
+
style={{
|
|
121
|
+
color: color.primary,
|
|
122
|
+
fontSize: 14,
|
|
123
|
+
fontWeight: '400',
|
|
124
|
+
}}
|
|
125
|
+
>
|
|
126
|
+
{' '}
|
|
127
|
+
điều khoản
|
|
128
|
+
</MText>
|
|
129
|
+
<MText
|
|
130
|
+
style={{
|
|
131
|
+
marginLeft: 4,
|
|
132
|
+
color: '#1D1B1B',
|
|
133
|
+
fontSize: 14,
|
|
134
|
+
fontWeight: '400',
|
|
135
|
+
}}
|
|
136
|
+
>
|
|
137
|
+
của Tima
|
|
138
|
+
</MText>
|
|
139
|
+
</MButton>
|
|
140
|
+
</View>
|
|
141
|
+
<TouchableOpacity
|
|
142
|
+
style={{
|
|
143
|
+
flex: 1,
|
|
144
|
+
width: '100%',
|
|
145
|
+
}}
|
|
146
|
+
disabled={!isAccept}
|
|
147
|
+
onPress={() => {
|
|
148
|
+
livenessStore.confirmLicense(loan?.id, () => {
|
|
149
|
+
navigation.goBack();
|
|
150
|
+
});
|
|
151
|
+
}}
|
|
152
|
+
>
|
|
153
|
+
<LinearGradient
|
|
154
|
+
style={{
|
|
155
|
+
height: 40,
|
|
156
|
+
marginVertical: 16,
|
|
157
|
+
borderRadius: 30,
|
|
158
|
+
alignItems: 'center',
|
|
159
|
+
justifyContent: 'center',
|
|
160
|
+
}}
|
|
161
|
+
colors={
|
|
162
|
+
isAccept ? ['#FF7A00', '#EF4123'] : ['#BDBDBD', '#BDBDBD']
|
|
163
|
+
}
|
|
164
|
+
>
|
|
165
|
+
<MText
|
|
166
|
+
style={[
|
|
167
|
+
commonStyles.textNormalBold,
|
|
168
|
+
{
|
|
169
|
+
color: true ? 'white' : '#333333',
|
|
170
|
+
textAlign: 'center',
|
|
171
|
+
},
|
|
172
|
+
]}
|
|
173
|
+
>
|
|
174
|
+
{'xác nhận'.toUpperCase()}
|
|
175
|
+
</MText>
|
|
176
|
+
</LinearGradient>
|
|
177
|
+
</TouchableOpacity>
|
|
178
|
+
</View>
|
|
66
179
|
</View>
|
|
67
180
|
</SafeAreaView>
|
|
68
181
|
</View>
|
package/src/services/api/api.ts
CHANGED
|
@@ -2319,4 +2319,60 @@ export class Api {
|
|
|
2319
2319
|
return { kind: "bad-data" }
|
|
2320
2320
|
}
|
|
2321
2321
|
}
|
|
2322
|
+
|
|
2323
|
+
async getPaymentScheduleTima(id) {
|
|
2324
|
+
// make the api call
|
|
2325
|
+
const response: ApiResponse<any> = await this.apisauce.get(`api/v2.0/loanbrief/payment_schedule_tima?loanBriefId=${id}`)
|
|
2326
|
+
myLog(response)
|
|
2327
|
+
// the typical ways to die when calling an api
|
|
2328
|
+
if (!response.ok) {
|
|
2329
|
+
const problem = getGeneralApiProblem(response)
|
|
2330
|
+
if (problem) return problem
|
|
2331
|
+
}
|
|
2332
|
+
|
|
2333
|
+
// transform the data into the format we are expecting
|
|
2334
|
+
try {
|
|
2335
|
+
return { kind: "ok", data: response.data }
|
|
2336
|
+
} catch {
|
|
2337
|
+
return { kind: "bad-data" }
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
|
|
2341
|
+
async confirmRule(loandID) {
|
|
2342
|
+
// make the api call
|
|
2343
|
+
const response: ApiResponse<any> = await this.apisauce.post(`api/v2.0/loanbrief/log_confirm_tima_rules`, {
|
|
2344
|
+
LoanBriefId: loandID
|
|
2345
|
+
})
|
|
2346
|
+
myLog(response)
|
|
2347
|
+
// the typical ways to die when calling an api
|
|
2348
|
+
if (!response.ok) {
|
|
2349
|
+
const problem = getGeneralApiProblem(response)
|
|
2350
|
+
if (problem) return problem
|
|
2351
|
+
}
|
|
2352
|
+
|
|
2353
|
+
// transform the data into the format we are expecting
|
|
2354
|
+
try {
|
|
2355
|
+
return { kind: "ok", data: response.data }
|
|
2356
|
+
} catch {
|
|
2357
|
+
return { kind: "bad-data" }
|
|
2358
|
+
}
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
async addNfcData(body: any) {
|
|
2362
|
+
// make the api call
|
|
2363
|
+
const response: ApiResponse<any> = await this.apisauce.post(`api/v1.0/timacare/add_nfc_raw`, body)
|
|
2364
|
+
myLog(response)
|
|
2365
|
+
// the typical ways to die when calling an api
|
|
2366
|
+
if (!response.ok) {
|
|
2367
|
+
const problem = getGeneralApiProblem(response)
|
|
2368
|
+
if (problem) return problem
|
|
2369
|
+
}
|
|
2370
|
+
// transform the data into the format we are expecting
|
|
2371
|
+
try {
|
|
2372
|
+
return { kind: "ok", data: response.data }
|
|
2373
|
+
} catch {
|
|
2374
|
+
return { kind: "bad-data" }
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
|
|
2322
2378
|
}
|