import 'package:flutter/material.dart'; import '../services/user_service.dart'; import 'package:provider/provider.dart'; import '../providers/user_provider.dart'; class LoginPage extends StatefulWidget { const LoginPage({super.key}); @override State createState() => _LoginPageState(); } class _LoginPageState extends State { final _formKey = GlobalKey(); final _emailController = TextEditingController(); final _passwordController = TextEditingController(); final _userService = UserService(); bool _isLoading = false; bool _obscurePassword = true; @override void dispose() { _emailController.dispose(); _passwordController.dispose(); super.dispose(); } // Validation de l'email String? _validateEmail(String? value) { if (value == null || value.trim().isEmpty) { return 'Email requis'; } final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$'); if (!emailRegex.hasMatch(value.trim())) { return 'Email invalide'; } return null; } // Validation du mot de passe String? _validatePassword(String? value) { if (value == null || value.isEmpty) { return 'Mot de passe requis'; } return null; } // Méthode de connexion Future _login() async { if (!_formKey.currentState!.validate()) { return; } setState(() { _isLoading = true; }); try { final user = await _userService.authenticateUser( _emailController.text.trim(), _passwordController.text, ); if (mounted) { if (user != null) { // Naviguer vers la page d'accueil Provider.of(context, listen: false).setCurrentUser(user); Navigator.pushReplacementNamed(context, '/home'); } else { // Échec de la connexion _showErrorMessage('Email ou mot de passe incorrect'); } } } catch (e) { if (mounted) { _showErrorMessage('Erreur lors de la connexion: ${e.toString()}'); } } finally { if (mounted) { setState(() { _isLoading = false; }); } } } void _showErrorMessage(String message) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message), backgroundColor: Colors.red, duration: const Duration(seconds: 3), ), ); } } @override Widget build(BuildContext context) { return Scaffold( body: SafeArea( child: SingleChildScrollView( child: Padding( padding: const EdgeInsets.all(24.0), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(height: 40), // Titre Text( 'Travel Mate', style: TextStyle(fontSize: 28, fontWeight: FontWeight.bold), ), const SizedBox(height: 12), // Sous-titre Text( 'Connectez-vous pour continuer', style: TextStyle(fontSize: 16, color: Colors.grey), ), const SizedBox(height: 32), // Champ email TextFormField( controller: _emailController, validator: _validateEmail, keyboardType: TextInputType.emailAddress, decoration: InputDecoration( labelText: 'Email', border: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(12)), ), prefixIcon: Icon(Icons.email), ), ), const SizedBox(height: 16), // Champ mot de passe TextFormField( controller: _passwordController, validator: _validatePassword, obscureText: _obscurePassword, decoration: InputDecoration( labelText: 'Mot de passe', border: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(12)), ), prefixIcon: Icon(Icons.lock), suffixIcon: IconButton( icon: Icon( _obscurePassword ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() { _obscurePassword = !_obscurePassword; }); }, ), ), ), const SizedBox(height: 8), // Lien "Mot de passe oublié" Align( alignment: Alignment.centerRight, child: TextButton( onPressed: () { Navigator.pushNamed(context, '/forgot'); }, child: Text('Mot de passe oublié?'), ), ), const SizedBox(height: 24), // Bouton de connexion SizedBox( width: double.infinity, height: 50, child: ElevatedButton( onPressed: _isLoading ? null : _login, style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: _isLoading ? CircularProgressIndicator(color: Colors.white) : Text( 'Se connecter', style: TextStyle(fontSize: 16), ), ), ), const SizedBox(height: 24), // Lien d'inscription Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text("Vous n'avez pas de compte?"), TextButton( onPressed: () { Navigator.pushNamed(context, '/signup'); }, child: Text('S\'inscrire'), ), ], ), const SizedBox(height: 40), // Séparateur Container( width: double.infinity, height: 1, color: Colors.grey.shade300, ), const SizedBox(height: 40), Text( 'Ou connectez-vous avec', style: TextStyle(color: Colors.grey.shade600), ), const SizedBox(height: 20), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Column( children: [ // GOOGLE GestureDetector( onTap: () { // TODO: Implémenter la connexion Google _showErrorMessage( 'Connexion Google non implémentée', ); }, child: Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.black, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.grey.withValues(alpha: 0.3), spreadRadius: 1, blurRadius: 3, offset: Offset(0, 1), ), ], border: Border.all( color: Colors.grey.shade300, width: 1, ), ), child: Center( child: Image.asset( 'assets/icons/google.png', width: 24, height: 24, ), ), ), ), const SizedBox(height: 8), const Text('Google'), ], ), const SizedBox(width: 40), Column( children: [ // APPLE GestureDetector( onTap: () { // TODO: Implémenter la connexion Apple _showErrorMessage( 'Connexion Apple non implémentée', ); }, child: Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.black, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.grey.withValues(alpha: 0.3), spreadRadius: 1, blurRadius: 3, offset: Offset(0, 1), ), ], border: Border.all( color: Colors.grey.shade300, width: 1, ), ), child: Center( child: Image.asset( 'assets/icons/apple_white.png', width: 24, height: 24, color: Colors.white, ), ), ), ), const SizedBox(height: 8), const Text('Apple'), ], ), ], ), const SizedBox(height: 40), ], ), ), ), ), ), ); } }