react-native-biometric-verifier 0.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.
Files changed (64) hide show
  1. package/README.md +20 -0
  2. package/package.json +32 -0
  3. package/src/Asset/Icons/Female.png +0 -0
  4. package/src/Asset/Icons/FemaleI(1).png +0 -0
  5. package/src/Asset/Icons/Male(2).png +0 -0
  6. package/src/Asset/Icons/arrowleft.png +0 -0
  7. package/src/Asset/Icons/barcode2.png +0 -0
  8. package/src/Asset/Icons/calendar.png +0 -0
  9. package/src/Asset/Icons/downarrow.png +0 -0
  10. package/src/Asset/Icons/male.png +0 -0
  11. package/src/Asset/Icons/stethoscope.jpg +0 -0
  12. package/src/Asset/Icons/user.png +0 -0
  13. package/src/Asset/Icons/youtube.png +0 -0
  14. package/src/Asset/gif/Pulse.gif +0 -0
  15. package/src/Asset/gif/Search_blue.gif +0 -0
  16. package/src/Asset/gif/hb.gif +0 -0
  17. package/src/Asset/gif/heartpulse.gif +0 -0
  18. package/src/Asset/gif/lab_1.gif +0 -0
  19. package/src/Asset/gif/loader.gif +0 -0
  20. package/src/Asset/gif/overwrite.gif +0 -0
  21. package/src/Asset/gif/pharmacist.gif +0 -0
  22. package/src/Asset/images/AdamsNeilson.jpg +0 -0
  23. package/src/Asset/images/AyurvedicHospital.jpg +0 -0
  24. package/src/Asset/images/DevamathaLogo.jpg +0 -0
  25. package/src/Asset/images/IMA.png +0 -0
  26. package/src/Asset/images/amalainstitute.png +0 -0
  27. package/src/Asset/images/amalainstituteN.png +0 -0
  28. package/src/Asset/images/amalainstituteX.png +0 -0
  29. package/src/Asset/images/amalalogo.jpg +0 -0
  30. package/src/Asset/images/amalalogoN.jpg +0 -0
  31. package/src/Asset/images/arrow-collapse.png +0 -0
  32. package/src/Asset/images/arrow-expand.png +0 -0
  33. package/src/Asset/images/audio.png +0 -0
  34. package/src/Asset/images/camera.png +0 -0
  35. package/src/Asset/images/camera_red.png +0 -0
  36. package/src/Asset/images/companyaddress_transparent.png +0 -0
  37. package/src/Asset/images/companyname_transparent.png +0 -0
  38. package/src/Asset/images/download.png +0 -0
  39. package/src/Asset/images/jes.png +0 -0
  40. package/src/Asset/images/lefteye.jpg +0 -0
  41. package/src/Asset/images/mundakayamlogo.png +0 -0
  42. package/src/Asset/images/nirmalanabh.jpeg +0 -0
  43. package/src/Asset/images/pregnantlady.png +0 -0
  44. package/src/Asset/images/prescriptioneye.png +0 -0
  45. package/src/Asset/images/rblogo.png +0 -0
  46. package/src/Asset/images/righteye.jpg +0 -0
  47. package/src/Asset/images/rtlogo.png +0 -0
  48. package/src/Asset/images/video_red.png +0 -0
  49. package/src/Asset/images/vimaljyothi.png +0 -0
  50. package/src/components/CountdownTimer.js +42 -0
  51. package/src/components/EmployeeCard.js +61 -0
  52. package/src/components/Notification.js +63 -0
  53. package/src/components/StateIndicator.js +112 -0
  54. package/src/components/styles.js +182 -0
  55. package/src/hooks/useCountdown.js +72 -0
  56. package/src/hooks/useGeolocation.js +72 -0
  57. package/src/hooks/useImageProcessing.js +79 -0
  58. package/src/hooks/useNotifyMessage.js +131 -0
  59. package/src/index.js +283 -0
  60. package/src/utils/Global.js +6 -0
  61. package/src/utils/NetworkServiceCall.js +35 -0
  62. package/src/utils/constants.js +69 -0
  63. package/src/utils/distanceCalculator.js +25 -0
  64. package/src/utils/logger.js +7 -0
package/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # React Native Biometric Verifier
2
+
3
+ A comprehensive biometric verification module for React Native that combines face recognition and QR code scanning with location verification.
4
+
5
+ ## Features
6
+
7
+ - Face recognition verification
8
+ - QR code scanning
9
+ - Location verification
10
+ - Animated UI with state indicators
11
+ - Countdown timer
12
+ - Customizable notification system
13
+ - Comprehensive error handling
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install react-native-biometric-verifier
19
+ # or
20
+ yarn add react-native-biometric-verifier
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "react-native-biometric-verifier",
3
+ "version": "0.0.1",
4
+ "description": "A React Native module for biometric verification with face recognition and QR code scanning",
5
+ "main": "src/index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [
10
+ "react-native",
11
+ "biometric",
12
+ "verification",
13
+ "face-recognition",
14
+ "qr-code"
15
+ ],
16
+ "author": "JESCON",
17
+ "license": "MIT",
18
+ "peerDependencies": {
19
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0",
20
+ "react-native": ">=0.60.0",
21
+ "react-native-vector-icons": "^9.0.0",
22
+ "react-native-geolocation-service": "^5.0.0",
23
+ "react-native-image-resizer": "^1.0.0",
24
+ "@react-navigation/native": "^6.0.0",
25
+ "prop-types": "^15.8.0",
26
+ "react-native-fs": "^2.20.0"
27
+ },
28
+ "devDependencies": {
29
+ "react": "^18.0.0",
30
+ "react-native": "^0.69.0"
31
+ }
32
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,42 @@
1
+ import React from 'react';
2
+ import { View, Text, Animated, StyleSheet } from 'react-native';
3
+ import { COLORS } from '../utils/constants';
4
+ import { styles } from './styles';
5
+
6
+ export const CountdownTimer = ({ duration, currentTime }) => {
7
+ const progress = React.useRef(new Animated.Value(1)).current;
8
+
9
+ React.useEffect(() => {
10
+ Animated.timing(progress, {
11
+ toValue: currentTime / duration,
12
+ duration: 1000,
13
+ useNativeDriver: false,
14
+ }).start();
15
+ }, [currentTime, duration, progress]);
16
+
17
+ const circumference = 2 * Math.PI * 40;
18
+ const strokeDashoffset = progress.interpolate({
19
+ inputRange: [0, 1],
20
+ outputRange: [circumference, 0],
21
+ });
22
+
23
+ return (
24
+ <View style={styles.timerContainer}>
25
+ <View style={styles.timerCircle}>
26
+ <Animated.View style={styles.timerProgressContainer}>
27
+ <Animated.View
28
+ style={[
29
+ styles.timerProgress,
30
+ {
31
+ strokeDashoffset,
32
+ transform: [{ rotate: '-90deg' }],
33
+ }
34
+ ]}
35
+ />
36
+ </Animated.View>
37
+ <Text style={styles.timerText}>{currentTime}s</Text>
38
+ </View>
39
+ <Text style={styles.timerLabel}>Remaining</Text>
40
+ </View>
41
+ );
42
+ };
@@ -0,0 +1,61 @@
1
+ import React, { useState } from 'react';
2
+ import { View, Text, Image } from 'react-native';
3
+ import Icon from 'react-native-vector-icons/MaterialIcons';
4
+ import PropTypes from 'prop-types';
5
+ import { COLORS ,IMAGE_URL} from '../utils/constants';
6
+ import { styles } from './styles';
7
+
8
+ export const EmployeeCard = ({ employeeData }) => {
9
+ const [imageError, setImageError] = useState(false);
10
+
11
+ if (!employeeData || typeof employeeData !== 'object') {
12
+ console.warn('EmployeeCard: Invalid or missing employeeData');
13
+ return null;
14
+ }
15
+
16
+ const { employeename, employeeid, imageurl } = employeeData;
17
+
18
+ const employeeName = employeename || 'Unknown Employee';
19
+ const employeeId = employeeid || 'N/A';
20
+ const imageSource = !imageError && imageurl
21
+ ? { uri: `${IMAGE_URL}${imageurl}` }
22
+ : require('../Asset/images/camera.png'); // Add a local fallback image in assets
23
+
24
+ return (
25
+ <View style={styles.employeeCard}>
26
+ {/* Employee Image */}
27
+ <View style={styles.employeeImageContainer}>
28
+ <Image
29
+ source={imageSource}
30
+ style={styles.employeeImage}
31
+ resizeMode="cover"
32
+ onError={() => {
33
+ console.error(`Error loading image for employee: ${employeeName}`);
34
+ setImageError(true);
35
+ }}
36
+ />
37
+ <View style={styles.employeeImageOverlay} />
38
+ </View>
39
+
40
+ {/* Employee Info */}
41
+ <Text style={styles.empName}>{employeeName}</Text>
42
+ <Text style={styles.empId}>Employee ID: {employeeId}</Text>
43
+
44
+ {/* Verified Badge */}
45
+ <View style={styles.employeeDetails}>
46
+ <View style={styles.detailItem}>
47
+ <Icon name="verified-user" size={16} color={COLORS.success} />
48
+ <Text style={styles.detailText}>Identity Verified</Text>
49
+ </View>
50
+ </View>
51
+ </View>
52
+ );
53
+ };
54
+
55
+ EmployeeCard.propTypes = {
56
+ employeeData: PropTypes.shape({
57
+ employeename: PropTypes.string,
58
+ employeeid: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
59
+ imageurl: PropTypes.string,
60
+ }),
61
+ };
@@ -0,0 +1,63 @@
1
+ import React from 'react';
2
+ import { Animated, Text } from 'react-native';
3
+ import Icon from 'react-native-vector-icons/MaterialIcons';
4
+ import PropTypes from 'prop-types';
5
+ import { COLORS } from '../utils/constants';
6
+ import { styles } from './styles';
7
+
8
+ export const Notification = ({ notification, fadeAnim, slideAnim }) => {
9
+ // Defensive check for null or malformed props
10
+ if (
11
+ !notification ||
12
+ typeof notification !== 'object' ||
13
+ !notification.visible
14
+ ) {
15
+ return null;
16
+ }
17
+
18
+ const { type = 'info', message = '' } = notification;
19
+
20
+ // Icon and color mapping
21
+ const iconMap = {
22
+ success: { name: 'check-circle', color: COLORS.success },
23
+ error: { name: 'error', color: COLORS.error },
24
+ info: { name: 'info', color: COLORS.info },
25
+ };
26
+
27
+ const { name: iconName, color: iconColor } = iconMap[type] || iconMap.info;
28
+
29
+ return (
30
+ <Animated.View
31
+ style={[
32
+ styles.notificationBox,
33
+ styles[type] || {}, // Prevent undefined style
34
+ {
35
+ opacity: fadeAnim instanceof Animated.Value ? fadeAnim : 1,
36
+ transform: [
37
+ {
38
+ translateY: slideAnim instanceof Animated.Value ? slideAnim : 0,
39
+ },
40
+ ],
41
+ },
42
+ ]}
43
+ >
44
+ <Icon
45
+ name={iconName}
46
+ size={20}
47
+ color={iconColor}
48
+ style={styles.notificationIcon}
49
+ />
50
+ <Text style={styles.notificationText}>{message}</Text>
51
+ </Animated.View>
52
+ );
53
+ };
54
+
55
+ Notification.propTypes = {
56
+ notification: PropTypes.shape({
57
+ visible: PropTypes.bool.isRequired,
58
+ type: PropTypes.oneOf(['success', 'error', 'info']),
59
+ message: PropTypes.string,
60
+ }),
61
+ fadeAnim: PropTypes.any, // Animated.Value expected
62
+ slideAnim: PropTypes.any, // Animated.Value expected
63
+ };
@@ -0,0 +1,112 @@
1
+ import React, { useEffect, useRef } from 'react';
2
+ import { Animated, ActivityIndicator, Easing } from 'react-native';
3
+ import Icon from 'react-native-vector-icons/MaterialIcons';
4
+ import { ANIMATION_STATES, COLORS } from '../utils/constants';
5
+ import { styles } from './styles';
6
+
7
+ export const StateIndicator = ({ state, size = 100 }) => {
8
+ const spinValue = useRef(new Animated.Value(0)).current;
9
+ const pulseValue = useRef(new Animated.Value(1)).current;
10
+ const spinAnimation = useRef(null);
11
+ const pulseAnimation = useRef(null);
12
+
13
+ useEffect(() => {
14
+ // Stop ongoing animations when state changes
15
+ spinValue.stopAnimation();
16
+ pulseValue.stopAnimation();
17
+
18
+ if (
19
+ state === ANIMATION_STATES.PROCESSING ||
20
+ state === ANIMATION_STATES.FACE_SCAN ||
21
+ state === ANIMATION_STATES.QR_SCAN
22
+ ) {
23
+ spinAnimation.current = Animated.loop(
24
+ Animated.timing(spinValue, {
25
+ toValue: 1,
26
+ duration: 1500,
27
+ easing: Easing.linear,
28
+ useNativeDriver: true,
29
+ })
30
+ );
31
+ spinAnimation.current.start();
32
+ }
33
+ else if (
34
+ state === ANIMATION_STATES.SUCCESS ||
35
+ state === ANIMATION_STATES.ERROR
36
+ ) {
37
+ pulseAnimation.current = Animated.loop(
38
+ Animated.sequence([
39
+ Animated.timing(pulseValue, {
40
+ toValue: 1.1,
41
+ duration: 500,
42
+ useNativeDriver: true,
43
+ }),
44
+ Animated.timing(pulseValue, {
45
+ toValue: 1,
46
+ duration: 500,
47
+ useNativeDriver: true,
48
+ }),
49
+ ]),
50
+ { iterations: 2 }
51
+ );
52
+ pulseAnimation.current.start();
53
+ }
54
+ else {
55
+ spinValue.setValue(0);
56
+ pulseValue.setValue(1);
57
+ }
58
+ }, [state, spinValue, pulseValue]);
59
+
60
+ const spin = spinValue.interpolate({
61
+ inputRange: [0, 1],
62
+ outputRange: ['0deg', '360deg'],
63
+ });
64
+
65
+ const getIcon = () => {
66
+ switch (state) {
67
+ case ANIMATION_STATES.FACE_SCAN:
68
+ return <Icon name="face" size={size * 0.5} color={COLORS.primary} />;
69
+ case ANIMATION_STATES.QR_SCAN:
70
+ return <Icon name="qr-code-scanner" size={size * 0.5} color={COLORS.primary} />;
71
+ case ANIMATION_STATES.PROCESSING:
72
+ return <Icon name="settings" size={size * 0.5} color={COLORS.info} />;
73
+ case ANIMATION_STATES.SUCCESS:
74
+ return <Icon name="check-circle" size={size * 0.5} color={COLORS.success} />;
75
+ case ANIMATION_STATES.ERROR:
76
+ return <Icon name="error" size={size * 0.5} color={COLORS.error} />;
77
+ default:
78
+ return <Icon name="hourglass-empty" size={size * 0.5} color={COLORS.gray} />;
79
+ }
80
+ };
81
+
82
+ return (
83
+ <Animated.View
84
+ style={[
85
+ styles.indicatorContainer,
86
+ {
87
+ width: size,
88
+ height: size,
89
+ transform: [
90
+ { scale: pulseValue },
91
+ ...(state === ANIMATION_STATES.PROCESSING ||
92
+ state === ANIMATION_STATES.FACE_SCAN ||
93
+ state === ANIMATION_STATES.QR_SCAN
94
+ ? [{ rotate: spin }]
95
+ : []),
96
+ ],
97
+ },
98
+ ]}
99
+ >
100
+ {(state === ANIMATION_STATES.PROCESSING ||
101
+ state === ANIMATION_STATES.FACE_SCAN ||
102
+ state === ANIMATION_STATES.QR_SCAN) ? (
103
+ <ActivityIndicator
104
+ size="large"
105
+ color={state === ANIMATION_STATES.PROCESSING ? COLORS.info : COLORS.primary}
106
+ />
107
+ ) : (
108
+ getIcon()
109
+ )}
110
+ </Animated.View>
111
+ );
112
+ };
@@ -0,0 +1,182 @@
1
+ import { StyleSheet, Platform } from 'react-native';
2
+ import { COLORS } from '../utils/constants';
3
+
4
+ export const styles = StyleSheet.create({
5
+ modalBg: {
6
+ flex: 1,
7
+ backgroundColor: 'rgba(0, 0, 0, 0.7)',
8
+ justifyContent: 'center',
9
+ alignItems: 'center',
10
+ paddingHorizontal: 20,
11
+ },
12
+ close: {
13
+ position: 'absolute',
14
+ top: 20,
15
+ right: 20,
16
+ zIndex: 10,
17
+ backgroundColor: 'rgba(255, 255, 255, 0.2)',
18
+ borderRadius: 20,
19
+ padding: 5,
20
+ },
21
+ title: {
22
+ fontSize: 26,
23
+ fontWeight: '700',
24
+ color: COLORS.light,
25
+ marginBottom: 5,
26
+ textAlign: 'center',
27
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
28
+ },
29
+ subTitle: {
30
+ fontSize: 18,
31
+ color: COLORS.light,
32
+ marginBottom: 25,
33
+ fontWeight: '600',
34
+ textAlign: 'center',
35
+ opacity: 0.9,
36
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif-medium',
37
+ },
38
+ indicatorContainer: {
39
+ justifyContent: 'center',
40
+ alignItems: 'center',
41
+ marginVertical: 25,
42
+ },
43
+ employeeCard: {
44
+ alignItems: 'center',
45
+ marginVertical: 20,
46
+ width: '100%',
47
+ padding: 20,
48
+ backgroundColor: 'rgba(255, 255, 255, 0.9)',
49
+ borderRadius: 16,
50
+ shadowColor: '#000',
51
+ shadowOffset: { width: 0, height: 4 },
52
+ shadowOpacity: 0.1,
53
+ shadowRadius: 6,
54
+ elevation: 3,
55
+ },
56
+ employeeImageContainer: {
57
+ width: 100,
58
+ height: 100,
59
+ borderRadius: 50,
60
+ borderWidth: 3,
61
+ borderColor: COLORS.primary,
62
+ position: 'relative',
63
+ overflow: 'hidden',
64
+ },
65
+ employeeImage: {
66
+ width: '100%',
67
+ height: '100%',
68
+ },
69
+ employeeImageOverlay: {
70
+ ...StyleSheet.absoluteFillObject,
71
+ backgroundColor: 'rgba(108, 99, 255, 0.1)',
72
+ },
73
+ empName: {
74
+ fontSize: 20,
75
+ fontWeight: '600',
76
+ marginTop: 15,
77
+ color: COLORS.dark,
78
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif-medium',
79
+ },
80
+ empId: {
81
+ fontSize: 15,
82
+ color: COLORS.gray,
83
+ marginTop: 5,
84
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
85
+ },
86
+ employeeDetails: {
87
+ flexDirection: 'row',
88
+ marginTop: 15,
89
+ justifyContent: 'center',
90
+ flexWrap: 'wrap',
91
+ },
92
+ detailItem: {
93
+ flexDirection: 'row',
94
+ alignItems: 'center',
95
+ marginHorizontal: 8,
96
+ marginVertical: 4,
97
+ },
98
+ detailText: {
99
+ fontSize: 13,
100
+ color: COLORS.gray,
101
+ marginLeft: 5,
102
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
103
+ },
104
+ notificationBox: {
105
+ padding: 15,
106
+ borderRadius: 12,
107
+ marginVertical: 10,
108
+ width: '100%',
109
+ flexDirection: 'row',
110
+ alignItems: 'center',
111
+ shadowColor: '#000',
112
+ shadowOffset: { width: 0, height: 2 },
113
+ shadowOpacity: 0.1,
114
+ shadowRadius: 4,
115
+ elevation: 2,
116
+ },
117
+ info: {
118
+ backgroundColor: 'rgba(33, 150, 243, 0.15)',
119
+ borderLeftWidth: 4,
120
+ borderLeftColor: COLORS.light,
121
+ },
122
+ success: {
123
+ backgroundColor: 'rgba(76, 175, 80, 0.15)',
124
+ borderLeftWidth: 4,
125
+ borderLeftColor: COLORS.success,
126
+ },
127
+ error: {
128
+ backgroundColor: 'rgba(244, 67, 54, 0.15)',
129
+ borderLeftWidth: 4,
130
+ borderLeftColor: COLORS.error,
131
+ },
132
+ notificationIcon: {
133
+ marginRight: 10,
134
+ },
135
+ notificationText: {
136
+ fontSize: 14,
137
+ color: COLORS.light,
138
+ fontWeight: '500',
139
+ flex: 1,
140
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
141
+ },
142
+ timerContainer: {
143
+ marginTop: 20,
144
+ alignItems: 'center',
145
+ },
146
+ timerCircle: {
147
+ width: 80,
148
+ height: 80,
149
+ borderRadius: 40,
150
+ backgroundColor: 'rgba(255, 255, 255, 0.2)',
151
+ justifyContent: 'center',
152
+ alignItems: 'center',
153
+ position: 'relative',
154
+ },
155
+ timerProgressContainer: {
156
+ position: 'absolute',
157
+ width: '100%',
158
+ height: '100%',
159
+ },
160
+ timerProgress: {
161
+ width: 76,
162
+ height: 76,
163
+ borderRadius: 38,
164
+ borderWidth: 3,
165
+ borderColor: COLORS.light,
166
+ borderLeftColor: 'transparent',
167
+ borderBottomColor: 'transparent',
168
+ },
169
+ timerText: {
170
+ fontSize: 20,
171
+ fontWeight: '700',
172
+ color: COLORS.light,
173
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif-medium',
174
+ },
175
+ timerLabel: {
176
+ fontSize: 14,
177
+ color: COLORS.light,
178
+ marginTop: 5,
179
+ opacity: 0.8,
180
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
181
+ },
182
+ });