react-native-biometric-verifier 0.0.6 → 0.0.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/package.json +1 -1
- package/src/components/EmployeeCard.js +4 -4
- package/src/index.js +67 -32
- package/src/utils/constants.js +0 -12
- package/src/utils/getLoaderGif.js +4 -4
- package/src/utils/Global.js +0 -6
package/package.json
CHANGED
|
@@ -2,10 +2,10 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import { View, Text, Image } from 'react-native';
|
|
3
3
|
import Icon from 'react-native-vector-icons/MaterialIcons';
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
|
-
import { COLORS
|
|
5
|
+
import { COLORS} from '../utils/constants';
|
|
6
6
|
import { styles } from './styles';
|
|
7
7
|
|
|
8
|
-
export const EmployeeCard = ({ employeeData }) => {
|
|
8
|
+
export const EmployeeCard = ({ employeeData,apiurl }) => {
|
|
9
9
|
const [imageError, setImageError] = useState(false);
|
|
10
10
|
|
|
11
11
|
if (!employeeData || typeof employeeData !== 'object') {
|
|
@@ -18,8 +18,8 @@ export const EmployeeCard = ({ employeeData }) => {
|
|
|
18
18
|
const employeeName = facename || 'Unknown Employee';
|
|
19
19
|
const employeeId = faceid || 'N/A';
|
|
20
20
|
const imageSource = !imageError && imageurl
|
|
21
|
-
? { uri: `${
|
|
22
|
-
: { uri: `${
|
|
21
|
+
? { uri: `${apiurl}file/filedownload/photo/${imageurl}` }
|
|
22
|
+
: { uri: `${apiurl}file/getCommonFile/image/camera.png` }; // Add a local fallback image in assets
|
|
23
23
|
|
|
24
24
|
return (
|
|
25
25
|
<View style={styles.employeeCard}>
|
package/src/index.js
CHANGED
|
@@ -16,7 +16,6 @@ import {
|
|
|
16
16
|
COLORS,
|
|
17
17
|
COUNTDOWN_DURATION,
|
|
18
18
|
MAX_DISTANCE_METERS,
|
|
19
|
-
RECOGNIZE_URL,
|
|
20
19
|
} from './utils/constants';
|
|
21
20
|
import Loader from './components/Loader';
|
|
22
21
|
import { CountdownTimer } from './components/CountdownTimer';
|
|
@@ -28,9 +27,9 @@ import { useNavigation } from '@react-navigation/native';
|
|
|
28
27
|
import networkServiceCall from './utils/NetworkServiceCall';
|
|
29
28
|
import { getLoaderGif } from './utils/getLoaderGif';
|
|
30
29
|
|
|
31
|
-
const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback }) => {
|
|
30
|
+
const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback, apiurl }) => {
|
|
32
31
|
const navigation = useNavigation();
|
|
33
|
-
|
|
32
|
+
|
|
34
33
|
const { countdown, startCountdown, resetCountdown } = useCountdown();
|
|
35
34
|
const { requestLocationPermission, getCurrentLocation } = useGeolocation();
|
|
36
35
|
const { convertImageToBase64 } = useImageProcessing();
|
|
@@ -80,19 +79,39 @@ const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback
|
|
|
80
79
|
animationState: ANIMATION_STATES.ERROR,
|
|
81
80
|
});
|
|
82
81
|
resetState();
|
|
83
|
-
navigation.goBack();
|
|
82
|
+
if (navigation.canGoBack()) navigation.goBack();
|
|
84
83
|
}, [navigation, notifyMessage, resetState, updateState]);
|
|
85
84
|
|
|
85
|
+
const validateApiUrl = useCallback(() => {
|
|
86
|
+
if (!apiurl || typeof apiurl !== 'string') {
|
|
87
|
+
notifyMessage('Invalid API URL configuration.', 'error');
|
|
88
|
+
updateState({ animationState: ANIMATION_STATES.ERROR });
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}, [apiurl, notifyMessage, updateState]);
|
|
93
|
+
|
|
86
94
|
const uploadFaceScan = useCallback(async (selfie) => {
|
|
95
|
+
if (!validateApiUrl()) return;
|
|
96
|
+
|
|
87
97
|
const currentData = dataRef.current;
|
|
88
|
-
const base64 = await convertImageToBase64(selfie.uri);
|
|
89
98
|
if (!currentData) {
|
|
90
99
|
notifyMessage('Employee data not found.', 'error');
|
|
91
100
|
updateState({ animationState: ANIMATION_STATES.ERROR });
|
|
92
101
|
return;
|
|
93
102
|
}
|
|
103
|
+
|
|
104
|
+
let base64;
|
|
105
|
+
try {
|
|
106
|
+
base64 = await convertImageToBase64(selfie?.uri);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
notifyMessage('Image conversion failed.', 'error');
|
|
109
|
+
updateState({ animationState: ANIMATION_STATES.ERROR });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
94
113
|
if (!base64) {
|
|
95
|
-
notifyMessage('
|
|
114
|
+
notifyMessage('Failed to process image.', 'error');
|
|
96
115
|
updateState({ animationState: ANIMATION_STATES.ERROR });
|
|
97
116
|
return;
|
|
98
117
|
}
|
|
@@ -103,38 +122,50 @@ const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback
|
|
|
103
122
|
});
|
|
104
123
|
|
|
105
124
|
try {
|
|
106
|
-
const body = { image: base64 }
|
|
107
|
-
const header = { faceid: currentData }
|
|
108
|
-
const
|
|
109
|
-
|
|
125
|
+
const body = { image: base64 };
|
|
126
|
+
const header = { faceid: currentData };
|
|
127
|
+
const buttonapi = `${apiurl}python/recognize`;
|
|
128
|
+
|
|
129
|
+
console.log("buttonapi--------------------", buttonapi);
|
|
130
|
+
|
|
131
|
+
const response = await networkServiceCall("POST", buttonapi, header, body);
|
|
132
|
+
|
|
133
|
+
if (response?.httpstatus === 200) {
|
|
110
134
|
notifyMessage('Identity verified successfully!', 'success');
|
|
111
135
|
updateState({
|
|
112
|
-
employeeData: response.data?.data,
|
|
136
|
+
employeeData: response.data?.data || null,
|
|
113
137
|
animationState: ANIMATION_STATES.SUCCESS,
|
|
114
138
|
});
|
|
115
139
|
|
|
116
140
|
if (qrscan) {
|
|
117
|
-
// If QR scanning is required, continue with QR Scan
|
|
118
141
|
setTimeout(() => startQRCodeScan(), 1500);
|
|
119
142
|
} else {
|
|
120
|
-
// If only Face recognition → finish process
|
|
121
143
|
setTimeout(() => {
|
|
122
|
-
|
|
144
|
+
try {
|
|
145
|
+
callback?.(dataRef.current);
|
|
146
|
+
} catch (err) {
|
|
147
|
+
console.error("Callback execution failed:", err);
|
|
148
|
+
notifyMessage('Unexpected error after verification.', 'error');
|
|
149
|
+
}
|
|
123
150
|
updateState({ modalVisible: false });
|
|
124
151
|
resetState();
|
|
125
152
|
}, 1500);
|
|
126
153
|
}
|
|
127
154
|
} else {
|
|
155
|
+
notifyMessage(
|
|
156
|
+
response?.data?.error?.message || 'Face not recognized. Please try again.',
|
|
157
|
+
'error'
|
|
158
|
+
);
|
|
128
159
|
updateState({ animationState: ANIMATION_STATES.ERROR });
|
|
129
|
-
notifyMessage(response.data?.error?.message || 'Face not recognized. Please try again.', 'error');
|
|
130
160
|
}
|
|
131
161
|
} catch (error) {
|
|
132
|
-
|
|
162
|
+
console.error("Face recognition API error:", error);
|
|
133
163
|
notifyMessage('Connection error. Please check your network.', 'error');
|
|
164
|
+
updateState({ animationState: ANIMATION_STATES.ERROR });
|
|
134
165
|
} finally {
|
|
135
166
|
updateState({ isLoading: false });
|
|
136
167
|
}
|
|
137
|
-
}, [convertImageToBase64, notifyMessage, qrscan, resetState, updateState, callback]);
|
|
168
|
+
}, [convertImageToBase64, notifyMessage, qrscan, resetState, updateState, callback, validateApiUrl]);
|
|
138
169
|
|
|
139
170
|
const handleStartFaceScan = useCallback(() => {
|
|
140
171
|
updateState({
|
|
@@ -162,9 +193,11 @@ const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback
|
|
|
162
193
|
}, [navigation, updateState]);
|
|
163
194
|
|
|
164
195
|
const handleQRScanned = useCallback(async (qrCodeData) => {
|
|
165
|
-
|
|
196
|
+
if (!validateApiUrl()) return;
|
|
197
|
+
|
|
198
|
+
updateState({
|
|
166
199
|
animationState: ANIMATION_STATES.PROCESSING,
|
|
167
|
-
isLoading: true
|
|
200
|
+
isLoading: true,
|
|
168
201
|
});
|
|
169
202
|
|
|
170
203
|
try {
|
|
@@ -175,7 +208,7 @@ const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback
|
|
|
175
208
|
return;
|
|
176
209
|
}
|
|
177
210
|
|
|
178
|
-
const qrString = typeof qrCodeData === 'object' ? qrCodeData
|
|
211
|
+
const qrString = typeof qrCodeData === 'object' ? qrCodeData?.data : qrCodeData;
|
|
179
212
|
if (!qrString || typeof qrString !== 'string') {
|
|
180
213
|
notifyMessage('Invalid QR code. Please try again.', 'error');
|
|
181
214
|
updateState({ animationState: ANIMATION_STATES.ERROR });
|
|
@@ -188,18 +221,19 @@ const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback
|
|
|
188
221
|
const lng = parseFloat(lngStr);
|
|
189
222
|
|
|
190
223
|
const validCoords = !isNaN(lat) && !isNaN(lng);
|
|
191
|
-
const validDev = !isNaN(location
|
|
224
|
+
const validDev = !isNaN(location?.latitude) && !isNaN(location?.longitude);
|
|
192
225
|
|
|
193
226
|
if (validCoords && validDev) {
|
|
194
|
-
const distance = getDistanceInMeters(
|
|
195
|
-
lat,
|
|
196
|
-
lng,
|
|
197
|
-
location.latitude,
|
|
198
|
-
location.longitude
|
|
199
|
-
);
|
|
227
|
+
const distance = getDistanceInMeters(lat, lng, location.latitude, location.longitude);
|
|
200
228
|
|
|
201
229
|
if (distance <= MAX_DISTANCE_METERS) {
|
|
202
|
-
|
|
230
|
+
try {
|
|
231
|
+
callback?.(dataRef.current);
|
|
232
|
+
} catch (err) {
|
|
233
|
+
console.error("Callback execution failed:", err);
|
|
234
|
+
notifyMessage('Unexpected error during location verification.', 'error');
|
|
235
|
+
}
|
|
236
|
+
|
|
203
237
|
notifyMessage('Location verified successfully!', 'success');
|
|
204
238
|
updateState({ animationState: ANIMATION_STATES.SUCCESS });
|
|
205
239
|
|
|
@@ -218,13 +252,14 @@ const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback
|
|
|
218
252
|
resetState();
|
|
219
253
|
}
|
|
220
254
|
} catch (error) {
|
|
255
|
+
console.error("QR scan handling failed:", error);
|
|
221
256
|
notifyMessage('Unable to verify location. Please try again.', 'error');
|
|
222
257
|
updateState({ animationState: ANIMATION_STATES.ERROR });
|
|
223
258
|
resetState();
|
|
224
259
|
} finally {
|
|
225
260
|
updateState({ isLoading: false });
|
|
226
261
|
}
|
|
227
|
-
}, [callback, getCurrentLocation, notifyMessage, requestLocationPermission, resetState, updateState]);
|
|
262
|
+
}, [callback, getCurrentLocation, notifyMessage, requestLocationPermission, resetState, updateState, validateApiUrl]);
|
|
228
263
|
|
|
229
264
|
const startProcess = useCallback(() => {
|
|
230
265
|
startCountdown(COUNTDOWN_DURATION, handleCountdownFinish);
|
|
@@ -270,7 +305,7 @@ const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback
|
|
|
270
305
|
{state.employeeData && (
|
|
271
306
|
<EmployeeCard
|
|
272
307
|
employeeData={state.employeeData}
|
|
273
|
-
|
|
308
|
+
apiurl={apiurl}
|
|
274
309
|
/>
|
|
275
310
|
)}
|
|
276
311
|
|
|
@@ -285,8 +320,8 @@ const BiometricVerificationModal = React.memo(({ data, qrscan = false, callback
|
|
|
285
320
|
currentTime={countdown}
|
|
286
321
|
/>
|
|
287
322
|
|
|
288
|
-
{state.isLoading && getLoaderGif(state.animationState, state.currentStep) && (
|
|
289
|
-
<Loader source={getLoaderGif(state.animationState, state.currentStep)} />
|
|
323
|
+
{state.isLoading && getLoaderGif(state.animationState, state.currentStep, apiurl) && (
|
|
324
|
+
<Loader source={getLoaderGif(state.animationState, state.currentStep, apiurl)} />
|
|
290
325
|
)}
|
|
291
326
|
</View>
|
|
292
327
|
</Modal>
|
package/src/utils/constants.js
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
import { Global } from "./Global";
|
|
2
|
-
|
|
3
|
-
// ====== BASE CONFIG ======
|
|
4
|
-
export const BASE_URL = Global.ipAddress;
|
|
5
|
-
export const PORT = Global.port;
|
|
6
|
-
export const APIURL = `http://${BASE_URL}:${PORT}/`;
|
|
7
|
-
|
|
8
|
-
// ====== API ENDPOINTS ======
|
|
9
|
-
export const RECOGNIZE_URL = APIURL + "python/recognize";
|
|
10
|
-
export const IMAGE_URL = APIURL + "file/filedownload/photo/";
|
|
11
|
-
export const GIF_URL = APIURL + "file/getCommonFile/image/";
|
|
12
|
-
|
|
13
1
|
|
|
14
2
|
// ====== COLORS ======
|
|
15
3
|
export const COLORS = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ANIMATION_STATES
|
|
1
|
+
import { ANIMATION_STATES} from '../utils/constants';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Decides which GIF should be shown based on animationState or currentStep
|
|
@@ -6,11 +6,11 @@ import { ANIMATION_STATES, GIF_URL } from '../utils/constants';
|
|
|
6
6
|
* @param {string} currentStep - Current step of verification
|
|
7
7
|
* @returns {any} - Gif image source or null
|
|
8
8
|
*/
|
|
9
|
-
export const getLoaderGif = (animationState, currentStep) => {
|
|
9
|
+
export const getLoaderGif = (animationState, currentStep,APIURL) => {
|
|
10
10
|
const FaceGifUrl =
|
|
11
|
-
`${
|
|
11
|
+
`${APIURL}file/getCommonFile/image/Face.gif`;
|
|
12
12
|
const LocationGifUrl =
|
|
13
|
-
`${
|
|
13
|
+
`${APIURL}file/getCommonFile/image/Location.gif`;
|
|
14
14
|
|
|
15
15
|
if (
|
|
16
16
|
animationState === ANIMATION_STATES.FACE_SCAN ||
|