react-native-biometric-verifier 0.0.18 → 0.0.20

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.
@@ -1,7 +1,7 @@
1
1
  import { useCallback } from 'react';
2
2
  import ImageResizer from 'react-native-image-resizer';
3
3
  import RNFS from 'react-native-fs';
4
- import { IMAGE_RESIZE } from '../utils/constants';
4
+ import { Global } from '../utils/Global';
5
5
 
6
6
  /**
7
7
  * Custom hook to process images: resize and convert to Base64.
@@ -38,10 +38,10 @@ export const useImageProcessing = () => {
38
38
  try {
39
39
  resizedImage = await ImageResizer.createResizedImage(
40
40
  uri,
41
- IMAGE_RESIZE.width,
42
- IMAGE_RESIZE.height,
43
- IMAGE_RESIZE.format, // 'JPEG' or 'PNG'
44
- IMAGE_RESIZE.quality, // e.g., 80
41
+ Global.ImageResize.width,
42
+ Global.ImageResize.height,
43
+ Global.ImageResize.format, // 'JPEG' or 'PNG'
44
+ Global.ImageResize.quality, // e.g., 80
45
45
  0, // Rotation
46
46
  undefined, // Output path (let library choose)
47
47
  false // Keep EXIF metadata
@@ -64,7 +64,7 @@ export const useImageProcessing = () => {
64
64
 
65
65
  // Optionally prepend MIME type
66
66
  if (includeMimeType) {
67
- const mimeType = IMAGE_RESIZE.format.toLowerCase() === 'png' ? 'image/png' : 'image/jpeg';
67
+ const mimeType = Global.ImageResize.format.toLowerCase() === 'png' ? 'image/png' : 'image/jpeg';
68
68
  base64Data = `data:${mimeType};base64,${base64Data}`;
69
69
  }
70
70
 
@@ -7,7 +7,7 @@ import {
7
7
  ToastAndroid,
8
8
  Alert,
9
9
  } from 'react-native';
10
- import { COLORS } from '../utils/constants';
10
+ import { Global } from '../utils/Global';
11
11
 
12
12
  export const useNotifyMessage = () => {
13
13
  const [notification, setNotification] = useState({
@@ -22,9 +22,9 @@ export const useNotifyMessage = () => {
22
22
 
23
23
  // Styles for notification container based on type
24
24
  const getNotificationStyle = useCallback((type) => {
25
- let backgroundColor = COLORS.info;
26
- if (type === 'success') backgroundColor = COLORS.success;
27
- if (type === 'error') backgroundColor = COLORS.error;
25
+ let backgroundColor = Global.AppTheme.info;
26
+ if (type === 'success') backgroundColor = Global.AppTheme.success;
27
+ if (type === 'error') backgroundColor = Global.AppTheme.error;
28
28
 
29
29
  return {
30
30
  position: 'absolute',
package/src/index.js CHANGED
@@ -27,13 +27,7 @@ import { useSafeCallback } from "./hooks/useSafeCallback";
27
27
 
28
28
  // Utils
29
29
  import { getDistanceInMeters } from "./utils/distanceCalculator";
30
- import {
31
- ANIMATION_STATES,
32
- COLORS,
33
- COUNTDOWN_DURATION,
34
- MAX_DISTANCE_METERS,
35
- LOADING_TYPES,
36
- } from "./utils/constants";
30
+ import { Global } from "./utils/Global";
37
31
  import networkServiceCall from "./utils/NetworkServiceCall";
38
32
  import { getLoaderGif } from "./utils/getLoaderGif";
39
33
 
@@ -46,7 +40,7 @@ import CaptureImageWithoutEdit from "./components/CaptureImageWithoutEdit";
46
40
  import StepIndicator from "./components/StepIndicator";
47
41
 
48
42
  const BiometricModal = React.memo(
49
- ({ data, qrscan = false, callback, apiurl, onclose, frameProcessorFps }) => {
43
+ ({ data, qrscan = false, callback, apiurl, onclose, frameProcessorFps, livenessLevel }) => {
50
44
  const navigation = useNavigation();
51
45
 
52
46
  // Custom hooks
@@ -61,10 +55,10 @@ const BiometricModal = React.memo(
61
55
  const [cameraType, setCameraType] = useState("front");
62
56
  const [state, setState] = useState({
63
57
  isLoading: false,
64
- loadingType: LOADING_TYPES.NONE,
58
+ loadingType: Global.LoadingTypes.none,
65
59
  currentStep: "Start",
66
60
  employeeData: null,
67
- animationState: ANIMATION_STATES.FACE_SCAN,
61
+ animationState: Global.AnimationStates.faceScan,
68
62
  });
69
63
 
70
64
  // Refs
@@ -174,10 +168,10 @@ const BiometricModal = React.memo(
174
168
 
175
169
  setState({
176
170
  isLoading: false,
177
- loadingType: LOADING_TYPES.NONE,
171
+ loadingType: Global.LoadingTypes.none,
178
172
  currentStep: "Start",
179
173
  employeeData: null,
180
- animationState: ANIMATION_STATES.FACE_SCAN,
174
+ animationState: Global.AnimationStates.faceScan,
181
175
  });
182
176
 
183
177
  setModalVisible(false);
@@ -200,9 +194,9 @@ const BiometricModal = React.memo(
200
194
 
201
195
  notifyMessage(message, "error");
202
196
  updateState({
203
- animationState: ANIMATION_STATES.ERROR,
197
+ animationState: Global.AnimationStates.error,
204
198
  isLoading: false,
205
- loadingType: LOADING_TYPES.NONE,
199
+ loadingType: Global.LoadingTypes.none,
206
200
  });
207
201
 
208
202
  if (resetTimeoutRef.current) {
@@ -256,8 +250,8 @@ const BiometricModal = React.memo(
256
250
 
257
251
  updateState({
258
252
  isLoading: true,
259
- loadingType: LOADING_TYPES.FACE_RECOGNITION,
260
- animationState: ANIMATION_STATES.PROCESSING,
253
+ loadingType: Global.LoadingTypes.faceRecognition,
254
+ animationState: Global.AnimationStates.processing,
261
255
  });
262
256
 
263
257
  InteractionManager.runAfterInteractions(async () => {
@@ -266,7 +260,7 @@ const BiometricModal = React.memo(
266
260
  try {
267
261
  console.log("🖼️ Converting image to base64");
268
262
  updateState({
269
- loadingType: LOADING_TYPES.IMAGE_PROCESSING,
263
+ loadingType: Global.LoadingTypes.imageProcessing,
270
264
  });
271
265
 
272
266
  base64 = await convertImageToBase64(selfie?.uri);
@@ -290,7 +284,7 @@ const BiometricModal = React.memo(
290
284
  console.log("🌐 Calling face recognition API:", buttonapi);
291
285
 
292
286
  updateState({
293
- loadingType: LOADING_TYPES.NETWORK_REQUEST,
287
+ loadingType: Global.LoadingTypes.networkRequest,
294
288
  });
295
289
 
296
290
  const response = await networkServiceCall(
@@ -308,9 +302,9 @@ const BiometricModal = React.memo(
308
302
 
309
303
  updateState({
310
304
  employeeData: response.data?.data || null,
311
- animationState: ANIMATION_STATES.SUCCESS,
305
+ animationState: Global.AnimationStates.success,
312
306
  isLoading: false,
313
- loadingType: LOADING_TYPES.NONE,
307
+ loadingType: Global.LoadingTypes.none,
314
308
  });
315
309
 
316
310
  notifyMessage("Identity verified successfully!", "success");
@@ -367,15 +361,15 @@ const BiometricModal = React.memo(
367
361
  if (!validateApiUrl()) return;
368
362
 
369
363
  updateState({
370
- animationState: ANIMATION_STATES.PROCESSING,
364
+ animationState: Global.AnimationStates.processing,
371
365
  isLoading: true,
372
- loadingType: LOADING_TYPES.LOCATION_VERIFICATION,
366
+ loadingType: Global.LoadingTypes.locationVerification,
373
367
  });
374
368
 
375
369
  try {
376
370
  console.log("📍 Requesting location permission");
377
371
  updateState({
378
- loadingType: LOADING_TYPES.LOCATION_PERMISSION,
372
+ loadingType: Global.LoadingTypes.locationPermission,
379
373
  });
380
374
 
381
375
  const hasPermission = await requestLocationPermission();
@@ -400,7 +394,7 @@ const BiometricModal = React.memo(
400
394
  console.log("📋 QR code content:", qrString);
401
395
 
402
396
  updateState({
403
- loadingType: LOADING_TYPES.GETTING_LOCATION,
397
+ loadingType: Global.LoadingTypes.gettingLocation,
404
398
  });
405
399
 
406
400
  const location = await getCurrentLocation();
@@ -422,7 +416,7 @@ const BiometricModal = React.memo(
422
416
 
423
417
  if (validCoords && validDev) {
424
418
  updateState({
425
- loadingType: LOADING_TYPES.CALCULATING_DISTANCE,
419
+ loadingType: Global.LoadingTypes.calculateDistance,
426
420
  });
427
421
 
428
422
  const distance = getDistanceInMeters(
@@ -438,15 +432,15 @@ const BiometricModal = React.memo(
438
432
  "meters"
439
433
  );
440
434
 
441
- if (distance <= MAX_DISTANCE_METERS) {
435
+ if (distance <= Global.MaxDistanceMeters) {
442
436
  console.log("✅ Location verified successfully");
443
437
  safeCallback(responseRef.current);
444
438
  notifyMessage("Location verified successfully!", "success");
445
439
 
446
440
  updateState({
447
- animationState: ANIMATION_STATES.SUCCESS,
441
+ animationState: Global.AnimationStates.success,
448
442
  isLoading: false,
449
- loadingType: LOADING_TYPES.NONE,
443
+ loadingType: Global.LoadingTypes.none,
450
444
  });
451
445
 
452
446
  if (resetTimeoutRef.current) {
@@ -517,7 +511,7 @@ const BiometricModal = React.memo(
517
511
  console.log("👤 Starting face scan");
518
512
  updateState({
519
513
  currentStep: "Identity Verification",
520
- animationState: ANIMATION_STATES.FACE_SCAN,
514
+ animationState: Global.AnimationStates.faceScan,
521
515
  });
522
516
  setCameraType("front");
523
517
  }, [updateState]);
@@ -527,21 +521,11 @@ const BiometricModal = React.memo(
527
521
  console.log("📍 Starting QR code scan");
528
522
  updateState({
529
523
  currentStep: "Location Verification",
530
- animationState: ANIMATION_STATES.QR_SCAN,
524
+ animationState: Global.AnimationStates.qrScan,
531
525
  });
532
526
  setCameraType("back");
533
527
  }, [updateState]);
534
528
 
535
- // Toggle camera
536
- const toggleCamera = useCallback(() => {
537
- console.log("🔄 Toggling camera");
538
- setCameraType((prevType) => {
539
- const newType = prevType === "front" ? "back" : "front";
540
- console.log("📷 Switching to camera:", newType);
541
- return newType;
542
- });
543
- }, []);
544
-
545
529
  // Start the verification process
546
530
  const startProcess = useCallback(() => {
547
531
  console.log("🚀 Starting verification process");
@@ -571,8 +555,8 @@ const BiometricModal = React.memo(
571
555
  const shouldShowCamera =
572
556
  (state.currentStep === "Identity Verification" ||
573
557
  state.currentStep === "Location Verification") &&
574
- state.animationState !== ANIMATION_STATES.SUCCESS &&
575
- state.animationState !== ANIMATION_STATES.ERROR;
558
+ state.animationState !== Global.AnimationStates.success &&
559
+ state.animationState !== Global.AnimationStates.error;
576
560
 
577
561
  return (
578
562
  <Modal
@@ -589,11 +573,10 @@ const BiometricModal = React.memo(
589
573
  <CaptureImageWithoutEdit
590
574
  cameraType={cameraType}
591
575
  onCapture={handleImageCapture}
592
- onToggleCamera={toggleCamera}
593
576
  showCodeScanner={state.currentStep === "Location Verification"}
594
577
  isLoading={state.isLoading}
595
- currentStep={state.currentStep}
596
578
  frameProcessorFps={frameProcessorFps}
579
+ livenessLevel={livenessLevel}
597
580
  />
598
581
  </View>
599
582
  )}
@@ -605,7 +588,7 @@ const BiometricModal = React.memo(
605
588
  accessibilityLabel="Close modal"
606
589
  hitSlop={{ top: 20, bottom: 20, left: 20, right: 20 }}
607
590
  >
608
- <Icon name="close" size={24} color={COLORS.light} />
591
+ <Icon name="close" size={24} color={Global.AppTheme.light} />
609
592
  </TouchableOpacity>
610
593
 
611
594
  <View style={styles.topContainer}>
@@ -639,7 +622,7 @@ const BiometricModal = React.memo(
639
622
 
640
623
  <View style={styles.timerContainer}>
641
624
  <CountdownTimer
642
- duration={COUNTDOWN_DURATION}
625
+ duration={Global.CountdownDuration}
643
626
  currentTime={countdown}
644
627
  />
645
628
  </View>
@@ -657,7 +640,7 @@ const BiometricModal = React.memo(
657
640
  const styles = StyleSheet.create({
658
641
  modalContainer: {
659
642
  flex: 1,
660
- backgroundColor: COLORS.modalBackground || 'rgba(0, 0, 0, 0.85)',
643
+ backgroundColor: Global.AppTheme.modalBackground || 'rgba(0, 0, 0, 0.85)',
661
644
  },
662
645
  cameraContainer: {
663
646
  position: 'absolute',
@@ -694,7 +677,7 @@ const styles = StyleSheet.create({
694
677
  title: {
695
678
  fontSize: 26,
696
679
  fontWeight: '700',
697
- color: COLORS.textLight || COLORS.light,
680
+ color: Global.AppTheme.textLight || Global.AppTheme.light,
698
681
  marginBottom: 5,
699
682
  textAlign: 'left',
700
683
  fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
@@ -704,7 +687,7 @@ const styles = StyleSheet.create({
704
687
  },
705
688
  subtitle: {
706
689
  fontSize: 18,
707
- color: COLORS.textLight || COLORS.light,
690
+ color: Global.AppTheme.textLight || Global.AppTheme.light,
708
691
  marginBottom: 0,
709
692
  fontWeight: '600',
710
693
  textAlign: 'left',
@@ -0,0 +1,48 @@
1
+ export class Global {
2
+ // ====== APP CONSTANTS ======
3
+ static AppTheme = {
4
+ primary: '#6C63FF',
5
+ primaryLight: '#8A85FF',
6
+ success: '#4CAF50',
7
+ error: '#F44336',
8
+ warning: '#FF9800',
9
+ info: '#2196F3',
10
+ dark: '#2D3748',
11
+ light: '#F7FAFC',
12
+ gray: '#A0AEC0',
13
+ background: '#F8F9FA',
14
+ cardBackground: '#FFFFFF',
15
+ textLight: '#FFFFFF',
16
+ shadow: '#00000033', // semi-transparent shadow
17
+ modalBackground: 'rgba(0, 0, 0, 0.85)',
18
+ };
19
+
20
+ static LoadingTypes = {
21
+ none: 'none',
22
+ imageProcessing: 'imageProcessing',
23
+ faceRecognition: 'faceRecognition',
24
+ networkRequest: 'networkRequest',
25
+ locationPermission: 'locationPermission',
26
+ gettingLocation: 'gettingLocation',
27
+ calculateDistance: 'calculateDistance',
28
+ locationVerification: 'locationVerification',
29
+ };
30
+
31
+ static AnimationStates = {
32
+ faceScan: 'faceScan',
33
+ qrScan: 'qrScan',
34
+ processing: 'processing',
35
+ success: 'success',
36
+ error: 'error',
37
+ };
38
+
39
+ static ImageResize = {
40
+ width: 640,
41
+ height: 640,
42
+ format: 'JPEG', // 'PNG' or 'JPEG'
43
+ quality: 85, // 0–100
44
+ };
45
+
46
+ static CountdownDuration = 100; // seconds
47
+ static MaxDistanceMeters = 100; // Max allowed distance for QR verification
48
+ }
@@ -1,4 +1,4 @@
1
- import { ANIMATION_STATES} from '../utils/constants';
1
+ import { Global } from "./Global";
2
2
 
3
3
  /**
4
4
  * Decides which GIF should be shown based on animationState or currentStep
@@ -13,14 +13,14 @@ export const getLoaderGif = (animationState, currentStep,APIURL) => {
13
13
  `${APIURL}file/getCommonFile/image/Location.gif`;
14
14
 
15
15
  if (
16
- animationState === ANIMATION_STATES.FACE_SCAN ||
16
+ animationState === Global.AnimationStates.faceScan ||
17
17
  currentStep === 'Identity Verification'
18
18
  ) {
19
19
  return { uri: FaceGifUrl };
20
20
  }
21
21
 
22
22
  if (
23
- animationState === ANIMATION_STATES.QR_SCAN ||
23
+ animationState === Global.AnimationStates.qrScan ||
24
24
  currentStep === 'Location Verification'
25
25
  ) {
26
26
  return { uri: LocationGifUrl };
@@ -1,73 +0,0 @@
1
- // ====== COLORS ======
2
- export const COLORS = {
3
- primary: '#6C63FF',
4
- primaryLight: '#8A85FF',
5
- success: '#4CAF50',
6
- error: '#F44336',
7
- warning: '#FF9800',
8
- info: '#2196F3',
9
- dark: '#2D3748',
10
- light: '#F7FAFC',
11
- gray: '#A0AEC0',
12
- background: '#F8F9FA',
13
- cardBackground: '#FFFFFF',
14
- textLight: '#FFFFFF',
15
- shadow: '#00000033', // semi-transparent shadow
16
- modalBackground: 'rgba(0, 0, 0, 0.85)',
17
- };
18
-
19
- // ====== LOADING TYPES ======
20
- export const LOADING_TYPES = {
21
- NONE: 'NONE',
22
- CAMERA_INIT: 'CAMERA_INIT',
23
- CAPTURING_PHOTO: 'CAPTURING_PHOTO',
24
- IMAGE_PROCESSING: 'IMAGE_PROCESSING',
25
- FACE_RECOGNITION: 'FACE_RECOGNITION',
26
- NETWORK_REQUEST: 'NETWORK_REQUEST',
27
- LOCATION_PERMISSION: 'LOCATION_PERMISSION',
28
- GETTING_LOCATION: 'GETTING_LOCATION',
29
- CALCULATING_DISTANCE: 'CALCULATING_DISTANCE',
30
- LOCATION_VERIFICATION: 'LOCATION_VERIFICATION',
31
- };
32
-
33
- // ====== ANIMATION STATES ======
34
- export const ANIMATION_STATES = {
35
- FACE_SCAN: 'faceScan',
36
- QR_SCAN: 'qrScan',
37
- PROCESSING: 'processing',
38
- SUCCESS: 'success',
39
- ERROR: 'error',
40
- };
41
-
42
- // ====== IMAGE RESIZE CONFIG ======
43
- export const IMAGE_RESIZE = {
44
- width: 640,
45
- height: 640,
46
- format: 'JPEG', // 'PNG' or 'JPEG'
47
- quality: 85, // 0-100
48
- };
49
-
50
- // ====== CONSTANTS ======
51
- export const COUNTDOWN_DURATION = 100; // seconds
52
- export const MAX_DISTANCE_METERS = 100; // Max allowed distance for QR verification
53
-
54
- // ====== NOTIFICATION SETTINGS ======
55
- export const NOTIFICATION = {
56
- DEFAULT_DURATION: 3000, // ms
57
- FADE_DURATION: 300, // ms
58
- SLIDE_DISTANCE: 20, // px
59
- VIBRATION_DURATION: 100, // ms
60
- TOAST_OFFSET: 80, // Android Toast vertical offset
61
- };
62
-
63
- // ====== QR VERIFICATION SETTINGS ======
64
- export const QR_VERIFICATION = {
65
- MAX_ATTEMPTS: 3, // Maximum retries for QR scan
66
- TIMEOUT: 10000, // Timeout in ms per scan
67
- };
68
-
69
- // ====== PLATFORM ======
70
- export const PLATFORM = {
71
- IOS: 'ios',
72
- ANDROID: 'android',
73
- };