/// Dialogue d'ajout de membre /// Formulaire complet pour créer un nouveau membre library add_member_dialog; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; import '../../bloc/membres_bloc.dart'; import '../../bloc/membres_event.dart'; import '../../data/models/membre_complete_model.dart'; /// Dialogue d'ajout de membre class AddMemberDialog extends StatefulWidget { const AddMemberDialog({super.key}); @override State createState() => _AddMemberDialogState(); } class _AddMemberDialogState extends State { final _formKey = GlobalKey(); // Contrôleurs de texte final _nomController = TextEditingController(); final _prenomController = TextEditingController(); final _emailController = TextEditingController(); final _telephoneController = TextEditingController(); final _adresseController = TextEditingController(); final _villeController = TextEditingController(); final _codePostalController = TextEditingController(); final _regionController = TextEditingController(); final _paysController = TextEditingController(); final _professionController = TextEditingController(); final _nationaliteController = TextEditingController(); // Valeurs sélectionnées Genre? _selectedGenre; DateTime? _dateNaissance; StatutMembre _selectedStatut = StatutMembre.actif; @override void dispose() { _nomController.dispose(); _prenomController.dispose(); _emailController.dispose(); _telephoneController.dispose(); _adresseController.dispose(); _villeController.dispose(); _codePostalController.dispose(); _regionController.dispose(); _paysController.dispose(); _professionController.dispose(); _nationaliteController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return Dialog( child: Container( width: MediaQuery.of(context).size.width * 0.9, constraints: const BoxConstraints(maxHeight: 600), child: Column( mainAxisSize: MainAxisSize.min, children: [ // En-tête Container( padding: const EdgeInsets.all(16), decoration: const BoxDecoration( color: Color(0xFF6C5CE7), borderRadius: BorderRadius.only( topLeft: Radius.circular(4), topRight: Radius.circular(4), ), ), child: Row( children: [ const Icon(Icons.person_add, color: Colors.white), const SizedBox(width: 12), const Text( 'Ajouter un membre', style: TextStyle( color: Colors.white, fontSize: 18, fontWeight: FontWeight.bold, ), ), const Spacer(), IconButton( icon: const Icon(Icons.close, color: Colors.white), onPressed: () => Navigator.pop(context), ), ], ), ), // Formulaire Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(16), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Informations personnelles _buildSectionTitle('Informations personnelles'), const SizedBox(height: 12), TextFormField( controller: _nomController, decoration: const InputDecoration( labelText: 'Nom *', border: OutlineInputBorder(), prefixIcon: Icon(Icons.person), ), validator: (value) { if (value == null || value.isEmpty) { return 'Le nom est obligatoire'; } return null; }, ), const SizedBox(height: 12), TextFormField( controller: _prenomController, decoration: const InputDecoration( labelText: 'Prénom *', border: OutlineInputBorder(), prefixIcon: Icon(Icons.person_outline), ), validator: (value) { if (value == null || value.isEmpty) { return 'Le prénom est obligatoire'; } return null; }, ), const SizedBox(height: 12), TextFormField( controller: _emailController, decoration: const InputDecoration( labelText: 'Email *', border: OutlineInputBorder(), prefixIcon: Icon(Icons.email), ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value == null || value.isEmpty) { return 'L\'email est obligatoire'; } if (!value.contains('@')) { return 'Email invalide'; } return null; }, ), const SizedBox(height: 12), TextFormField( controller: _telephoneController, decoration: const InputDecoration( labelText: 'Téléphone', border: OutlineInputBorder(), prefixIcon: Icon(Icons.phone), ), keyboardType: TextInputType.phone, ), const SizedBox(height: 12), // Genre DropdownButtonFormField( value: _selectedGenre, decoration: const InputDecoration( labelText: 'Genre', border: OutlineInputBorder(), prefixIcon: Icon(Icons.wc), ), items: Genre.values.map((genre) { return DropdownMenuItem( value: genre, child: Text(_getGenreLabel(genre)), ); }).toList(), onChanged: (value) { setState(() { _selectedGenre = value; }); }, ), const SizedBox(height: 12), // Date de naissance InkWell( onTap: () => _selectDate(context), child: InputDecorator( decoration: const InputDecoration( labelText: 'Date de naissance', border: OutlineInputBorder(), prefixIcon: Icon(Icons.calendar_today), ), child: Text( _dateNaissance != null ? DateFormat('dd/MM/yyyy').format(_dateNaissance!) : 'Sélectionner une date', ), ), ), const SizedBox(height: 16), // Adresse _buildSectionTitle('Adresse'), const SizedBox(height: 12), TextFormField( controller: _adresseController, decoration: const InputDecoration( labelText: 'Adresse', border: OutlineInputBorder(), prefixIcon: Icon(Icons.home), ), maxLines: 2, ), const SizedBox(height: 12), Row( children: [ Expanded( child: TextFormField( controller: _villeController, decoration: const InputDecoration( labelText: 'Ville', border: OutlineInputBorder(), ), ), ), const SizedBox(width: 12), Expanded( child: TextFormField( controller: _codePostalController, decoration: const InputDecoration( labelText: 'Code postal', border: OutlineInputBorder(), ), ), ), ], ), const SizedBox(height: 12), TextFormField( controller: _regionController, decoration: const InputDecoration( labelText: 'Région', border: OutlineInputBorder(), ), ), const SizedBox(height: 12), TextFormField( controller: _paysController, decoration: const InputDecoration( labelText: 'Pays', border: OutlineInputBorder(), ), ), const SizedBox(height: 16), // Informations professionnelles _buildSectionTitle('Informations professionnelles'), const SizedBox(height: 12), TextFormField( controller: _professionController, decoration: const InputDecoration( labelText: 'Profession', border: OutlineInputBorder(), prefixIcon: Icon(Icons.work), ), ), const SizedBox(height: 12), TextFormField( controller: _nationaliteController, decoration: const InputDecoration( labelText: 'Nationalité', border: OutlineInputBorder(), prefixIcon: Icon(Icons.flag), ), ), ], ), ), ), ), // Boutons d'action Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey[100], border: Border(top: BorderSide(color: Colors.grey[300]!)), ), child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Annuler'), ), const SizedBox(width: 12), ElevatedButton( onPressed: _submitForm, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF6C5CE7), foregroundColor: Colors.white, ), child: const Text('Créer le membre'), ), ], ), ), ], ), ), ); } Widget _buildSectionTitle(String title) { return Text( title, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, color: Color(0xFF6C5CE7), ), ); } String _getGenreLabel(Genre genre) { switch (genre) { case Genre.homme: return 'Homme'; case Genre.femme: return 'Femme'; case Genre.autre: return 'Autre'; } } Future _selectDate(BuildContext context) async { final DateTime? picked = await showDatePicker( context: context, initialDate: _dateNaissance ?? DateTime.now().subtract(const Duration(days: 365 * 25)), firstDate: DateTime(1900), lastDate: DateTime.now(), ); if (picked != null && picked != _dateNaissance) { setState(() { _dateNaissance = picked; }); } } void _submitForm() { if (_formKey.currentState!.validate()) { // Créer le modèle de membre final membre = MembreCompletModel( nom: _nomController.text, prenom: _prenomController.text, email: _emailController.text, telephone: _telephoneController.text.isNotEmpty ? _telephoneController.text : null, dateNaissance: _dateNaissance, genre: _selectedGenre, adresse: _adresseController.text.isNotEmpty ? _adresseController.text : null, ville: _villeController.text.isNotEmpty ? _villeController.text : null, codePostal: _codePostalController.text.isNotEmpty ? _codePostalController.text : null, region: _regionController.text.isNotEmpty ? _regionController.text : null, pays: _paysController.text.isNotEmpty ? _paysController.text : null, profession: _professionController.text.isNotEmpty ? _professionController.text : null, nationalite: _nationaliteController.text.isNotEmpty ? _nationaliteController.text : null, statut: _selectedStatut, ); // Envoyer l'événement au BLoC context.read().add(CreateMembre(membre)); // Fermer le dialogue Navigator.pop(context); // Afficher un message de succès ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Membre créé avec succès'), backgroundColor: Colors.green, ), ); } } }