import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; import 'package:geosector_app/core/data/models/user_model.dart'; import 'custom_text_field.dart'; class UserForm extends StatefulWidget { final UserModel? user; final Function(UserModel)? onSubmit; final bool readOnly; final bool allowUsernameEdit; final bool allowSectNameEdit; const UserForm({ super.key, this.user, this.onSubmit, this.readOnly = false, this.allowUsernameEdit = false, this.allowSectNameEdit = false, }); @override State createState() => _UserFormState(); } class _UserFormState extends State { final _formKey = GlobalKey(); // Controllers late final TextEditingController _usernameController; late final TextEditingController _firstNameController; late final TextEditingController _nameController; late final TextEditingController _sectNameController; late final TextEditingController _phoneController; late final TextEditingController _mobileController; late final TextEditingController _emailController; late final TextEditingController _dateNaissanceController; late final TextEditingController _dateEmbaucheController; // Form values int _fkTitre = 1; // 1 = M., 2 = Mme DateTime? _dateNaissance; DateTime? _dateEmbauche; @override void initState() { super.initState(); // Initialize controllers with user data if available final user = widget.user; _usernameController = TextEditingController(text: user?.username ?? ''); _firstNameController = TextEditingController(text: user?.firstName ?? ''); _nameController = TextEditingController(text: user?.name ?? ''); _sectNameController = TextEditingController(text: user?.sectName ?? ''); _phoneController = TextEditingController(text: user?.phone ?? ''); _mobileController = TextEditingController(text: user?.mobile ?? ''); _emailController = TextEditingController(text: user?.email ?? ''); _dateNaissance = user?.dateNaissance; _dateEmbauche = user?.dateEmbauche; _dateNaissanceController = TextEditingController(text: _dateNaissance != null ? DateFormat('dd/MM/yyyy').format(_dateNaissance!) : ''); _dateEmbaucheController = TextEditingController(text: _dateEmbauche != null ? DateFormat('dd/MM/yyyy').format(_dateEmbauche!) : ''); _fkTitre = user?.fkTitre ?? 1; } @override void dispose() { _usernameController.dispose(); _firstNameController.dispose(); _nameController.dispose(); _sectNameController.dispose(); _phoneController.dispose(); _mobileController.dispose(); _emailController.dispose(); _dateNaissanceController.dispose(); _dateEmbaucheController.dispose(); super.dispose(); } // Validation conditionnelle pour name/sectName String? _validateNameOrSectName(String? value, bool isNameField) { final nameValue = _nameController.text.trim(); final sectNameValue = _sectNameController.text.trim(); // Si les deux sont vides if (nameValue.isEmpty && sectNameValue.isEmpty) { return isNameField ? "Veuillez renseigner soit le nom soit le nom de tournée" : "Veuillez renseigner soit le nom de tournée soit le nom"; } return null; // Validation OK si au moins un des deux est rempli } // Méthode simplifiée pour sélectionner une date void _selectDate(BuildContext context, bool isDateNaissance) { // Utiliser un bloc try-catch pour capturer toutes les erreurs possibles try { // Afficher le sélecteur de date sans spécifier de locale showDatePicker( context: context, initialDate: DateTime.now(), // Toujours utiliser la date actuelle firstDate: DateTime(1900), lastDate: DateTime.now(), // Ne pas spécifier de locale pour éviter les problèmes ).then((DateTime? picked) { // Vérifier si une date a été sélectionnée if (picked != null) { setState(() { // Mettre à jour la date et le texte du contrôleur if (isDateNaissance) { _dateNaissance = picked; _dateNaissanceController.text = DateFormat('dd/MM/yyyy').format(picked); } else { _dateEmbauche = picked; _dateEmbaucheController.text = DateFormat('dd/MM/yyyy').format(picked); } }); } }).catchError((error) { // Gérer les erreurs spécifiques au sélecteur de date debugPrint('Erreur lors de la sélection de la date: $error'); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Erreur lors de la sélection de la date'), backgroundColor: Colors.red, ), ); }); } catch (e) { // Gérer toutes les autres erreurs debugPrint('Exception lors de l\'affichage du sélecteur de date: $e'); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('Impossible d\'afficher le sélecteur de date'), backgroundColor: Colors.red, ), ); } } // Méthode publique pour valider et récupérer l'utilisateur UserModel? validateAndGetUser() { if (_formKey.currentState!.validate()) { return widget.user?.copyWith( username: _usernameController.text, firstName: _firstNameController.text, name: _nameController.text, sectName: _sectNameController.text, phone: _phoneController.text, mobile: _mobileController.text, email: _emailController.text, fkTitre: _fkTitre, dateNaissance: _dateNaissance, dateEmbauche: _dateEmbauche, ) ?? UserModel( id: 0, username: _usernameController.text, firstName: _firstNameController.text, name: _nameController.text, sectName: _sectNameController.text, phone: _phoneController.text, mobile: _mobileController.text, email: _emailController.text, fkTitre: _fkTitre, dateNaissance: _dateNaissance, dateEmbauche: _dateEmbauche, role: 1, createdAt: DateTime.now(), lastSyncedAt: DateTime.now(), ); } return null; } @override Widget build(BuildContext context) { final theme = Theme.of(context); final isWideScreen = MediaQuery.of(context).size.width > 900; return Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Ligne 1: Username et Email (si écran large) if (isWideScreen) Row( children: [ Expanded( child: CustomTextField( controller: _usernameController, label: "Nom d'utilisateur", readOnly: !widget.allowUsernameEdit, // Utiliser le paramètre prefixIcon: Icons.account_circle, isRequired: widget.allowUsernameEdit, validator: widget.allowUsernameEdit ? (value) { if (value == null || value.isEmpty) { return "Veuillez entrer le nom d'utilisateur"; } return null; } : null, ), ), const SizedBox(width: 16), Expanded( child: CustomTextField( controller: _emailController, label: "Email", keyboardType: TextInputType.emailAddress, readOnly: widget.readOnly, isRequired: true, // Email toujours obligatoire validator: (value) { if (value == null || value.isEmpty) { return "Veuillez entrer l'adresse email"; } if (!value.contains('@') || !value.contains('.')) { return "Veuillez entrer une adresse email valide"; } return null; }, ), ), ], ) else ...[ // Version mobile: Username seul CustomTextField( controller: _usernameController, label: "Nom d'utilisateur", readOnly: !widget.allowUsernameEdit, // Utiliser le paramètre prefixIcon: Icons.account_circle, isRequired: widget.allowUsernameEdit, // Obligatoire si éditable validator: widget.allowUsernameEdit ? (value) { if (value == null || value.isEmpty) { return "Veuillez entrer le nom d'utilisateur"; } return null; } : null, ), const SizedBox(height: 16), // Email seul en mobile CustomTextField( controller: _emailController, label: "Email", keyboardType: TextInputType.emailAddress, readOnly: widget.readOnly, isRequired: true, // Email toujours obligatoire validator: (value) { if (value == null || value.isEmpty) { return "Veuillez entrer l'adresse email"; } if (!value.contains('@') || !value.contains('.')) { return "Veuillez entrer une adresse email valide"; } return null; }, ), ], const SizedBox(height: 16), // Titre (M. ou Mme) Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Titre", style: theme.textTheme.titleSmall?.copyWith( fontWeight: FontWeight.w500, color: theme.colorScheme.onSurface, ), ), const SizedBox(height: 8), Row( children: [ _buildRadioOption( value: 1, label: 'M.', groupValue: _fkTitre, onChanged: widget.readOnly ? null : (value) { setState(() { _fkTitre = value!; }); }, ), const SizedBox(width: 40), _buildRadioOption( value: 2, label: 'Mme', groupValue: _fkTitre, onChanged: widget.readOnly ? null : (value) { setState(() { _fkTitre = value!; }); }, ), ], ), ], ), const SizedBox(height: 16), // Ligne 2: Prénom et Nom if (isWideScreen) Row( children: [ Expanded( child: CustomTextField( controller: _firstNameController, label: "Prénom", readOnly: widget.readOnly, ), ), const SizedBox(width: 16), Expanded( child: CustomTextField( controller: _nameController, label: "Nom", readOnly: widget.readOnly, validator: (value) => _validateNameOrSectName(value, true), onChanged: (value) { // Revalider sectName quand name change if (widget.allowSectNameEdit) { _formKey.currentState?.validate(); } }, ), ), ], ) else ...[ // Version mobile: Prénom et nom séparés CustomTextField( controller: _firstNameController, label: "Prénom", readOnly: widget.readOnly, ), const SizedBox(height: 16), CustomTextField( controller: _nameController, label: "Nom", readOnly: widget.readOnly, validator: (value) => _validateNameOrSectName(value, true), onChanged: (value) { // Revalider sectName quand name change if (widget.allowSectNameEdit) { _formKey.currentState?.validate(); } }, ), ], const SizedBox(height: 16), // Ligne 2.5: Nom de tournée (sectName) - uniquement si éditable if (widget.allowSectNameEdit) ...[ CustomTextField( controller: _sectNameController, label: "Nom de tournée", readOnly: widget.readOnly, validator: (value) => _validateNameOrSectName(value, false), onChanged: (value) { // Revalider name quand sectName change _formKey.currentState?.validate(); }, hintText: "Nom utilisé pour identifier la tournée", ), const SizedBox(height: 16), ], // Ligne 3: Téléphones (fixe et mobile) if (isWideScreen) Row( children: [ Expanded( child: CustomTextField( controller: _phoneController, label: "Téléphone fixe", keyboardType: TextInputType.phone, readOnly: widget.readOnly, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), ], validator: (value) { if (value != null && value.isNotEmpty && value.length < 10) { return "Le numéro doit contenir 10 chiffres"; } return null; }, ), ), const SizedBox(width: 16), Expanded( child: CustomTextField( controller: _mobileController, label: "Téléphone mobile", keyboardType: TextInputType.phone, readOnly: widget.readOnly, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), ], validator: (value) { if (value != null && value.isNotEmpty && value.length < 10) { return "Le numéro doit contenir 10 chiffres"; } return null; }, ), ), ], ) else ...[ // Version mobile: Téléphones séparés CustomTextField( controller: _phoneController, label: "Téléphone fixe", keyboardType: TextInputType.phone, readOnly: widget.readOnly, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), ], validator: (value) { if (value != null && value.isNotEmpty && value.length < 10) { return "Le numéro doit contenir 10 chiffres"; } return null; }, ), const SizedBox(height: 16), CustomTextField( controller: _mobileController, label: "Téléphone mobile", keyboardType: TextInputType.phone, readOnly: widget.readOnly, inputFormatters: [ FilteringTextInputFormatter.digitsOnly, LengthLimitingTextInputFormatter(10), ], validator: (value) { if (value != null && value.isNotEmpty && value.length < 10) { return "Le numéro doit contenir 10 chiffres"; } return null; }, ), ], const SizedBox(height: 16), // Ligne 4: Dates (naissance et embauche) if (isWideScreen) Row( children: [ Expanded( child: CustomTextField( controller: _dateNaissanceController, label: "Date de naissance", readOnly: true, onTap: widget.readOnly ? null : () => _selectDate(context, true), suffixIcon: Icon( Icons.calendar_today, color: theme.colorScheme.primary, ), ), ), const SizedBox(width: 16), Expanded( child: CustomTextField( controller: _dateEmbaucheController, label: "Date d'embauche", readOnly: true, onTap: widget.readOnly ? null : () => _selectDate(context, false), suffixIcon: Icon( Icons.calendar_today, color: theme.colorScheme.primary, ), ), ), ], ) else ...[ // Version mobile: Dates séparées CustomTextField( controller: _dateNaissanceController, label: "Date de naissance", readOnly: true, onTap: widget.readOnly ? null : () => _selectDate(context, true), suffixIcon: Icon( Icons.calendar_today, color: theme.colorScheme.primary, ), ), const SizedBox(height: 16), CustomTextField( controller: _dateEmbaucheController, label: "Date d'embauche", readOnly: true, onTap: widget.readOnly ? null : () => _selectDate(context, false), suffixIcon: Icon( Icons.calendar_today, color: theme.colorScheme.primary, ), ), ], const SizedBox(height: 16), ], ), ); } Widget _buildRadioOption({ required int value, required String label, required int groupValue, required Function(int?)? onChanged, }) { final theme = Theme.of(context); final isSelected = value == groupValue; return Row( children: [ Radio( value: value, groupValue: groupValue, onChanged: onChanged, activeColor: const Color(0xFF20335E), ), Text( label, style: theme.textTheme.bodyMedium?.copyWith( color: theme.colorScheme.onSurface, fontWeight: FontWeight.w500, ), ), ], ); } } // Exporter la classe State pour pouvoir l'utiliser avec GlobalKey typedef UserFormState = _UserFormState;