import React from 'react'; import { View, Text, StyleSheet, TextInput, TouchableOpacity, Pressable, Alert, } from 'react-native'; import { useNavigation } from '@react-navigation/native'; import GradientBackground from '@/shared/components/layout/GradientBackground'; import LinearGradient from 'react-native-linear-gradient'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; import { useDispatch, useSelector } from 'react-redux'; import { login, clearError } from '@/modules/auth/store/authSlice'; import type { RootState, AppDispatch } from '@/store/store'; import { useTheme } from '@/shared/styles/useTheme'; import { validateLoginForm } from '@/shared/utils/validation'; import { showError, showSuccess, showWarning, showInfo } from '@/shared/utils/Toast'; const LoginScreen: React.FC = () => { const navigation = useNavigation(); const dispatch = useDispatch(); const { colors, fonts } = useTheme(); const { loading, error, isAuthenticated } = useSelector((s: RootState) => s.auth); const [email, setEmail] = React.useState(''); const [password, setPassword] = React.useState(''); const [showPassword, setShowPassword] = React.useState(false); const [rememberMe, setRememberMe] = React.useState(false); const [focused, setFocused] = React.useState(null); const [validationErrors, setValidationErrors] = React.useState<{ email?: string; password?: string }>({}); const emailRef = React.useRef(null); const passwordRef = React.useRef(null); // Clear validation errors when user starts typing const handleEmailChange = (text: string) => { setEmail(text); if (validationErrors.email) { setValidationErrors(prev => ({ ...prev, email: undefined })); } // Clear API error when user starts typing if (error) { dispatch(clearError()); } }; const handlePasswordChange = (text: string) => { setPassword(text); if (validationErrors.password) { setValidationErrors(prev => ({ ...prev, password: undefined })); } // Clear API error when user starts typing if (error) { dispatch(clearError()); } }; const handleLogin = async () => { // Clear previous validation errors setValidationErrors({}); // Validate form inputs const validation = validateLoginForm(email, password); if (!validation.isValid) { setValidationErrors(validation.errors); // Show toast messages for validation errors if (validation.errors.email) { showError(validation.errors.email); } if (validation.errors.password) { showError(validation.errors.password); } return; } try { // Dispatch login action const result = await dispatch(login({ email, password })); // Check if login was successful if (login.fulfilled.match(result)) { // Login successful - show success toast showSuccess('Login successful! Welcome back!'); // Navigation will be handled by the app navigator based on isAuthenticated state } else if (login.rejected.match(result)) { // Login failed - show error toast showError(result.payload as string || 'Login failed. Please try again.'); } } catch (err) { // Error handling is done in the slice console.error('Login error:', err); showError('An unexpected error occurred. Please try again.'); } }; // Clear error when component mounts or when user starts typing React.useEffect(() => { if (error) { dispatch(clearError()); } }, [dispatch]); // Auto-focus email input when component mounts React.useEffect(() => { const timer = setTimeout(() => { emailRef.current?.focus(); }, 100); return () => clearTimeout(timer); }, []); return ( {/* Card */} {/* Logo placeholder */} Login Enter your email and password to log in {/* Email input */} emailRef.current?.focus()} > setFocused('email')} onBlur={() => setFocused(null)} onChangeText={handleEmailChange} onSubmitEditing={() => passwordRef.current?.focus()} style={[styles.input, { color: colors.text, fontFamily: fonts.regular }]} /> {validationErrors.email && ( {validationErrors.email} )} {/* Password input */} passwordRef.current?.focus()} > setFocused('password')} onBlur={() => setFocused(null)} onChangeText={handlePasswordChange} style={[styles.input, { color: colors.text, fontFamily: fonts.regular }]} /> setShowPassword(v => !v)} hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }} accessibilityRole="button" accessibilityLabel={showPassword ? 'Hide password' : 'Show password'} > {validationErrors.password && ( {validationErrors.password} )} {/* Row: Remember me + Forgot password */} { setRememberMe(v => !v); showInfo(rememberMe ? 'Will not remember login' : 'Will remember login'); }} > Remember me showInfo('Forgot password feature coming soon!')}> Forgot Password ? {/* Login button */} {loading ? 'Logging in...' : 'Log In'} {/* Or divider */} Or login with {/* Social buttons */} showInfo('Google login coming soon!')} > showInfo('Facebook login coming soon!')} > showInfo('Apple login coming soon!')} > {/* Sign up */} Don't have an account? navigation.navigate('Signup' as never)}> Sign up {/* API Error */} {!!error && ( {error} )} ); }; const styles = StyleSheet.create({ gradient: { flex: 1, }, container: { flex: 1, alignItems: 'center', justifyContent: 'center', padding: 16, }, card: { width: '100%', maxWidth: 380, borderRadius: 16, padding: 16, borderWidth: 1, }, logoCircle: { alignSelf: 'center', width: 48, height: 48, borderRadius: 12, alignItems: 'center', justifyContent: 'center', marginBottom: 8, }, title: { fontSize: 24, textAlign: 'center', }, subtitle: { textAlign: 'center', marginTop: 4, marginBottom: 12, }, inputWrapper: { marginTop: 12, borderWidth: 1, borderRadius: 10, paddingHorizontal: 12, height: 52, flexDirection: 'row', alignItems: 'center', }, input: { paddingVertical: 0, marginLeft: 8, flex: 1, }, iconButton: { position: 'absolute', right: 8, top: 0, bottom: 0, width: 36, alignItems: 'center', justifyContent: 'center', }, rowBetween: { marginTop: 12, flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, row: { flexDirection: 'row', alignItems: 'center', }, rememberText: { marginLeft: 6, }, link: {}, loginButton: { height: 48, borderRadius: 8, alignItems: 'center', justifyContent: 'center', }, loginButtonText: { color: '#FFFFFF', fontSize: 16, }, orContainer: { flexDirection: 'row', alignItems: 'center', marginVertical: 16, }, orLine: { flex: 1, height: 1, }, orText: { marginHorizontal: 8, fontSize: 12, }, socialRow: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', }, socialButton: { width: 52, height: 44, borderRadius: 8, borderWidth: 1, alignItems: 'center', justifyContent: 'center', marginHorizontal: 6, flex: 1, }, signupRow: { flexDirection: 'row', justifyContent: 'center', marginTop: 16, }, signupText: { fontSize: 12, }, errorContainer: { flexDirection: 'row', alignItems: 'center', marginTop: 12, paddingHorizontal: 8, }, errorText: { marginLeft: 6, fontSize: 14, textAlign: 'left', flex: 1, }, }); export default LoginScreen;