Files
unionflow-client-quarkus-pr…/unionflow-mobile-apps/lib/features/members/presentation/widgets/edit_member_dialog.dart

442 lines
16 KiB
Dart

/// Dialogue de modification de membre
/// Formulaire complet pour modifier un membre existant
library edit_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 de modification de membre
class EditMemberDialog extends StatefulWidget {
final MembreCompletModel membre;
const EditMemberDialog({
super.key,
required this.membre,
});
@override
State<EditMemberDialog> createState() => _EditMemberDialogState();
}
class _EditMemberDialogState extends State<EditMemberDialog> {
final _formKey = GlobalKey<FormState>();
// Contrôleurs de texte
late final TextEditingController _nomController;
late final TextEditingController _prenomController;
late final TextEditingController _emailController;
late final TextEditingController _telephoneController;
late final TextEditingController _adresseController;
late final TextEditingController _villeController;
late final TextEditingController _codePostalController;
late final TextEditingController _regionController;
late final TextEditingController _paysController;
late final TextEditingController _professionController;
late final TextEditingController _nationaliteController;
// Valeurs sélectionnées
Genre? _selectedGenre;
DateTime? _dateNaissance;
StatutMembre? _selectedStatut;
@override
void initState() {
super.initState();
// Initialiser les contrôleurs avec les valeurs existantes
_nomController = TextEditingController(text: widget.membre.nom);
_prenomController = TextEditingController(text: widget.membre.prenom);
_emailController = TextEditingController(text: widget.membre.email);
_telephoneController = TextEditingController(text: widget.membre.telephone ?? '');
_adresseController = TextEditingController(text: widget.membre.adresse ?? '');
_villeController = TextEditingController(text: widget.membre.ville ?? '');
_codePostalController = TextEditingController(text: widget.membre.codePostal ?? '');
_regionController = TextEditingController(text: widget.membre.region ?? '');
_paysController = TextEditingController(text: widget.membre.pays ?? '');
_professionController = TextEditingController(text: widget.membre.profession ?? '');
_nationaliteController = TextEditingController(text: widget.membre.nationalite ?? '');
_selectedGenre = widget.membre.genre;
_dateNaissance = widget.membre.dateNaissance;
_selectedStatut = widget.membre.statut;
}
@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.edit, color: Colors.white),
const SizedBox(width: 12),
const Text(
'Modifier le 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),
// Statut
DropdownButtonFormField<StatutMembre>(
value: _selectedStatut,
decoration: const InputDecoration(
labelText: 'Statut *',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.info),
),
items: StatutMembre.values.map((statut) {
return DropdownMenuItem(
value: statut,
child: Text(_getStatutLabel(statut)),
);
}).toList(),
onChanged: (value) {
setState(() {
_selectedStatut = 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(),
),
),
],
),
),
),
),
// 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('Enregistrer'),
),
],
),
),
],
),
),
);
}
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';
}
}
String _getStatutLabel(StatutMembre statut) {
switch (statut) {
case StatutMembre.actif:
return 'Actif';
case StatutMembre.inactif:
return 'Inactif';
case StatutMembre.suspendu:
return 'Suspendu';
case StatutMembre.enAttente:
return 'En attente';
}
}
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 mis à jour
final membreUpdated = widget.membre.copyWith(
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(UpdateMembre(widget.membre.id!, membreUpdated));
// Fermer le dialogue
Navigator.pop(context);
// Afficher un message de succès
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Membre modifié avec succès'),
backgroundColor: Colors.green,
),
);
}
}
}