Files
WalletTracker/src/screens/LoginScreen.tsx
Arthur Lempereur 8bde3d4f21 Initial commit: WalletTracker app with Firebase integration
- Setup Expo project with TypeScript
- Implement authentication (Login/Signup/Logout)
- Create Dashboard, Transactions, Subscriptions, and Analysis screens
- Add Firebase services (Auth, Firestore, Storage)
- Implement real-time synchronization
- Add charts and analytics
- Create reusable components (Button, InputText, TransactionCard, SubscriptionCard)
- Configure React Navigation with bottom tabs
- Add Firestore security rules
- Create comprehensive documentation (README, FIREBASE_SETUP, TESTING)
2025-10-23 14:36:36 +02:00

151 lines
3.6 KiB
TypeScript

import React, { useState } from 'react';
import {
View,
Text,
StyleSheet,
KeyboardAvoidingView,
Platform,
ScrollView,
Alert
} from 'react-native';
import { InputText } from '../components/InputText';
import { Button } from '../components/Button';
import { useAuth } from '../hooks/useAuth';
export const LoginScreen = ({ navigation }: any) => {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [errors, setErrors] = useState<{ email?: string; password?: string }>({});
const { login, loading } = useAuth();
const validateForm = () => {
const newErrors: { email?: string; password?: string } = {};
if (!email.trim()) {
newErrors.email = 'L\'email est requis';
} else if (!/\S+@\S+\.\S+/.test(email)) {
newErrors.email = 'Email invalide';
}
if (!password) {
newErrors.password = 'Le mot de passe est requis';
} else if (password.length < 6) {
newErrors.password = 'Le mot de passe doit contenir au moins 6 caractères';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleLogin = async () => {
if (!validateForm()) return;
try {
await login(email.trim(), password);
} catch (error: any) {
Alert.alert('Erreur de connexion', error.message);
}
};
return (
<KeyboardAvoidingView
style={styles.container}
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
>
<ScrollView
contentContainerStyle={styles.scrollContent}
keyboardShouldPersistTaps="handled"
>
<View style={styles.header}>
<Text style={styles.logo}>💰</Text>
<Text style={styles.title}>WalletTracker</Text>
<Text style={styles.subtitle}>Gérez votre budget facilement</Text>
</View>
<View style={styles.form}>
<InputText
label="Email"
placeholder="votre@email.com"
value={email}
onChangeText={(text) => {
setEmail(text);
setErrors({ ...errors, email: undefined });
}}
error={errors.email}
keyboardType="email-address"
autoCapitalize="none"
autoComplete="email"
/>
<InputText
label="Mot de passe"
placeholder="••••••••"
value={password}
onChangeText={(text) => {
setPassword(text);
setErrors({ ...errors, password: undefined });
}}
error={errors.password}
secureTextEntry
autoCapitalize="none"
autoComplete="password"
/>
<Button
title="Se connecter"
onPress={handleLogin}
loading={loading}
style={styles.loginButton}
/>
<Button
title="Créer un compte"
onPress={() => navigation.navigate('Signup')}
variant="outline"
style={styles.signupButton}
/>
</View>
</ScrollView>
</KeyboardAvoidingView>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F8F9FA'
},
scrollContent: {
flexGrow: 1,
justifyContent: 'center',
padding: 24
},
header: {
alignItems: 'center',
marginBottom: 48
},
logo: {
fontSize: 64,
marginBottom: 16
},
title: {
fontSize: 32,
fontWeight: 'bold',
color: '#333',
marginBottom: 8
},
subtitle: {
fontSize: 16,
color: '#666'
},
form: {
width: '100%'
},
loginButton: {
marginTop: 8
},
signupButton: {
marginTop: 12
}
});