Files
2025-11-17 16:02:04 +00:00

404 lines
15 KiB
Dart

/// 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<AddMemberDialog> createState() => _AddMemberDialogState();
}
class _AddMemberDialogState extends State<AddMemberDialog> {
final _formKey = GlobalKey<FormState>();
// 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;
final 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<Genre>(
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<void> _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<MembresBloc>().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,
),
);
}
}
}