419 lines
12 KiB
TypeScript
419 lines
12 KiB
TypeScript
/*
|
|
* File: LoginScreen.tsx
|
|
* Description: Login screen with credential-based authentication
|
|
* Design & Developed by Tech4Biz Solutions
|
|
* Copyright (c) Spurrin Innovations. All rights reserved.
|
|
*/
|
|
|
|
import React, { useState } from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
StyleSheet,
|
|
TouchableWithoutFeedback,
|
|
Keyboard,
|
|
TouchableOpacity,
|
|
TextInput,
|
|
ScrollView,
|
|
KeyboardAvoidingView,
|
|
Alert,
|
|
Image,
|
|
} from 'react-native';
|
|
import { useAppDispatch, useAppSelector } from '../../../store/hooks';
|
|
import { login } from '../redux/authActions';
|
|
import { selectAuthLoading } from '../redux/authSelectors';
|
|
import { theme } from '../../../theme/theme';
|
|
import { validateEmail } from '../../../shared/utils/validators';
|
|
import Icon from 'react-native-vector-icons/Feather';
|
|
import { AuthNavigationProp } from '../navigation';
|
|
|
|
/**
|
|
* LoginScreenProps Interface
|
|
*
|
|
* Purpose: Defines the props required by the LoginScreen component
|
|
*
|
|
* Props:
|
|
* - navigation: React Navigation object for screen navigation
|
|
*/
|
|
interface LoginScreenProps {
|
|
navigation: AuthNavigationProp;
|
|
}
|
|
|
|
/**
|
|
* LoginScreen Component
|
|
*
|
|
* Purpose: Main authentication screen for credential-based login
|
|
*
|
|
* Authentication Flow:
|
|
* 1. Email/Password validation
|
|
* 2. Redux action dispatch for login
|
|
* 3. Loading state management
|
|
* 4. Error handling and user feedback
|
|
*
|
|
* Features:
|
|
* - Keyboard-aware layout for better UX
|
|
* - Form validation and error handling
|
|
* - Loading states during authentication
|
|
* - Password visibility toggle
|
|
* - Navigation to sign up screen
|
|
* - Responsive design for different screen sizes
|
|
*/
|
|
const LoginScreen: React.FC<LoginScreenProps> = ({ navigation }) => {
|
|
// ============================================================================
|
|
// STATE MANAGEMENT
|
|
// ============================================================================
|
|
|
|
// Form input states
|
|
const [email, setEmail] = useState(''); // User's email address
|
|
const [password, setPassword] = useState(''); // User's password
|
|
const [isPasswordVisible, setPasswordVisible] = useState(false); // Password visibility toggle
|
|
|
|
// Redux state
|
|
const dispatch = useAppDispatch();
|
|
const loading = useAppSelector(selectAuthLoading);
|
|
|
|
// ============================================================================
|
|
// EVENT HANDLERS
|
|
// ============================================================================
|
|
|
|
/**
|
|
* handleLogin Function
|
|
*
|
|
* Purpose: Process credential-based login with email and password
|
|
*
|
|
* Flow:
|
|
* 1. Validate that both email and password are provided
|
|
* 2. Validate email format
|
|
* 3. Show error alert if validation fails
|
|
* 4. Dispatch Redux login action with credentials
|
|
*/
|
|
const handleLogin = () => {
|
|
// Validate required fields
|
|
if (!email.trim() || !password.trim()) {
|
|
Alert.alert('Validation Error', 'Email and password are required.');
|
|
return;
|
|
}
|
|
|
|
// Validate email format
|
|
if (!validateEmail(email)) {
|
|
Alert.alert('Validation Error', 'Please enter a valid email address.');
|
|
return;
|
|
}
|
|
|
|
// Dispatch login action
|
|
dispatch(login({ email, password }));
|
|
};
|
|
|
|
/**
|
|
* handleSignUp Function
|
|
*
|
|
* Purpose: Navigate to the SignUpScreen for new user registration
|
|
*
|
|
* Flow: Navigate to SignUp screen using React Navigation
|
|
*/
|
|
const handleSignUp = () => {
|
|
navigation.navigate('SignUp');
|
|
};
|
|
|
|
/**
|
|
* togglePasswordVisibility Function
|
|
*
|
|
* Purpose: Toggle password field visibility for better UX
|
|
*/
|
|
const togglePasswordVisibility = () => {
|
|
setPasswordVisible(!isPasswordVisible);
|
|
};
|
|
|
|
// ============================================================================
|
|
// RENDER SECTION
|
|
// ============================================================================
|
|
|
|
return (
|
|
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
|
|
<KeyboardAvoidingView behavior="padding" style={styles.container}>
|
|
<ScrollView showsVerticalScrollIndicator={false}>
|
|
<View style={styles.content}>
|
|
{/* ========================================================================
|
|
* HEADER SECTION - App branding and title
|
|
* ======================================================================== */}
|
|
<View style={styles.header}>
|
|
<Text style={styles.title}>Radiologist</Text>
|
|
{/* <Text style={styles.subtitle}>Emergency Department Access</Text> */}
|
|
</View>
|
|
<View style={styles.imageContainer}>
|
|
<Image source={require('../../../assets/images/hospital-logo.png')} style={styles.image} />
|
|
</View>
|
|
|
|
{/* ========================================================================
|
|
* LOGIN FORM - Main authentication interface
|
|
* ======================================================================== */}
|
|
<View style={styles.formContainer}>
|
|
{/* Email Input */}
|
|
<View style={styles.inputContainer}>
|
|
<Icon name="mail" size={20} color={theme.colors.textSecondary} style={styles.inputIcon} />
|
|
<TextInput
|
|
placeholder="Email"
|
|
value={email}
|
|
onChangeText={setEmail}
|
|
style={styles.inputField}
|
|
autoCapitalize="none"
|
|
keyboardType="email-address"
|
|
placeholderTextColor={theme.colors.textMuted}
|
|
editable={!loading}
|
|
/>
|
|
</View>
|
|
|
|
{/* Password Input */}
|
|
<View style={styles.inputContainer}>
|
|
<Icon name="lock" size={20} color={theme.colors.textSecondary} style={styles.inputIcon} />
|
|
<TextInput
|
|
placeholder="Password"
|
|
value={password}
|
|
onChangeText={setPassword}
|
|
style={styles.inputField}
|
|
secureTextEntry={!isPasswordVisible}
|
|
placeholderTextColor={theme.colors.textMuted}
|
|
editable={!loading}
|
|
/>
|
|
<TouchableOpacity
|
|
onPress={togglePasswordVisibility}
|
|
style={styles.eyeIcon}
|
|
disabled={loading}
|
|
>
|
|
<Icon
|
|
name={isPasswordVisible ? 'eye-off' : 'eye'}
|
|
size={22}
|
|
color={theme.colors.textSecondary}
|
|
/>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
|
|
|
|
{/* Login Button */}
|
|
<TouchableOpacity
|
|
style={[styles.button, styles.loginButton, loading && styles.buttonDisabled]}
|
|
onPress={handleLogin}
|
|
disabled={loading}
|
|
>
|
|
{loading ? (
|
|
<View style={styles.loadingContainer}>
|
|
<Text style={styles.buttonText}>Logging in...</Text>
|
|
</View>
|
|
) : (
|
|
<Text style={styles.buttonText}>Login</Text>
|
|
)}
|
|
</TouchableOpacity>
|
|
|
|
{/* Divider */}
|
|
<View style={styles.divider}>
|
|
<View style={styles.dividerLine} />
|
|
<Text style={styles.dividerText}>OR</Text>
|
|
<View style={styles.dividerLine} />
|
|
</View>
|
|
|
|
{/* Sign Up Button */}
|
|
<TouchableOpacity
|
|
style={[styles.button, styles.signUpButton]}
|
|
onPress={handleSignUp}
|
|
disabled={loading}
|
|
>
|
|
<Text style={styles.signUpButtonText}>Sign Up</Text>
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* ========================================================================
|
|
* FOOTER - Security and information message
|
|
* ======================================================================== */}
|
|
<View style={styles.footer}>
|
|
<Text style={styles.footerText}>
|
|
Secure access to patient information and critical alerts
|
|
</Text>
|
|
</View>
|
|
</View>
|
|
</ScrollView>
|
|
</KeyboardAvoidingView>
|
|
</TouchableWithoutFeedback>
|
|
);
|
|
};
|
|
|
|
// ============================================================================
|
|
// STYLES SECTION
|
|
// ============================================================================
|
|
|
|
const styles = StyleSheet.create({
|
|
// Main container
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: theme.colors.background,
|
|
},
|
|
|
|
// Content wrapper
|
|
content: {
|
|
flex: 1,
|
|
justifyContent: 'center',
|
|
padding: theme.spacing.lg,
|
|
},
|
|
|
|
// Header section
|
|
header: {
|
|
alignItems: 'center',
|
|
marginBottom: theme.spacing.xxl,
|
|
},
|
|
|
|
// App title
|
|
title: {
|
|
fontSize: theme.typography.fontSize.displayMedium,
|
|
fontFamily: theme.typography.fontFamily.bold,
|
|
color: theme.colors.primary,
|
|
marginBottom: theme.spacing.sm,
|
|
textAlign: 'center',
|
|
},
|
|
|
|
// App subtitle
|
|
subtitle: {
|
|
fontSize: theme.typography.fontSize.bodyMedium,
|
|
fontFamily: theme.typography.fontFamily.regular,
|
|
color: theme.colors.textSecondary,
|
|
textAlign: 'center',
|
|
},
|
|
|
|
// Form container
|
|
formContainer: {
|
|
marginBottom: theme.spacing.xl,
|
|
},
|
|
|
|
// Input container
|
|
inputContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
backgroundColor: theme.colors.backgroundAlt,
|
|
borderWidth: 1,
|
|
borderColor: theme.colors.border,
|
|
borderRadius: theme.borderRadius.medium,
|
|
marginBottom: theme.spacing.md,
|
|
paddingHorizontal: theme.spacing.md,
|
|
paddingVertical: 2,
|
|
},
|
|
|
|
// Input icon
|
|
inputIcon: {
|
|
marginRight: theme.spacing.sm,
|
|
},
|
|
|
|
// Input field
|
|
inputField: {
|
|
flex: 1,
|
|
paddingVertical: theme.spacing.md,
|
|
fontSize: theme.typography.fontSize.bodyLarge,
|
|
fontFamily: theme.typography.fontFamily.regular,
|
|
color: theme.colors.textPrimary,
|
|
},
|
|
|
|
// Eye icon for password visibility
|
|
eyeIcon: {
|
|
padding: theme.spacing.sm,
|
|
},
|
|
|
|
// Base button styling
|
|
button: {
|
|
paddingVertical: theme.spacing.md,
|
|
paddingHorizontal: theme.spacing.lg,
|
|
borderRadius: theme.borderRadius.medium,
|
|
alignItems: 'center',
|
|
marginBottom: theme.spacing.md,
|
|
},
|
|
|
|
// Login button
|
|
loginButton: {
|
|
backgroundColor: theme.colors.primary,
|
|
...theme.shadows.primary,
|
|
},
|
|
|
|
// Sign up button
|
|
signUpButton: {
|
|
backgroundColor: theme.colors.background,
|
|
borderWidth: 1,
|
|
borderColor: theme.colors.primary,
|
|
},
|
|
|
|
// Disabled button
|
|
buttonDisabled: {
|
|
opacity: 0.6,
|
|
},
|
|
|
|
// Button text
|
|
buttonText: {
|
|
color: theme.colors.background,
|
|
fontSize: theme.typography.fontSize.bodyLarge,
|
|
fontFamily: theme.typography.fontFamily.medium,
|
|
},
|
|
|
|
// Sign up button text
|
|
signUpButtonText: {
|
|
color: theme.colors.primary,
|
|
fontSize: theme.typography.fontSize.bodyLarge,
|
|
fontFamily: theme.typography.fontFamily.medium,
|
|
},
|
|
|
|
// Loading container
|
|
loadingContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
|
|
// Divider
|
|
divider: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginVertical: theme.spacing.lg,
|
|
},
|
|
|
|
// Divider line
|
|
dividerLine: {
|
|
flex: 1,
|
|
height: 1,
|
|
backgroundColor: theme.colors.border,
|
|
},
|
|
|
|
// Divider text
|
|
dividerText: {
|
|
marginHorizontal: theme.spacing.md,
|
|
color: theme.colors.textSecondary,
|
|
fontSize: theme.typography.fontSize.bodyMedium,
|
|
fontFamily: theme.typography.fontFamily.medium,
|
|
},
|
|
|
|
// Footer
|
|
footer: {
|
|
alignItems: 'center',
|
|
},
|
|
|
|
// Footer text
|
|
footerText: {
|
|
fontSize: theme.typography.fontSize.bodySmall,
|
|
fontFamily: theme.typography.fontFamily.regular,
|
|
color: theme.colors.textMuted,
|
|
textAlign: 'center',
|
|
},
|
|
|
|
// Image container
|
|
imageContainer: {
|
|
alignItems: 'center',
|
|
marginBottom: theme.spacing.xl,
|
|
},
|
|
|
|
// Image
|
|
image: {
|
|
width: '100%',
|
|
height: 150,
|
|
},
|
|
});
|
|
|
|
export default LoginScreen;
|
|
|
|
/*
|
|
* End of File: LoginScreen.tsx
|
|
* Design & Developed by Tech4Biz Solutions
|
|
* Copyright (c) Spurrin Innovations. All rights reserved.
|
|
*/ |