import 'package:flutter/material.dart'; import 'package:firebase_auth/firebase_auth.dart'; import 'package:cloud_firestore/cloud_firestore.dart'; class PageInscription extends StatefulWidget { const PageInscription({super.key}); @override State createState() => _PageInscriptionState(); } class _PageInscriptionState extends State with TickerProviderStateMixin { final TextEditingController nomController = TextEditingController(); final TextEditingController prenomController = TextEditingController(); final TextEditingController telController = TextEditingController(); final TextEditingController emailController = TextEditingController(); final TextEditingController passwordController = TextEditingController(); final TextEditingController confirmPasswordController = TextEditingController(); final FirebaseAuth _auth = FirebaseAuth.instance; final FirebaseFirestore _firestore = FirebaseFirestore.instance; String? selectedProfil = 'patient'; bool _isLoading = false; bool _obscurePassword = true; bool _obscureConfirmPassword = true; bool _acceptTerms = false; late AnimationController _animationController; late Animation _fadeAnimation; @override void initState() { super.initState(); _animationController = AnimationController( duration: const Duration(milliseconds: 1200), vsync: this, ); _fadeAnimation = Tween(begin: 0.0, end: 1.0).animate( CurvedAnimation(parent: _animationController, curve: Curves.easeInOut), ); _animationController.forward(); } @override void dispose() { _animationController.dispose(); super.dispose(); } bool _validateForm() { if (nomController.text.trim().isEmpty || prenomController.text.trim().isEmpty || telController.text.trim().isEmpty || emailController.text.trim().isEmpty || passwordController.text.trim().isEmpty || confirmPasswordController.text.trim().isEmpty) { _showSnackBar('Veuillez remplir tous les champs', Colors.orange); return false; } if (passwordController.text != confirmPasswordController.text) { _showSnackBar('Les mots de passe ne correspondent pas', Colors.red); return false; } if (passwordController.text.length < 6) { _showSnackBar( 'Le mot de passe doit contenir au moins 6 caractères', Colors.orange); return false; } if (!_acceptTerms) { _showSnackBar( 'Veuillez accepter les conditions d\'utilisation', Colors.orange); return false; } return true; } void _showSnackBar(String message, Color backgroundColor) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: [ Icon( backgroundColor == Colors.red ? Icons.error_outline : Icons.warning_amber_outlined, color: Colors.white, ), const SizedBox(width: 8), Expanded(child: Text(message)), ], ), backgroundColor: backgroundColor, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), ); } Future _creerCompte() async { if (!_validateForm()) return; setState(() { _isLoading = true; }); try { UserCredential userCredential = await _auth.createUserWithEmailAndPassword( email: emailController.text.trim(), password: passwordController.text.trim(), ); User? user = userCredential.user; await _firestore.collection('users').doc(user!.uid).set({ 'nom': nomController.text.trim(), 'prenom': prenomController.text.trim(), 'telephone': telController.text.trim(), 'email': emailController.text.trim(), 'profil': selectedProfil, 'uid': user.uid, 'dateCreation': FieldValue.serverTimestamp(), }); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: const Row( children: [ Icon(Icons.check_circle, color: Colors.white), SizedBox(width: 8), Text('Compte créé avec succès !'), ], ), backgroundColor: Colors.green, behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), ); Navigator.pop(context); } on FirebaseAuthException catch (e) { String message = 'Une erreur est survenue.'; if (e.code == 'email-already-in-use') { message = 'Cet email est déjà utilisé.'; } else if (e.code == 'weak-password') { message = 'Le mot de passe est trop faible.'; } else if (e.code == 'invalid-email') { message = 'Format d\'email invalide.'; } _showSnackBar(message, Colors.red); } finally { setState(() { _isLoading = false; }); } } Widget _buildTextField({ required TextEditingController controller, required String label, required String hint, required IconData icon, TextInputType? keyboardType, bool obscureText = false, Widget? suffixIcon, }) { return Container( margin: const EdgeInsets.only(bottom: 16), decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(15), border: Border.all( color: Colors.grey.shade200, width: 1, ), ), child: TextField( controller: controller, keyboardType: keyboardType, obscureText: obscureText, decoration: InputDecoration( labelText: label, hintText: hint, prefixIcon: Container( margin: const EdgeInsets.all(12), padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFF4A90E2).withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon( icon, color: const Color(0xFF4A90E2), size: 20, ), ), suffixIcon: suffixIcon, border: InputBorder.none, labelStyle: TextStyle( color: Colors.grey.shade600, fontSize: 16, ), hintStyle: TextStyle( color: Colors.grey.shade400, fontSize: 14, ), ), ), ); } @override Widget build(BuildContext context) { return Scaffold( body: Container( decoration: const BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFF4A90E2), Color(0xFF2E7D82), Color(0xFF1B5E62), ], ), ), child: SafeArea( child: SingleChildScrollView( child: FadeTransition( opacity: _fadeAnimation, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 24.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ const SizedBox(height: 20), // Header avec bouton retour Row( children: [ Container( decoration: BoxDecoration( color: Colors.white.withOpacity(0.15), borderRadius: BorderRadius.circular(12), ), child: IconButton( onPressed: () => Navigator.pop(context), icon: const Icon( Icons.arrow_back_ios_new, color: Colors.white, ), ), ), const Expanded( child: Text( 'Créer un compte', style: TextStyle( fontSize: 24, color: Colors.white, fontWeight: FontWeight.w600, ), textAlign: TextAlign.center, ), ), const SizedBox(width: 48), ], ), const SizedBox(height: 30), // Logo et titre Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white.withOpacity(0.15), borderRadius: BorderRadius.circular(20), border: Border.all( color: Colors.white.withOpacity(0.2), width: 1, ), ), child: Column( children: [ Container( height: 70, width: 70, decoration: BoxDecoration( color: Colors.white.withOpacity(0.15), shape: BoxShape.circle, border: Border.all( color: Colors.white.withOpacity(0.3), width: 2, ), ), child: const Icon( Icons.person_add_outlined, size: 35, color: Colors.white, ), ), const SizedBox(height: 12), const Text( 'Rejoignez TuberculoScan', style: TextStyle( fontSize: 24, color: Colors.white, fontWeight: FontWeight.bold, letterSpacing: 1.2, ), textAlign: TextAlign.center, ), const SizedBox(height: 8), const Text( 'Créez votre compte pour accéder au diagnostic', style: TextStyle( fontSize: 14, color: Colors.white70, fontWeight: FontWeight.w300, ), textAlign: TextAlign.center, ), ], ), ), const SizedBox(height: 30), // Formulaire d'inscription Container( padding: const EdgeInsets.all(24), decoration: BoxDecoration( color: Colors.white.withOpacity(0.95), borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 20, offset: const Offset(0, 8), ), ], ), child: Column( children: [ // Nom et Prénom Row( children: [ Expanded( child: _buildTextField( controller: nomController, label: 'Nom', hint: 'Votre nom', icon: Icons.person_outline, ), ), const SizedBox(width: 12), Expanded( child: _buildTextField( controller: prenomController, label: 'Prénom', hint: 'Votre prénom', icon: Icons.person_outline, ), ), ], ), // Téléphone _buildTextField( controller: telController, label: 'Téléphone', hint: '+229 XX XX XX XX', icon: Icons.phone_outlined, keyboardType: TextInputType.phone, ), // Email _buildTextField( controller: emailController, label: 'Email', hint: 'votre.email@exemple.com', icon: Icons.email_outlined, keyboardType: TextInputType.emailAddress, ), // Mot de passe _buildTextField( controller: passwordController, label: 'Mot de passe', hint: 'Minimum 6 caractères', icon: Icons.lock_outline, obscureText: _obscurePassword, suffixIcon: IconButton( onPressed: () { setState(() { _obscurePassword = !_obscurePassword; }); }, icon: Icon( _obscurePassword ? Icons.visibility_off_outlined : Icons.visibility_outlined, color: Colors.grey.shade600, ), ), ), // Confirmer mot de passe _buildTextField( controller: confirmPasswordController, label: 'Confirmer le mot de passe', hint: 'Répétez le mot de passe', icon: Icons.lock_outline, obscureText: _obscureConfirmPassword, suffixIcon: IconButton( onPressed: () { setState(() { _obscureConfirmPassword = !_obscureConfirmPassword; }); }, icon: Icon( _obscureConfirmPassword ? Icons.visibility_off_outlined : Icons.visibility_outlined, color: Colors.grey.shade600, ), ), ), // Dropdown Profil Container( decoration: BoxDecoration( color: Colors.grey.shade50, borderRadius: BorderRadius.circular(15), border: Border.all( color: Colors.grey.shade200, width: 1, ), ), child: DropdownButtonFormField( value: selectedProfil, items: [ DropdownMenuItem( value: 'patient', child: Row( children: [ Icon(Icons.person, color: Colors.grey.shade600, size: 20), const SizedBox(width: 12), const Text('Patient'), ], ), ), DropdownMenuItem( value: 'clinique', child: Row( children: [ Icon(Icons.local_hospital, color: Colors.grey.shade600, size: 20), const SizedBox(width: 12), const Text('Professionnel de santé'), ], ), ), ], onChanged: (value) { setState(() { selectedProfil = value; }); }, decoration: InputDecoration( labelText: 'Type de profil', prefixIcon: Container( margin: const EdgeInsets.all(12), padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFF4A90E2) .withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.account_circle_outlined, color: Color(0xFF4A90E2), size: 20, ), ), border: InputBorder.none, labelStyle: TextStyle( color: Colors.grey.shade600, fontSize: 16, ), ), ), ), const SizedBox(height: 20), // Accepter les conditions Row( children: [ Checkbox( value: _acceptTerms, onChanged: (value) { setState(() { _acceptTerms = value ?? false; }); }, activeColor: const Color(0xFF00E676), ), Expanded( child: Text.rich( TextSpan( text: 'J\'accepte les ', style: TextStyle( color: Colors.grey.shade600, fontSize: 14, ), children: [ TextSpan( text: 'conditions d\'utilisation', style: TextStyle( color: const Color(0xFF4A90E2), fontWeight: FontWeight.w500, decoration: TextDecoration.underline, ), ), TextSpan( text: ' et la ', style: TextStyle( color: Colors.grey.shade600, ), ), TextSpan( text: 'politique de confidentialité', style: TextStyle( color: const Color(0xFF4A90E2), fontWeight: FontWeight.w500, decoration: TextDecoration.underline, ), ), ], ), ), ), ], ), const SizedBox(height: 30), // Bouton créer un compte Container( height: 55, width: double.infinity, decoration: BoxDecoration( gradient: const LinearGradient( colors: [ Color(0xFF00E676), Color(0xFF00C853), ], ), borderRadius: BorderRadius.circular(15), boxShadow: [ BoxShadow( color: const Color(0xFF00E676).withOpacity(0.4), blurRadius: 15, offset: const Offset(0, 5), ), ], ), child: ElevatedButton( onPressed: _isLoading ? null : _creerCompte, style: ElevatedButton.styleFrom( backgroundColor: Colors.transparent, shadowColor: Colors.transparent, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(15), ), ), child: _isLoading ? const SizedBox( height: 20, width: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2, ), ) : const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.person_add_rounded, color: Colors.white, size: 20, ), SizedBox(width: 8), Text( 'Créer mon compte', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w600, ), ), ], ), ), ), ], ), ), const SizedBox(height: 30), // Lien vers connexion Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), borderRadius: BorderRadius.circular(15), border: Border.all( color: Colors.white.withOpacity(0.2), width: 1, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( "Vous avez déjà un compte? ", style: TextStyle( color: Colors.white.withOpacity(0.8), fontSize: 14, ), ), TextButton( onPressed: () => Navigator.pop(context), child: const Text( 'Se connecter', style: TextStyle( color: Color(0xFF00E676), fontSize: 14, fontWeight: FontWeight.w600, ), ), ), ], ), ), const SizedBox(height: 30), ], ), ), ), ), ), ), ); } }