import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../blocs/auth/auth_bloc.dart'; import '../blocs/auth/auth_event.dart'; import '../blocs/auth/auth_state.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(); bool _obscurePassword = true; @override void dispose() { _emailController.dispose(); _passwordController.dispose(); super.dispose(); } 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; } String? _validatePassword(String? value) { if (value == null || value.isEmpty) { return 'Mot de passe requis'; } return null; } void _login(BuildContext context) { if (!_formKey.currentState!.validate()) { return; } context.read().add( AuthSignInRequested( email: _emailController.text.trim(), password: _passwordController.text, ), ); } @override Widget build(BuildContext context) { return Scaffold( body: BlocConsumer( listener: (context, state) { if (state is AuthAuthenticated) { Navigator.pushReplacementNamed(context, '/home'); } else if (state is AuthError) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.message), backgroundColor: Colors.red, ), ); } }, builder: (context, state) { final isLoading = state is AuthLoading; return 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), const Text( 'Travel Mate', style: TextStyle( fontSize: 28, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 12), const Text( 'Connectez-vous pour continuer', style: TextStyle(fontSize: 16, color: Colors.grey), ), const SizedBox(height: 32), // Email TextFormField( controller: _emailController, validator: _validateEmail, keyboardType: TextInputType.emailAddress, decoration: const InputDecoration( labelText: 'Email', border: OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(12)), ), prefixIcon: Icon(Icons.email), ), ), const SizedBox(height: 16), // Password TextFormField( controller: _passwordController, validator: _validatePassword, obscureText: _obscurePassword, decoration: InputDecoration( labelText: 'Mot de passe', border: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(12)), ), prefixIcon: const Icon(Icons.lock), suffixIcon: IconButton( icon: Icon( _obscurePassword ? Icons.visibility : Icons.visibility_off, ), onPressed: () { setState(() { _obscurePassword = !_obscurePassword; }); }, ), ), ), const SizedBox(height: 8), // Forgot password Align( alignment: Alignment.centerRight, child: TextButton( onPressed: () { Navigator.pushNamed(context, '/forgot'); }, child: const Text('Mot de passe oubliƩ?'), ), ), const SizedBox(height: 24), // Login button SizedBox( width: double.infinity, height: 50, child: ElevatedButton( onPressed: isLoading ? null : () => _login(context), style: ElevatedButton.styleFrom( shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: isLoading ? const CircularProgressIndicator( color: Colors.white, ) : const Text( 'Se connecter', style: TextStyle(fontSize: 16), ), ), ), const SizedBox(height: 24), // Sign up link Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text("Vous n'avez pas de compte?"), TextButton( onPressed: () { Navigator.pushNamed(context, '/signup'); }, child: const Text('S\'inscrire'), ), ], ), const SizedBox(height: 40), // Divider Container( width: double.infinity, height: 1, color: Colors.grey.shade300, ), const SizedBox(height: 40), const Text( 'Ou connectez-vous avec', style: TextStyle(color: Colors.grey), ), const SizedBox(height: 20), // Social login buttons Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // Google Column( children: [ GestureDetector( onTap: isLoading ? null : () { context .read() .add(AuthGoogleSignInRequested()); }, 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: const 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), // Apple Column( children: [ GestureDetector( onTap: isLoading ? null : () { context .read() .add(AuthAppleSignInRequested()); }, 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: const 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), ], ), ), ), ), ); }, ), ); } }