NeoScan_Physician/app/modules/Auth/screens/SetupBiometricScreen.tsx
2025-07-21 18:47:22 +05:30

192 lines
5.8 KiB
TypeScript

/*
* File: SetupBiometricScreen.tsx
* Description: Screen for setting up and authenticating with device biometrics or PIN.
* Design & Developed by Tech4Biz Solutions
* Copyright (c) Spurrin Innovations. All rights reserved.
*/
import React, { useState, useEffect } from 'react';
import {
View,
Text,
TouchableOpacity,
Alert,
StyleSheet,
SafeAreaView,
} from 'react-native';
import ReactNativeBiometrics, {
BiometryTypes,
BiometryType,
} from 'react-native-biometrics';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { Colors, Spacing, Typography, Shadows } from '../../../../shared/src/theme';
import { BASE_URL } from '../../../constants/URLS';
const PAYLOAD = 'neo-scan-secure-payload'; // A static payload for signature
/**
* SetupBiometricScreen - Manages user authentication using the device's
* built-in biometrics or PIN/password.
*/
const SetupBiometricScreen: React.FC = () => {
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [biometryType, setBiometryType] = useState<BiometryType | null>(null);
const [isAvailable, setIsAvailable] = useState(false);
const rnBiometrics = new ReactNativeBiometrics({ allowDeviceCredentials: true });
console.log('base url',BASE_URL)
useEffect(() => {
checkBiometricAvailability();
checkAuthStatus();
}, []);
const checkBiometricAvailability = async () => {
try {
const { available, biometryType: bioType } = await rnBiometrics.isSensorAvailable();
setIsAvailable(available);
setBiometryType(bioType || null);
} catch (error) {
console.error('Biometric check failed:', error);
Alert.alert('Error', 'Could not check for biometric features.');
}
};
const checkAuthStatus = async () => {
try {
const authStatus = await AsyncStorage.getItem('isAuthenticated');
setIsAuthenticated(authStatus === 'true');
} catch (error) {
console.error('Auth status check failed:', error);
}
};
const handleSuccessfulAuth = async () => {
setIsAuthenticated(true);
await AsyncStorage.setItem('isAuthenticated', 'true');
Alert.alert('Success', 'Authentication successful!');
};
const authenticateUser = async () => {
if (!isAvailable) {
Alert.alert('Not Available', 'Biometrics are not supported on this device.');
return;
}
try {
// Check if keys exist. If not, create them.
const { keysExist } = await rnBiometrics.biometricKeysExist();
if (!keysExist) {
await rnBiometrics.createKeys();
}
// Create a signature to authenticate. This will fallback to device PIN.
const { success, signature } = await rnBiometrics.createSignature({
promptMessage: 'Authenticate',
payload: PAYLOAD,
});
if (success && signature) {
// In a real app, you would verify the signature on your server.
// For this example, we'll assume it's valid.
await handleSuccessfulAuth();
} else {
Alert.alert('Authentication Failed', 'You could not be authenticated.');
}
} catch (error) {
console.error('Authentication failed:', error);
Alert.alert('Error', 'An unexpected error occurred during authentication.');
}
};
const getBiometricTypeText = () => {
switch (biometryType) {
case BiometryTypes.TouchID: return 'Touch ID';
case BiometryTypes.FaceID: return 'Face ID';
case BiometryTypes.Biometrics: return 'Fingerprint';
default: return 'Device Credentials';
}
};
const logout = async () => {
try {
setIsAuthenticated(false);
await AsyncStorage.setItem('isAuthenticated', 'false');
} catch (error) {
console.error('Logout failed:', error);
}
};
return (
<SafeAreaView style={styles.container}>
{isAuthenticated ? (
<View style={styles.content}>
<Text style={styles.title}>Welcome!</Text>
<Text style={styles.subtitle}>You are successfully authenticated.</Text>
<TouchableOpacity style={styles.button} onPress={logout}>
<Text style={styles.buttonText}>Logout</Text>
</TouchableOpacity>
</View>
) : (
<View style={styles.content}>
<Text style={styles.title}>Authentication Required</Text>
{isAvailable ? (
<Text style={styles.subtitle}>
Use {getBiometricTypeText()} or your device PIN to continue.
</Text>
) : (
<Text style={styles.subtitle}>
Biometrics not available. Please use your device PIN to continue.
</Text>
)}
<TouchableOpacity style={styles.button} onPress={authenticateUser}>
<Text style={styles.buttonText}>Authenticate</Text>
</TouchableOpacity>
</View>
)}
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: Colors.backgroundAlt,
},
content: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: Spacing.lg,
},
title: {
fontFamily: Typography.fontFamily.bold,
fontSize: Typography.fontSize.title,
color: Colors.textPrimary,
marginBottom: Spacing.md,
textAlign: 'center',
},
subtitle: {
fontFamily: Typography.fontFamily.regular,
fontSize: Typography.fontSize.md,
color: Colors.textSecondary,
textAlign: 'center',
marginBottom: Spacing.xl,
paddingHorizontal: Spacing.lg,
},
button: {
backgroundColor: Colors.primary,
paddingHorizontal: Spacing.xl,
paddingVertical: Spacing.md,
borderRadius: 8,
marginVertical: Spacing.sm,
...Shadows.sm,
minWidth: '80%',
alignItems: 'center',
},
buttonText: {
color: Colors.background,
fontSize: Typography.fontSize.md,
fontFamily: Typography.fontFamily.bold,
},
});
export default SetupBiometricScreen;