react-native-biometric-verifier 0.0.18 → 0.0.19

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-biometric-verifier",
3
- "version": "0.0.18",
3
+ "version": "0.0.19",
4
4
  "description": "A React Native module for biometric verification with face recognition and QR code scanning",
5
5
  "main": "src/index.js",
6
6
  "scripts": {
@@ -18,7 +18,7 @@ import {
18
18
  useCameraFormat,
19
19
  CameraRuntimeError,
20
20
  } from 'react-native-vision-camera';
21
- import { COLORS } from "../utils/constants";
21
+ import { Global } from '../utils/Global';
22
22
  import { useFaceDetectionFrameProcessor } from '../hooks/useFaceDetectionFrameProcessor';
23
23
 
24
24
  const CaptureImageWithoutEdit = React.memo(
@@ -389,7 +389,7 @@ const CaptureImageWithoutEdit = React.memo(
389
389
  <View style={styles.cameraContainer}>
390
390
  {cameraError ? (
391
391
  <View style={styles.errorContainer}>
392
- <Icon name="error-outline" size={40} color={COLORS.error} />
392
+ <Icon name="error-outline" size={40} color={Global.AppTheme.error} />
393
393
  <Text style={styles.errorText}>{cameraError}</Text>
394
394
  <TouchableOpacity
395
395
  style={styles.retryButton}
@@ -401,7 +401,7 @@ const CaptureImageWithoutEdit = React.memo(
401
401
  </View>
402
402
  ) : cameraPermission === 'denied' || cameraPermission === 'restricted' ? (
403
403
  <View style={styles.placeholderContainer}>
404
- <Icon name="camera-off" size={40} color={COLORS.light} />
404
+ <Icon name="camera-off" size={40} color={Global.AppTheme.light} />
405
405
  <Text style={styles.placeholderText}>
406
406
  Camera permission required. Please enable in settings.
407
407
  </Text>
@@ -415,14 +415,14 @@ const CaptureImageWithoutEdit = React.memo(
415
415
  </View>
416
416
  ) : cameraPermission === 'not-determined' ? (
417
417
  <View style={styles.placeholderContainer}>
418
- <ActivityIndicator size="large" color={COLORS.primary} />
418
+ <ActivityIndicator size="large" color={Global.AppTheme.primary} />
419
419
  <Text style={styles.placeholderText}>
420
420
  Requesting camera access...
421
421
  </Text>
422
422
  </View>
423
423
  ) : !cameraDevice ? (
424
424
  <View style={styles.placeholderContainer}>
425
- <Icon name="camera-alt" size={40} color={COLORS.light} />
425
+ <Icon name="camera-alt" size={40} color={Global.AppTheme.light} />
426
426
  <Text style={styles.placeholderText}>Camera not available</Text>
427
427
  <TouchableOpacity
428
428
  style={styles.retryButton}
@@ -434,7 +434,7 @@ const CaptureImageWithoutEdit = React.memo(
434
434
  </View>
435
435
  ) : (
436
436
  <View style={styles.placeholderContainer}>
437
- <ActivityIndicator size="large" color={COLORS.primary} />
437
+ <ActivityIndicator size="large" color={Global.AppTheme.primary} />
438
438
  <Text style={styles.placeholderText}>Initializing camera...</Text>
439
439
  </View>
440
440
  )}
@@ -545,7 +545,7 @@ const CaptureImageWithoutEdit = React.memo(
545
545
  disabled={isLoading || captured.current || livenessStep > 0}
546
546
  accessibilityLabel="Flip camera"
547
547
  >
548
- <Icon name="flip-camera-ios" size={28} color={COLORS.light} />
548
+ <Icon name="flip-camera-ios" size={28} color={Global.AppTheme.light} />
549
549
  </TouchableOpacity>
550
550
  )}
551
551
  </View>
@@ -562,7 +562,7 @@ const styles = StyleSheet.create({
562
562
  width: '100%',
563
563
  borderRadius: 12,
564
564
  overflow: 'hidden',
565
- backgroundColor: COLORS.dark,
565
+ backgroundColor: Global.AppTheme.dark,
566
566
  minHeight: 300,
567
567
  },
568
568
  camera: {
@@ -582,24 +582,24 @@ const styles = StyleSheet.create({
582
582
  padding: 20,
583
583
  },
584
584
  errorText: {
585
- color: COLORS.error,
585
+ color: Global.AppTheme.error,
586
586
  fontSize: 16,
587
587
  textAlign: 'center',
588
588
  marginVertical: 16,
589
589
  },
590
590
  retryButton: {
591
- backgroundColor: COLORS.primary,
591
+ backgroundColor: Global.AppTheme.primary,
592
592
  paddingHorizontal: 20,
593
593
  paddingVertical: 10,
594
594
  borderRadius: 8,
595
595
  marginTop: 10,
596
596
  },
597
597
  retryButtonText: {
598
- color: COLORS.light,
598
+ color: Global.AppTheme.light,
599
599
  fontWeight: 'bold',
600
600
  },
601
601
  placeholderText: {
602
- color: COLORS.light,
602
+ color: Global.AppTheme.light,
603
603
  fontSize: 16,
604
604
  textAlign: 'center',
605
605
  marginTop: 16,
@@ -689,12 +689,12 @@ const styles = StyleSheet.create({
689
689
  borderWidth: 2,
690
690
  },
691
691
  stepCompleted: {
692
- backgroundColor: COLORS.primary,
693
- borderColor: COLORS.primary,
692
+ backgroundColor: Global.AppTheme.primary,
693
+ borderColor: Global.AppTheme.primary,
694
694
  },
695
695
  stepCurrent: {
696
- backgroundColor: COLORS.primary,
697
- borderColor: COLORS.primary,
696
+ backgroundColor: Global.AppTheme.primary,
697
+ borderColor: Global.AppTheme.primary,
698
698
  opacity: 0.7,
699
699
  },
700
700
  stepPending: {
@@ -713,7 +713,7 @@ const styles = StyleSheet.create({
713
713
  marginHorizontal: 4,
714
714
  },
715
715
  connectorCompleted: {
716
- backgroundColor: COLORS.primary,
716
+ backgroundColor: Global.AppTheme.primary,
717
717
  },
718
718
  stepLabelsContainer: {
719
719
  flexDirection: 'row',
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
2
2
  import { View, Text, Image, StyleSheet, Platform } from 'react-native';
3
3
  import Icon from 'react-native-vector-icons/MaterialIcons';
4
4
  import PropTypes from 'prop-types';
5
- import { COLORS } from '../utils/constants';
5
+ import { Global } from '../utils/Global';
6
6
 
7
7
  export const Card = ({ employeeData, apiurl }) => {
8
8
  const [imageError, setImageError] = useState(false);
@@ -44,7 +44,7 @@ export const Card = ({ employeeData, apiurl }) => {
44
44
  {/* Verified Badge */}
45
45
  <View style={styles.badgeWrapper}>
46
46
  <View style={styles.badge}>
47
- <Icon name="verified-user" size={16} color={COLORS.success} />
47
+ <Icon name="verified-user" size={16} color={Global.AppTheme.success} />
48
48
  <Text style={styles.badgeText}>Identity Verified</Text>
49
49
  </View>
50
50
  </View>
@@ -82,7 +82,7 @@ const styles = StyleSheet.create({
82
82
  height: 110,
83
83
  borderRadius: 55,
84
84
  borderWidth: 3,
85
- borderColor: COLORS.primary,
85
+ borderColor: Global.AppTheme.primary,
86
86
  overflow: 'hidden',
87
87
  justifyContent: 'center',
88
88
  alignItems: 'center',
@@ -100,12 +100,12 @@ const styles = StyleSheet.create({
100
100
  fontSize: 20,
101
101
  fontWeight: '600',
102
102
  marginTop: 15,
103
- color: COLORS.light,
103
+ color: Global.AppTheme.light,
104
104
  fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif-medium',
105
105
  },
106
106
  id: {
107
107
  fontSize: 15,
108
- color: COLORS.gray,
108
+ color: Global.AppTheme.gray,
109
109
  marginTop: 5,
110
110
  fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
111
111
  },
@@ -127,7 +127,7 @@ const styles = StyleSheet.create({
127
127
  },
128
128
  badgeText: {
129
129
  fontSize: 13,
130
- color: COLORS.light,
130
+ color: Global.AppTheme.light,
131
131
  marginLeft: 6,
132
132
  fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
133
133
  },
@@ -1,6 +1,6 @@
1
1
  import React, { useEffect, useRef } from 'react';
2
2
  import { View, Text, Animated, StyleSheet, Platform } from 'react-native';
3
- import { COLORS } from '../utils/constants';
3
+ import { Global } from '../utils/Global';
4
4
 
5
5
  export const CountdownTimer = ({ duration, currentTime }) => {
6
6
  const progress = useRef(new Animated.Value(1)).current;
@@ -45,8 +45,8 @@ export const CountdownTimer = ({ duration, currentTime }) => {
45
45
 
46
46
  // Change color when < 10 seconds
47
47
  const isEnding = currentTime <= 10;
48
- const circleColor = isEnding ? 'red' : COLORS.light;
49
- const textColor = isEnding ? 'red' : COLORS.light;
48
+ const circleColor = isEnding ? 'red' : Global.AppTheme.light;
49
+ const textColor = isEnding ? 'red' : Global.AppTheme.light;
50
50
 
51
51
  return (
52
52
  <View style={styles.container}>
@@ -2,7 +2,7 @@ import React, { useEffect, useRef } from 'react';
2
2
  import { Animated, Text, Platform, StyleSheet } from 'react-native';
3
3
  import Icon from 'react-native-vector-icons/MaterialIcons';
4
4
  import PropTypes from 'prop-types';
5
- import { COLORS } from '../utils/constants';
5
+ import { Global } from '../utils/Global';
6
6
 
7
7
  export const Notification = ({ notification, fadeAnim, slideAnim }) => {
8
8
  if (!notification || typeof notification !== 'object') {
@@ -15,9 +15,9 @@ export const Notification = ({ notification, fadeAnim, slideAnim }) => {
15
15
 
16
16
  // Icon and color mapping
17
17
  const iconMap = {
18
- success: { name: 'check-circle', color: COLORS.success },
19
- error: { name: 'error', color: COLORS.error },
20
- info: { name: 'info', color: COLORS.info },
18
+ success: { name: 'check-circle', color: Global.AppTheme.success },
19
+ error: { name: 'error', color: Global.AppTheme.error },
20
+ info: { name: 'info', color: Global.AppTheme.info },
21
21
  };
22
22
 
23
23
  const { name: iconName, color: iconColor } = iconMap[type] || iconMap.info;
@@ -123,7 +123,7 @@ const styles = StyleSheet.create({
123
123
  width: '100%',
124
124
  flexDirection: 'row',
125
125
  alignItems: 'center',
126
- backgroundColor: COLORS.dark,
126
+ backgroundColor: Global.AppTheme.dark,
127
127
  shadowColor: '#000',
128
128
  shadowOffset: { width: 0, height: 2 },
129
129
  shadowOpacity: 0.1,
@@ -135,7 +135,7 @@ const styles = StyleSheet.create({
135
135
  },
136
136
  message: {
137
137
  fontSize: 14,
138
- color: COLORS.light,
138
+ color: Global.AppTheme.light,
139
139
  fontWeight: '500',
140
140
  flex: 1,
141
141
  fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
@@ -2,7 +2,7 @@
2
2
  import React from 'react';
3
3
  import { View, Text, StyleSheet } from 'react-native';
4
4
  import Icon from 'react-native-vector-icons/MaterialIcons';
5
- import { COLORS } from '../utils/constants';
5
+ import { Global } from '../utils/Global';
6
6
 
7
7
  const StepIndicator = ({ currentStep, qrscan }) => {
8
8
  return (
@@ -16,8 +16,8 @@ const StepIndicator = ({ currentStep, qrscan }) => {
16
16
  currentStep === "Identity Verification" ||
17
17
  currentStep === "Location Verification" ||
18
18
  currentStep === "Complete"
19
- ? COLORS.primary
20
- : COLORS.light
19
+ ? Global.AppTheme.primary
20
+ : Global.AppTheme.light
21
21
  }
22
22
  style={styles.statusIcon}
23
23
  />
@@ -44,8 +44,8 @@ const StepIndicator = ({ currentStep, qrscan }) => {
44
44
  color={
45
45
  currentStep === "Location Verification" ||
46
46
  currentStep === "Complete"
47
- ? COLORS.primary
48
- : COLORS.light
47
+ ? Global.AppTheme.primary
48
+ : Global.AppTheme.light
49
49
  }
50
50
  style={styles.statusIcon}
51
51
  />
@@ -81,7 +81,7 @@ const styles = StyleSheet.create({
81
81
  },
82
82
  statusText: {
83
83
  fontSize: 12,
84
- color: COLORS.light,
84
+ color: Global.AppTheme.light,
85
85
  opacity: 0.6,
86
86
  },
87
87
  statusTextActive: {
@@ -91,7 +91,7 @@ const styles = StyleSheet.create({
91
91
  statusSeparator: {
92
92
  width: 40,
93
93
  height: 1,
94
- backgroundColor: COLORS.light,
94
+ backgroundColor: Global.AppTheme.light,
95
95
  opacity: 0.3,
96
96
  marginHorizontal: 15,
97
97
  },
@@ -1,5 +1,5 @@
1
1
  import { useRef, useState, useEffect, useCallback } from 'react';
2
- import { COUNTDOWN_DURATION } from '../utils/constants';
2
+ import { Global } from '../utils/Global';
3
3
 
4
4
  /**
5
5
  * Custom hook for a countdown timer with pause/resume functionality.
@@ -8,9 +8,9 @@ import { COUNTDOWN_DURATION } from '../utils/constants';
8
8
  * @returns {Object} countdown, startCountdown, resetCountdown, pauseCountdown, resumeCountdown
9
9
  */
10
10
  export const useCountdown = (onExpire) => {
11
- const [countdown, setCountdown] = useState(COUNTDOWN_DURATION);
11
+ const [countdown, setCountdown] = useState(Global.CountdownDuration);
12
12
  const timerRef = useRef(null);
13
- const countdownRef = useRef(COUNTDOWN_DURATION);
13
+ const countdownRef = useRef(Global.CountdownDuration);
14
14
  const isPausedRef = useRef(false);
15
15
  const onExpireRef = useRef(onExpire);
16
16
 
@@ -23,8 +23,8 @@ export const useCountdown = (onExpire) => {
23
23
  const startCountdown = useCallback((onExpireCallback) => {
24
24
  try {
25
25
  // Reset countdown
26
- countdownRef.current = COUNTDOWN_DURATION;
27
- setCountdown(COUNTDOWN_DURATION);
26
+ countdownRef.current = Global.CountdownDuration;
27
+ setCountdown(Global.CountdownDuration);
28
28
  isPausedRef.current = false;
29
29
 
30
30
  // Clear any existing timer
@@ -77,8 +77,8 @@ export const useCountdown = (onExpire) => {
77
77
  // Reset countdown to initial duration
78
78
  const resetCountdown = useCallback(() => {
79
79
  try {
80
- countdownRef.current = COUNTDOWN_DURATION;
81
- setCountdown(COUNTDOWN_DURATION);
80
+ countdownRef.current = Global.CountdownDuration;
81
+ setCountdown(Global.CountdownDuration);
82
82
  isPausedRef.current = false;
83
83
 
84
84
  if (timerRef.current) {
@@ -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
 
@@ -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,7 +521,7 @@ 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]);
@@ -571,8 +565,8 @@ const BiometricModal = React.memo(
571
565
  const shouldShowCamera =
572
566
  (state.currentStep === "Identity Verification" ||
573
567
  state.currentStep === "Location Verification") &&
574
- state.animationState !== ANIMATION_STATES.SUCCESS &&
575
- state.animationState !== ANIMATION_STATES.ERROR;
568
+ state.animationState !== Global.AnimationStates.success &&
569
+ state.animationState !== Global.AnimationStates.error;
576
570
 
577
571
  return (
578
572
  <Modal
@@ -605,7 +599,7 @@ const BiometricModal = React.memo(
605
599
  accessibilityLabel="Close modal"
606
600
  hitSlop={{ top: 20, bottom: 20, left: 20, right: 20 }}
607
601
  >
608
- <Icon name="close" size={24} color={COLORS.light} />
602
+ <Icon name="close" size={24} color={Global.AppTheme.light} />
609
603
  </TouchableOpacity>
610
604
 
611
605
  <View style={styles.topContainer}>
@@ -639,7 +633,7 @@ const BiometricModal = React.memo(
639
633
 
640
634
  <View style={styles.timerContainer}>
641
635
  <CountdownTimer
642
- duration={COUNTDOWN_DURATION}
636
+ duration={Global.CountdownDuration}
643
637
  currentTime={countdown}
644
638
  />
645
639
  </View>
@@ -657,7 +651,7 @@ const BiometricModal = React.memo(
657
651
  const styles = StyleSheet.create({
658
652
  modalContainer: {
659
653
  flex: 1,
660
- backgroundColor: COLORS.modalBackground || 'rgba(0, 0, 0, 0.85)',
654
+ backgroundColor: Global.AppTheme.modalBackground || 'rgba(0, 0, 0, 0.85)',
661
655
  },
662
656
  cameraContainer: {
663
657
  position: 'absolute',
@@ -694,7 +688,7 @@ const styles = StyleSheet.create({
694
688
  title: {
695
689
  fontSize: 26,
696
690
  fontWeight: '700',
697
- color: COLORS.textLight || COLORS.light,
691
+ color: Global.AppTheme.textLight || Global.AppTheme.light,
698
692
  marginBottom: 5,
699
693
  textAlign: 'left',
700
694
  fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
@@ -704,7 +698,7 @@ const styles = StyleSheet.create({
704
698
  },
705
699
  subtitle: {
706
700
  fontSize: 18,
707
- color: COLORS.textLight || COLORS.light,
701
+ color: Global.AppTheme.textLight || Global.AppTheme.light,
708
702
  marginBottom: 0,
709
703
  fontWeight: '600',
710
704
  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
- };