152 lines
5.0 KiB
TypeScript
152 lines
5.0 KiB
TypeScript
// src/screens/LoginScreen.tsx
|
|
import React, { useState } from 'react';
|
|
import { View, StyleSheet, KeyboardAvoidingView, Platform } from 'react-native';
|
|
import { TextInput, Button, Text, useTheme, HelperText, ActivityIndicator, Avatar } from 'react-native-paper';
|
|
import { useAuth } from '../contexts/AuthContext';
|
|
import { NativeStackScreenProps } from '@react-navigation/native-stack';
|
|
import { AuthStackParamList } from '../types/navigation'; // Import from the new types file
|
|
|
|
type LoginScreenProps = NativeStackScreenProps<AuthStackParamList, 'Login'>;
|
|
|
|
const LoginScreen: React.FC<LoginScreenProps> = ({ navigation }) => {
|
|
const theme = useTheme();
|
|
const { login } = useAuth();
|
|
const [username, setUsername] = useState('');
|
|
const [password, setPassword] = useState('');
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
const handleLogin = async () => {
|
|
console.log("[LoginScreen] handleLogin: Button pressed."); // Log: Button Press
|
|
if (!username || !password) {
|
|
console.log("[LoginScreen] handleLogin: Missing username or password.");
|
|
setError('Please enter both username/email and password.');
|
|
return;
|
|
}
|
|
setError(null);
|
|
setIsLoading(true);
|
|
try {
|
|
// --- Add Log Here ---
|
|
console.log("[LoginScreen] handleLogin: Calling context login function...");
|
|
await login(username, password);
|
|
console.log("[LoginScreen] handleLogin: Context login function call finished (likely successful navigation).");
|
|
// If successful, this component might unmount before this log appears fully.
|
|
} catch (err: any) {
|
|
console.log("[LoginScreen] handleLogin: Caught error from context login."); // Log: Error caught
|
|
const errorMessage = err.response?.data?.detail ||
|
|
err.response?.data?.message ||
|
|
err.message ||
|
|
'Login failed. Please check your credentials.';
|
|
setError(errorMessage);
|
|
// **Important**: Set loading false *only in the catch block* if navigation doesn't happen
|
|
setIsLoading(false);
|
|
console.log("[LoginScreen] handleLogin: Set loading to false after error.");
|
|
}
|
|
// **Remove potential premature setIsLoading(false) if it was outside the catch block**
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
justifyContent: 'center',
|
|
padding: 20,
|
|
backgroundColor: theme.colors.background,
|
|
},
|
|
logoContainer: {
|
|
alignItems: 'center',
|
|
marginBottom: 40,
|
|
},
|
|
title: {
|
|
fontSize: 24,
|
|
fontWeight: 'bold',
|
|
textAlign: 'center',
|
|
marginBottom: 20,
|
|
color: theme.colors.primary,
|
|
},
|
|
input: {
|
|
marginBottom: 15,
|
|
},
|
|
button: {
|
|
marginTop: 10,
|
|
paddingVertical: 8, // Make button taller
|
|
},
|
|
errorText: {
|
|
// Use HelperText's styling by setting type='error'
|
|
textAlign: 'center',
|
|
marginBottom: 10,
|
|
},
|
|
loadingContainer: {
|
|
marginTop: 20,
|
|
}
|
|
});
|
|
|
|
return (
|
|
<KeyboardAvoidingView
|
|
behavior={Platform.OS === "ios" ? "padding" : "height"}
|
|
style={styles.container}
|
|
>
|
|
<View style={styles.logoContainer}>
|
|
<Avatar.Image
|
|
size={100}
|
|
source={require('../assets/MAIA_ICON.png')}
|
|
/>
|
|
</View>
|
|
<Text style={styles.title}>MAIA Login</Text>
|
|
<TextInput
|
|
label="Username"
|
|
value={username}
|
|
onChangeText={setUsername}
|
|
mode="outlined"
|
|
style={styles.input}
|
|
autoCapitalize="none"
|
|
disabled={isLoading}
|
|
/>
|
|
<TextInput
|
|
label="Password"
|
|
value={password}
|
|
onChangeText={setPassword}
|
|
mode="outlined"
|
|
style={styles.input}
|
|
secureTextEntry // Hides password input
|
|
disabled={isLoading}
|
|
/>
|
|
|
|
{/* Display Error Message */}
|
|
<HelperText type="error" visible={!!error} style={styles.errorText}>
|
|
{error}
|
|
</HelperText>
|
|
|
|
{/* Show loading indicator inline with button or replace it */}
|
|
{isLoading ? (
|
|
<ActivityIndicator animating={true} color={theme.colors.primary} style={styles.loadingContainer}/>
|
|
) : (
|
|
<>
|
|
<Button
|
|
mode="contained"
|
|
onPress={handleLogin}
|
|
style={styles.button}
|
|
disabled={isLoading} // Disable button while loading
|
|
icon="login"
|
|
>
|
|
Login
|
|
</Button>
|
|
|
|
{/* Add Register Button */}
|
|
<Button
|
|
mode="outlined" // Use outlined for secondary action
|
|
onPress={() => navigation.navigate('Register')} // Navigate to Register screen
|
|
style={styles.button} // Reuse button style or create a new one
|
|
disabled={isLoading}
|
|
icon="account-plus-outline"
|
|
>
|
|
Register
|
|
</Button>
|
|
</>
|
|
)}
|
|
|
|
{/* TODO: Add Register here - REMOVED */}
|
|
</KeyboardAvoidingView>
|
|
);
|
|
};
|
|
|
|
export default LoginScreen; |