import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:youmazgestion/Models/client.dart'; import '../Services/stock_managementDatabase.dart'; class ClientFormController extends GetxController { final _formKey = GlobalKey(); // Controllers pour les champs final _nomController = TextEditingController(); final _prenomController = TextEditingController(); final _emailController = TextEditingController(); final _telephoneController = TextEditingController(); final _adresseController = TextEditingController(); // Variables observables pour la recherche var suggestedClients = [].obs; var isSearching = false.obs; var selectedClient = Rxn(); @override void onClose() { _nomController.dispose(); _prenomController.dispose(); _emailController.dispose(); _telephoneController.dispose(); _adresseController.dispose(); super.onClose(); } // Méthode pour rechercher les clients existants Future searchClients(String query) async { if (query.length < 2) { suggestedClients.clear(); return; } isSearching.value = true; try { final clients = await AppDatabase.instance.suggestClients(query); suggestedClients.value = clients; } catch (e) { print("Erreur recherche clients: $e"); suggestedClients.clear(); } finally { isSearching.value = false; } } // Méthode pour remplir automatiquement le formulaire void fillFormWithClient(Client client) { selectedClient.value = client; _nomController.text = client.nom; _prenomController.text = client.prenom; _emailController.text = client.email; _telephoneController.text = client.telephone; _adresseController.text = client.adresse ?? ''; suggestedClients.clear(); } // Méthode pour vider le formulaire void clearForm() { selectedClient.value = null; _nomController.clear(); _prenomController.clear(); _emailController.clear(); _telephoneController.clear(); _adresseController.clear(); suggestedClients.clear(); } // Méthode pour valider et soumettre Future submitForm() async { if (!_formKey.currentState!.validate()) return; try { Client clientToUse; if (selectedClient.value != null) { // Utiliser le client existant clientToUse = selectedClient.value!; } else { // Créer un nouveau client final newClient = Client( nom: _nomController.text.trim(), prenom: _prenomController.text.trim(), email: _emailController.text.trim(), telephone: _telephoneController.text.trim(), adresse: _adresseController.text.trim().isEmpty ? null : _adresseController.text.trim(), dateCreation: DateTime.now(), ); clientToUse = await AppDatabase.instance.createOrGetClient(newClient); } // Procéder avec la commande Get.back(); _submitOrderWithClient(clientToUse); } catch (e) { Get.snackbar( 'Erreur', 'Erreur lors de la création/récupération du client: $e', backgroundColor: Colors.red.shade100, colorText: Colors.red.shade800, ); } } void _submitOrderWithClient(Client client) { // Votre logique existante pour soumettre la commande // avec le client fourni } } // Widget pour le formulaire avec auto-completion // ignore: unused_element void _showClientFormDialog() { final controller = Get.put(ClientFormController()); Get.dialog( AlertDialog( title: Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: Colors.blue.shade100, borderRadius: BorderRadius.circular(8), ), child: Icon(Icons.person_add, color: Colors.blue.shade700), ), const SizedBox(width: 12), const Text('Informations Client'), const Spacer(), // Bouton pour vider le formulaire IconButton( onPressed: controller.clearForm, icon: const Icon(Icons.clear), tooltip: 'Vider le formulaire', ), ], ), content: Container( width: 600, constraints: const BoxConstraints(maxHeight: 700), child: SingleChildScrollView( child: Form( key: controller._formKey, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ // Section de recherche rapide _buildSearchSection(controller), const SizedBox(height: 16), // Indicateur client sélectionné Obx(() { if (controller.selectedClient.value != null) { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: Colors.green.shade50, border: Border.all(color: Colors.green.shade200), borderRadius: BorderRadius.circular(8), ), child: Row( children: [ Icon(Icons.check_circle, color: Colors.green.shade600), const SizedBox(width: 8), Expanded( child: Text( 'Client existant sélectionné: ${controller.selectedClient.value!.nomComplet}', style: TextStyle( color: Colors.green.shade800, fontWeight: FontWeight.w500, ), ), ), ], ), ); } return const SizedBox.shrink(); }), const SizedBox(height: 12), // Champs du formulaire _buildTextFormField( controller: controller._nomController, label: 'Nom', validator: (value) => value?.isEmpty ?? true ? 'Veuillez entrer un nom' : null, onChanged: (value) { if (controller.selectedClient.value != null) { controller.selectedClient.value = null; } }, ), const SizedBox(height: 12), _buildTextFormField( controller: controller._prenomController, label: 'Prénom', validator: (value) => value?.isEmpty ?? true ? 'Veuillez entrer un prénom' : null, onChanged: (value) { if (controller.selectedClient.value != null) { controller.selectedClient.value = null; } }, ), const SizedBox(height: 12), _buildTextFormField( controller: controller._emailController, label: 'Email', keyboardType: TextInputType.emailAddress, validator: (value) { // if (value?.isEmpty ?? true) return 'Veuillez entrer un email'; if (value?.isEmpty ?? true) return null; if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$') .hasMatch(value!)) { return 'Email invalide'; } return null; }, onChanged: (value) { if (controller.selectedClient.value != null) { controller.selectedClient.value = null; } // Recherche automatique par email controller.searchClients(value); }, ), const SizedBox(height: 12), _buildTextFormField( controller: controller._telephoneController, label: 'Téléphone', keyboardType: TextInputType.phone, validator: (value) => value?.isEmpty ?? true ? 'Veuillez entrer un téléphone' : null, onChanged: (value) { if (controller.selectedClient.value != null) { controller.selectedClient.value = null; } // Recherche automatique par téléphone controller.searchClients(value); }, ), const SizedBox(height: 12), _buildTextFormField( controller: controller._adresseController, label: 'Adresse', maxLines: 2, validator: (value) => value?.isEmpty ?? true ? 'Veuillez entrer une adresse' : null, onChanged: (value) { if (controller.selectedClient.value != null) { controller.selectedClient.value = null; } }, ), const SizedBox(height: 12), _buildCommercialDropdown(), // Liste des suggestions Obx(() { if (controller.isSearching.value) { return const Padding( padding: EdgeInsets.all(16), child: Center(child: CircularProgressIndicator()), ); } if (controller.suggestedClients.isEmpty) { return const SizedBox.shrink(); } return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Divider(), Text( 'Clients trouvés:', style: TextStyle( fontWeight: FontWeight.w600, color: Colors.blue.shade700, ), ), const SizedBox(height: 8), ...controller.suggestedClients.map( (client) => _buildClientSuggestionTile(client, controller), ), ], ); }), ], ), ), ), ), actions: [ TextButton( onPressed: () => Get.back(), child: const Text('Annuler'), ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.blue.shade800, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), ), onPressed: controller.submitForm, child: const Text('Valider la commande'), ), ], ), ); } // Widget pour la section de recherche Widget _buildSearchSection(ClientFormController controller) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Recherche rapide', style: TextStyle( fontWeight: FontWeight.w600, color: Colors.blue.shade700, ), ), const SizedBox(height: 8), TextFormField( decoration: InputDecoration( labelText: 'Rechercher un client existant', hintText: 'Nom, prénom, email ou téléphone...', prefixIcon: const Icon(Icons.search), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), filled: true, fillColor: Colors.grey.shade50, ), onChanged: controller.searchClients, ), ], ); } // Widget pour afficher une suggestion de client Widget _buildClientSuggestionTile( Client client, ClientFormController controller) { return Card( margin: const EdgeInsets.only(bottom: 8), child: ListTile( leading: CircleAvatar( backgroundColor: Colors.blue.shade100, child: Icon(Icons.person, color: Colors.blue.shade700), ), title: Text( client.nomComplet, style: const TextStyle(fontWeight: FontWeight.w500), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('📧 ${client.email}'), Text('📞 ${client.telephone}'), if (client.adresse != null && client.adresse!.isNotEmpty) Text('📍 ${client.adresse}'), ], ), trailing: ElevatedButton( onPressed: () => controller.fillFormWithClient(client), style: ElevatedButton.styleFrom( backgroundColor: Colors.green, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), ), child: const Text('Utiliser'), ), isThreeLine: true, ), ); } // Widget helper pour les champs de texte Widget _buildTextFormField({ required TextEditingController controller, required String label, TextInputType? keyboardType, String? Function(String?)? validator, int maxLines = 1, void Function(String)? onChanged, }) { return TextFormField( controller: controller, decoration: InputDecoration( labelText: label, border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), filled: true, fillColor: Colors.grey.shade50, ), keyboardType: keyboardType, validator: validator, maxLines: maxLines, onChanged: onChanged, ); } // Votre méthode _buildCommercialDropdown existante Widget _buildCommercialDropdown() { // Votre implémentation existante return Container(); // Remplacez par votre code existant }