react-native-biometric-verifier 0.0.12 → 0.0.13

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,113 +1,175 @@
1
- import React, { useEffect, useRef } from 'react';
2
- import { Animated, Easing, View } 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';
1
+ import React, { useState, useEffect } from "react";
2
+ import {
3
+ StyleSheet,
4
+ Dimensions,
5
+ View,
6
+ Modal,
7
+ Animated,
8
+ Easing,
9
+ Text
10
+ } from "react-native";
6
11
  import FastImage from 'react-native-fast-image';
12
+ import { normalize } from "react-native-elements";
7
13
 
8
- export const Loader = ({ state, source, isLoading = false }) => {
9
- const spinValue = useRef(new Animated.Value(0)).current;
10
- const pulseValue = useRef(new Animated.Value(1)).current;
11
- const spinAnimation = useRef(null);
12
- const pulseAnimation = useRef(null);
13
-
14
- const size = 120; // Define the size constant
14
+ export default function Loader({
15
+ visible = false,
16
+ overlayColor = 'rgba(0,0,0,0.4)',
17
+ loaderColor = 'lightblue',
18
+ size = 50,
19
+ gifSource = {uri:`http://emr.amalaims.org:9393/file/getCommonFile/image/heartpulse.gif`},
20
+ message = '',
21
+ messageStyle = {},
22
+ animationType = 'fade',
23
+ hasBackground = true,
24
+ borderRadius = 20,
25
+ shadow = true
26
+ }) {
27
+ const [rotation] = useState(new Animated.Value(0));
28
+ const [pulse] = useState(new Animated.Value(1));
29
+ const [fade] = useState(new Animated.Value(0));
15
30
 
31
+ // Rotation animation
16
32
  useEffect(() => {
17
- // Stop ongoing animations when state changes
18
- spinAnimation.current?.stop();
19
- pulseAnimation.current?.stop();
20
-
21
- if (
22
- state === ANIMATION_STATES.PROCESSING ||
23
- state === ANIMATION_STATES.FACE_SCAN ||
24
- state === ANIMATION_STATES.QR_SCAN
25
- ) {
26
- spinAnimation.current = Animated.loop(
27
- Animated.timing(spinValue, {
33
+ if (!gifSource) { // Only animate if not using a GIF
34
+ Animated.loop(
35
+ Animated.timing(rotation, {
28
36
  toValue: 1,
29
37
  duration: 1500,
30
38
  easing: Easing.linear,
31
- useNativeDriver: true,
39
+ useNativeDriver: true
32
40
  })
33
- );
34
- spinAnimation.current.start();
35
- }
36
- else if (
37
- state === ANIMATION_STATES.SUCCESS ||
38
- state === ANIMATION_STATES.ERROR
39
- ) {
40
- pulseAnimation.current = Animated.loop(
41
- Animated.sequence([
42
- Animated.timing(pulseValue, {
43
- toValue: 1.1,
44
- duration: 500,
45
- useNativeDriver: true,
46
- }),
47
- Animated.timing(pulseValue, {
48
- toValue: 1,
49
- duration: 500,
50
- useNativeDriver: true,
51
- }),
52
- ]),
53
- { iterations: 2 }
54
- );
55
- pulseAnimation.current.start();
56
- }
57
- else {
58
- spinValue.setValue(0);
59
- pulseValue.setValue(1);
41
+ ).start();
60
42
  }
61
43
 
62
- return () => {
63
- spinAnimation.current?.stop();
64
- pulseAnimation.current?.stop();
65
- };
66
- }, [state, spinValue, pulseValue]);
44
+ // Pulse animation
45
+ Animated.loop(
46
+ Animated.sequence([
47
+ Animated.timing(pulse, {
48
+ toValue: 1.1,
49
+ duration: 800,
50
+ useNativeDriver: true
51
+ }),
52
+ Animated.timing(pulse, {
53
+ toValue: 1,
54
+ duration: 800,
55
+ useNativeDriver: true
56
+ })
57
+ ])
58
+ ).start();
59
+
60
+ // Fade in animation
61
+ Animated.timing(fade, {
62
+ toValue: 1,
63
+ duration: 300,
64
+ useNativeDriver: true
65
+ }).start();
66
+ }, []);
67
67
 
68
- const getIcon = () => {
69
- switch (state) {
70
- case ANIMATION_STATES.FACE_SCAN:
71
- return <Icon name="face" size={size * 0.5} color={COLORS.primary} />;
72
- case ANIMATION_STATES.QR_SCAN:
73
- return <Icon name="qr-code-scanner" size={size * 0.5} color={COLORS.primary} />;
74
- case ANIMATION_STATES.PROCESSING:
75
- return <Icon name="settings" size={size * 0.5} color={COLORS.info} />;
76
- case ANIMATION_STATES.SUCCESS:
77
- return <Icon name="check-circle" size={size * 0.5} color={COLORS.success} />;
78
- case ANIMATION_STATES.ERROR:
79
- return <Icon name="error" size={size * 0.5} color={COLORS.error} />;
80
- default:
81
- return <Icon name="hourglass-empty" size={size * 0.5} color={COLORS.gray} />;
82
- }
83
- };
68
+ const spin = rotation.interpolate({
69
+ inputRange: [0, 1],
70
+ outputRange: ['0deg', '360deg']
71
+ });
72
+
73
+ const loaderContent = gifSource ? (
74
+ <FastImage
75
+ style={[styles.icon_style, { width: normalize(size), height: normalize(size) }]}
76
+ source={gifSource}
77
+ />
78
+ ) : (
79
+ <Animated.View style={[
80
+ styles.defaultLoader,
81
+ {
82
+ borderColor: loaderColor,
83
+ transform: [{ rotate: spin }, { scale: pulse }],
84
+ width: normalize(size),
85
+ height: normalize(size),
86
+ borderWidth: normalize(size / 10)
87
+ }
88
+ ]}>
89
+ <View style={[
90
+ styles.innerCircle,
91
+ {
92
+ backgroundColor: loaderColor,
93
+ width: normalize(size / 2),
94
+ height: normalize(size / 2)
95
+ }
96
+ ]} />
97
+ </Animated.View>
98
+ );
84
99
 
85
100
  return (
86
- <View style={styles.indicatorWrapper}>
87
- <Animated.View
88
- style={[
89
- styles.indicatorContainer,
90
- {
91
- width: size,
92
- height: size,
93
- transform: [
94
- { scale: pulseValue },
95
- ],
96
- },
97
- ]}
98
- >
99
- {isLoading && source ? (
100
- <FastImage
101
- style={[styles.icon, { width: size * 0.8, height: size * 0.8 }]}
102
- source={source}
103
- resizeMode={FastImage.resizeMode.contain}
104
- />
105
- ) : (
106
- getIcon()
107
- )}
101
+ <Modal
102
+ animationType={animationType}
103
+ transparent={true}
104
+ visible={visible}
105
+ onRequestClose={() => {}}
106
+ >
107
+ <Animated.View style={[
108
+ styles.modalContainer,
109
+ {
110
+ backgroundColor: overlayColor,
111
+ opacity: fade
112
+ }
113
+ ]}>
114
+ <Animated.View style={[
115
+ styles.loaderContainer,
116
+ {
117
+ backgroundColor: hasBackground ? 'white' : 'transparent',
118
+ borderRadius: normalize(borderRadius),
119
+ transform: [{ scale: pulse }],
120
+ ...(shadow && styles.shadowStyle)
121
+ }
122
+ ]}>
123
+ {console.log('loadersource--------------------',JSON.stringify(gifSource))}
124
+ {loaderContent}
125
+ {message ? (
126
+ <Text style={[styles.messageText, messageStyle]}>
127
+ {message}
128
+ </Text>
129
+ ) : null}
130
+ </Animated.View>
108
131
  </Animated.View>
109
- </View>
132
+ </Modal>
110
133
  );
111
- };
134
+ }
112
135
 
113
- export default Loader;
136
+ const styles = StyleSheet.create({
137
+ modalContainer: {
138
+ flex: 1,
139
+ justifyContent: 'center',
140
+ alignItems: 'center',
141
+ },
142
+ loaderContainer: {
143
+ padding: normalize(20),
144
+ justifyContent: 'center',
145
+ alignItems: 'center',
146
+ },
147
+ icon_style: {
148
+ justifyContent: "center",
149
+ alignItems: "center"
150
+ },
151
+ defaultLoader: {
152
+ borderRadius: normalize(100),
153
+ justifyContent: 'center',
154
+ alignItems: 'center',
155
+ },
156
+ innerCircle: {
157
+ borderRadius: normalize(100),
158
+ },
159
+ messageText: {
160
+ marginTop: normalize(15),
161
+ fontSize: normalize(14),
162
+ color: '#555',
163
+ textAlign: 'center'
164
+ },
165
+ shadowStyle: {
166
+ shadowColor: "#000",
167
+ shadowOffset: {
168
+ width: 0,
169
+ height: 2,
170
+ },
171
+ shadowOpacity: 0.25,
172
+ shadowRadius: 3.84,
173
+ elevation: 5,
174
+ }
175
+ });
@@ -1,21 +1,19 @@
1
1
  import React from 'react';
2
- import { Animated, Text } from 'react-native';
2
+ import { Animated, Text, Platform } from 'react-native';
3
3
  import Icon from 'react-native-vector-icons/MaterialIcons';
4
4
  import PropTypes from 'prop-types';
5
5
  import { COLORS } from '../utils/constants';
6
- import { styles } from './styles';
7
6
 
8
7
  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
- ) {
8
+ // Defensive checks
9
+ if (!notification || typeof notification !== 'object') {
10
+ console.warn('Notification: Invalid or missing notification object');
15
11
  return null;
16
12
  }
17
13
 
18
- const { type = 'info', message = '' } = notification;
14
+ const { visible, type = 'info', message = '' } = notification;
15
+
16
+ if (!visible) return null;
19
17
 
20
18
  // Icon and color mapping
21
19
  const iconMap = {
@@ -29,8 +27,20 @@ export const Notification = ({ notification, fadeAnim, slideAnim }) => {
29
27
  return (
30
28
  <Animated.View
31
29
  style={[
32
- styles.notificationBox,
33
- styles[type] || {}, // Prevent undefined style
30
+ {
31
+ padding: 15,
32
+ borderRadius: 12,
33
+ marginVertical: 10,
34
+ width: '100%',
35
+ flexDirection: 'row',
36
+ alignItems: 'center',
37
+ backgroundColor: COLORS.dark, // Added for visibility
38
+ shadowColor: '#000',
39
+ shadowOffset: { width: 0, height: 2 },
40
+ shadowOpacity: 0.1,
41
+ shadowRadius: 4,
42
+ elevation: 2,
43
+ },
34
44
  {
35
45
  opacity: fadeAnim instanceof Animated.Value ? fadeAnim : 1,
36
46
  transform: [
@@ -45,9 +55,19 @@ export const Notification = ({ notification, fadeAnim, slideAnim }) => {
45
55
  name={iconName}
46
56
  size={20}
47
57
  color={iconColor}
48
- style={styles.notificationIcon}
58
+ style={{ marginRight: 10 }}
49
59
  />
50
- <Text style={styles.notificationText}>{message}</Text>
60
+ <Text
61
+ style={{
62
+ fontSize: 14,
63
+ color: COLORS.light,
64
+ fontWeight: '500',
65
+ flex: 1,
66
+ fontFamily: Platform.OS === 'ios' ? 'Helvetica Neue' : 'sans-serif',
67
+ }}
68
+ >
69
+ {message || 'No message provided'}
70
+ </Text>
51
71
  </Animated.View>
52
72
  );
53
73
  };
@@ -58,6 +78,14 @@ Notification.propTypes = {
58
78
  type: PropTypes.oneOf(['success', 'error', 'info']),
59
79
  message: PropTypes.string,
60
80
  }),
61
- fadeAnim: PropTypes.any, // Animated.Value expected
62
- slideAnim: PropTypes.any, // Animated.Value expected
81
+ fadeAnim: PropTypes.instanceOf(Animated.Value),
82
+ slideAnim: PropTypes.instanceOf(Animated.Value),
63
83
  };
84
+
85
+ Notification.defaultProps = {
86
+ notification: { visible: false, type: 'info', message: '' },
87
+ fadeAnim: new Animated.Value(1),
88
+ slideAnim: new Animated.Value(0),
89
+ };
90
+
91
+ export default Notification;
@@ -0,0 +1,71 @@
1
+ // components/StepIcon.js
2
+ import React from 'react';
3
+ import { Animated } from 'react-native';
4
+ import Icon from 'react-native-vector-icons/MaterialIcons';
5
+ import { COLORS } from '../utils/constants';
6
+
7
+ const StepIcon = ({
8
+ currentStep,
9
+ animationState,
10
+ scaleAnim,
11
+ opacityAnim
12
+ }) => {
13
+ // Get appropriate icon for current step
14
+ const getStepIcon = () => {
15
+ switch (currentStep) {
16
+ case "Start":
17
+ return "play-arrow";
18
+ case "Identity Verification":
19
+ return animationState === "success"
20
+ ? "check-circle"
21
+ : "face";
22
+ case "Location Verification":
23
+ return animationState === "success"
24
+ ? "check-circle"
25
+ : "location-on";
26
+ default:
27
+ return "info";
28
+ }
29
+ };
30
+
31
+ // Get appropriate icon color for current state
32
+ const getIconColor = () => {
33
+ switch (animationState) {
34
+ case "success":
35
+ return COLORS.success;
36
+ case "error":
37
+ return COLORS.error;
38
+ default:
39
+ return COLORS.primary;
40
+ }
41
+ };
42
+
43
+ return (
44
+ <Animated.View
45
+ style={[
46
+ styles.iconContainer,
47
+ {
48
+ transform: [{ scale: scaleAnim }],
49
+ opacity: opacityAnim
50
+ }
51
+ ]}
52
+ >
53
+ <Icon
54
+ name={getStepIcon()}
55
+ size={40}
56
+ color={getIconColor()}
57
+ />
58
+ </Animated.View>
59
+ );
60
+ };
61
+
62
+ const styles = {
63
+ iconContainer: {
64
+ marginRight: 15,
65
+ backgroundColor: 'rgba(255, 255, 255, 0.1)',
66
+ borderRadius: 30,
67
+ padding: 10,
68
+ },
69
+ };
70
+
71
+ export default StepIcon;
@@ -0,0 +1,91 @@
1
+ // components/StepIndicator.js
2
+ import React from 'react';
3
+ import { View, Text, StyleSheet, Platform } from 'react-native';
4
+ import Icon from 'react-native-vector-icons/MaterialIcons';
5
+ import { COLORS } from '../utils/constants';
6
+
7
+ const StepIndicator = ({ currentStep }) => {
8
+ return (
9
+ <View style={styles.statusContainer}>
10
+ <View style={styles.statusItem}>
11
+ <Icon
12
+ name="face"
13
+ size={20}
14
+ color={
15
+ currentStep === "Identity Verification" ||
16
+ currentStep === "Location Verification" ||
17
+ currentStep === "Complete"
18
+ ? COLORS.primary
19
+ : COLORS.light
20
+ }
21
+ style={styles.statusIcon}
22
+ />
23
+ <Text style={[
24
+ styles.statusText,
25
+ (currentStep === "Identity Verification" ||
26
+ currentStep === "Location Verification" ||
27
+ currentStep === "Complete") && styles.statusTextActive
28
+ ]}>
29
+ Identity
30
+ </Text>
31
+ </View>
32
+
33
+ <View style={styles.statusSeparator} />
34
+
35
+ <View style={styles.statusItem}>
36
+ <Icon
37
+ name="location-on"
38
+ size={20}
39
+ color={
40
+ currentStep === "Location Verification" ||
41
+ currentStep === "Complete"
42
+ ? COLORS.primary
43
+ : COLORS.light
44
+ }
45
+ style={styles.statusIcon}
46
+ />
47
+ <Text style={[
48
+ styles.statusText,
49
+ (currentStep === "Location Verification" ||
50
+ currentStep === "Complete") && styles.statusTextActive
51
+ ]}>
52
+ Location
53
+ </Text>
54
+ </View>
55
+ </View>
56
+ );
57
+ };
58
+
59
+ const styles = StyleSheet.create({
60
+ statusContainer: {
61
+ flexDirection: 'row',
62
+ alignItems: 'center',
63
+ marginBottom: 20,
64
+ paddingHorizontal: 20,
65
+ },
66
+ statusItem: {
67
+ alignItems: 'center',
68
+ justifyContent: 'center',
69
+ },
70
+ statusIcon: {
71
+ marginBottom: 5,
72
+ },
73
+ statusText: {
74
+ fontSize: 12,
75
+ color: COLORS.light,
76
+ opacity: 0.6,
77
+ },
78
+ statusTextActive: {
79
+ opacity: 1,
80
+ fontWeight: '600',
81
+ },
82
+ statusSeparator: {
83
+ width: 40,
84
+ height: 1,
85
+ backgroundColor: COLORS.light,
86
+ opacity: 0.3,
87
+ marginHorizontal: 15,
88
+ },
89
+ });
90
+
91
+ export default StepIndicator;
@@ -18,6 +18,7 @@ export const useNotifyMessage = () => {
18
18
 
19
19
  const fadeAnim = useRef(new Animated.Value(0)).current;
20
20
  const slideAnim = useRef(new Animated.Value(-20)).current;
21
+ const timeoutRef = useRef(null);
21
22
 
22
23
  // Styles for notification container based on type
23
24
  const getNotificationStyle = useCallback((type) => {
@@ -51,7 +52,25 @@ export const useNotifyMessage = () => {
51
52
  textAlign: 'center',
52
53
  }), []);
53
54
 
55
+ const clearNotification = useCallback(() => {
56
+ // Clear any pending timeout
57
+ if (timeoutRef.current) {
58
+ clearTimeout(timeoutRef.current);
59
+ timeoutRef.current = null;
60
+ }
61
+
62
+ // Reset animations
63
+ fadeAnim.setValue(0);
64
+ slideAnim.setValue(-20);
65
+
66
+ // Hide notification
67
+ setNotification({ visible: false, message: '', type: 'info' });
68
+ }, [fadeAnim, slideAnim]);
69
+
54
70
  const showNotification = useCallback((message, type = 'info') => {
71
+ // Clear any existing notification first
72
+ clearNotification();
73
+
55
74
  setNotification({ visible: true, message, type });
56
75
 
57
76
  fadeAnim.setValue(0);
@@ -69,7 +88,8 @@ export const useNotifyMessage = () => {
69
88
  useNativeDriver: false,
70
89
  }),
71
90
  ]).start(() => {
72
- setTimeout(() => {
91
+ // Store timeout reference so we can clear it later
92
+ timeoutRef.current = setTimeout(() => {
73
93
  Animated.parallel([
74
94
  Animated.timing(fadeAnim, {
75
95
  toValue: 0,
@@ -81,12 +101,13 @@ export const useNotifyMessage = () => {
81
101
  duration: 300,
82
102
  useNativeDriver: false,
83
103
  }),
84
- ]).start(() =>
85
- setNotification({ visible: false, message: '', type: 'info' })
86
- );
104
+ ]).start(() => {
105
+ timeoutRef.current = null;
106
+ setNotification({ visible: false, message: '', type: 'info' });
107
+ });
87
108
  }, 3000);
88
109
  });
89
- }, [fadeAnim, slideAnim]);
110
+ }, [fadeAnim, slideAnim, clearNotification]);
90
111
 
91
112
  const notifyMessage = useCallback(
92
113
  (msg, type = 'info') => {
@@ -125,7 +146,8 @@ export const useNotifyMessage = () => {
125
146
  fadeAnim,
126
147
  slideAnim,
127
148
  notifyMessage,
149
+ clearNotification,
128
150
  getNotificationStyle,
129
151
  notificationTextStyle,
130
152
  };
131
- };
153
+ };