import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:youmazgestion/Components/app_bar.dart'; import 'package:youmazgestion/Components/appDrawer.dart'; import 'package:youmazgestion/Models/client.dart'; import 'package:youmazgestion/Models/produit.dart'; import 'package:youmazgestion/Services/productDatabase.dart'; class NouvelleCommandePage extends StatefulWidget { const NouvelleCommandePage({super.key}); @override _NouvelleCommandePageState createState() => _NouvelleCommandePageState(); } class _NouvelleCommandePageState extends State { final ProductDatabase _database = ProductDatabase.instance; final _formKey = GlobalKey(); // Informations client final TextEditingController _nomController = TextEditingController(); final TextEditingController _prenomController = TextEditingController(); final TextEditingController _emailController = TextEditingController(); final TextEditingController _telephoneController = TextEditingController(); final TextEditingController _adresseController = TextEditingController(); // Panier final List _products = []; final Map _quantites = {}; // productId -> quantity @override void initState() { super.initState(); _loadProducts(); } Future _loadProducts() async { final products = await _database.getProducts(); setState(() { _products.addAll(products); }); } @override Widget build(BuildContext context) { return Scaffold( appBar: const CustomAppBar(title: 'Nouvelle Commande'), drawer: CustomDrawer(), body: Column( children: [ // Header avec logo et titre Container( padding: const EdgeInsets.all(16.0), decoration: BoxDecoration( gradient: LinearGradient( colors: [Colors.blue.shade50, Colors.white], begin: Alignment.topCenter, end: Alignment.bottomCenter, ), ), child: Column( children: [ // Logo et titre Row( children: [ // Logo de l'entreprise Container( width: 50, height: 50, decoration: BoxDecoration( borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 4, offset: const Offset(0, 2), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(8), child: Image.asset( 'assets/logo.png', fit: BoxFit.cover, errorBuilder: (context, error, stackTrace) { return Container( decoration: BoxDecoration( color: Colors.blue.shade800, borderRadius: BorderRadius.circular(8), ), child: const Icon( Icons.shopping_cart, color: Colors.white, size: 30, ), ); }, ), ), ), const SizedBox(width: 12), const Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Nouvelle Commande', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, color: Colors.black87, ), ), Text( 'Créez une nouvelle commande pour un client', style: TextStyle( fontSize: 14, color: Colors.grey, ), ), ], ), ), ], ), ], ), ), // Contenu principal Expanded( child: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ _buildClientForm(), const SizedBox(height: 20), _buildProductList(), const SizedBox(height: 20), _buildCartSection(), const SizedBox(height: 20), _buildTotalSection(), const SizedBox(height: 20), _buildSubmitButton(), ], ), ), ), ], ), ); } Widget _buildClientForm() { return Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Form( key: _formKey, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Informations Client', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 16), TextFormField( controller: _nomController, decoration: InputDecoration( labelText: 'Nom', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), filled: true, fillColor: Colors.white, ), validator: (value) { if (value == null || value.isEmpty) { return 'Veuillez entrer un nom'; } return null; }, ), const SizedBox(height: 12), TextFormField( controller: _prenomController, decoration: InputDecoration( labelText: 'Prénom', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), filled: true, fillColor: Colors.white, ), validator: (value) { if (value == null || value.isEmpty) { return 'Veuillez entrer un prénom'; } return null; }, ), const SizedBox(height: 12), TextFormField( controller: _emailController, decoration: InputDecoration( labelText: 'Email', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), filled: true, fillColor: Colors.white, ), keyboardType: TextInputType.emailAddress, validator: (value) { if (value == null || value.isEmpty) { return 'Veuillez entrer un email'; } if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) { return 'Veuillez entrer un email valide'; } return null; }, ), const SizedBox(height: 12), TextFormField( controller: _telephoneController, decoration: InputDecoration( labelText: 'Téléphone', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), filled: true, fillColor: Colors.white, ), keyboardType: TextInputType.phone, validator: (value) { if (value == null || value.isEmpty) { return 'Veuillez entrer un numéro de téléphone'; } return null; }, ), const SizedBox(height: 12), TextFormField( controller: _adresseController, decoration: InputDecoration( labelText: 'Adresse de livraison', border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), ), filled: true, fillColor: Colors.white, ), maxLines: 2, validator: (value) { if (value == null || value.isEmpty) { return 'Veuillez entrer une adresse'; } return null; }, ), ], ), ), ), ); } Widget _buildProductList() { return Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Produits Disponibles', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 16), _products.isEmpty ? const Center(child: CircularProgressIndicator()) : ListView.builder( shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), itemCount: _products.length, itemBuilder: (context, index) { final product = _products[index]; final quantity = _quantites[product.id] ?? 0; return Card( margin: const EdgeInsets.symmetric(vertical: 8), elevation: 2, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: ListTile( contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), leading: Container( width: 50, height: 50, decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(8), ), child: const Icon(Icons.shopping_bag, color: Colors.blue), ), title: Text( product.name, style: const TextStyle(fontWeight: FontWeight.bold), ), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 4), Text( '${product.price.toStringAsFixed(2)} DA', style: TextStyle( color: Colors.green.shade700, fontWeight: FontWeight.w600, ), ), if (product.stock != null) Text( 'Stock: ${product.stock}', style: TextStyle( fontSize: 12, color: Colors.grey.shade600, ), ), ], ), trailing: Container( decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(20), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ IconButton( icon: const Icon(Icons.remove, size: 18), onPressed: () { if (quantity > 0) { setState(() { _quantites[product.id!] = quantity - 1; }); } }, ), Text( quantity.toString(), style: const TextStyle(fontWeight: FontWeight.bold), ), IconButton( icon: const Icon(Icons.add, size: 18), onPressed: () { if (product.stock == null || quantity < product.stock!) { setState(() { _quantites[product.id!] = quantity + 1; }); } else { Get.snackbar( 'Stock insuffisant', 'Quantité demandée non disponible', snackPosition: SnackPosition.BOTTOM, ); } }, ), ], ), ), ), ); }, ), ], ), ), ); } Widget _buildCartSection() { final itemsInCart = _quantites.entries.where((e) => e.value > 0).toList(); if (itemsInCart.isEmpty) { return Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: const Padding( padding: EdgeInsets.all(16.0), child: Center( child: Text( 'Votre panier est vide', style: TextStyle(color: Colors.grey), ), ), ), ); } return Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'Votre Panier', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), const SizedBox(height: 16), ...itemsInCart.map((entry) { final product = _products.firstWhere((p) => p.id == entry.key); return Card( margin: const EdgeInsets.only(bottom: 8), elevation: 1, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), child: ListTile( contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 8, ), leading: Container( width: 40, height: 40, decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(8), ), child: const Icon(Icons.shopping_bag, size: 20), ), title: Text(product.name), subtitle: Text('${entry.value} x ${product.price.toStringAsFixed(2)} DA'), trailing: Text( '${(entry.value * product.price).toStringAsFixed(2)} DA', style: TextStyle( fontWeight: FontWeight.bold, color: Colors.blue.shade800, ), ), ), ); }), ], ), ), ); } Widget _buildTotalSection() { double total = 0; _quantites.forEach((productId, quantity) { final product = _products.firstWhere((p) => p.id == productId); total += quantity * product.price; }); return Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), child: Padding( padding: const EdgeInsets.all(16.0), child: Container( decoration: BoxDecoration( color: Colors.blue.shade50, borderRadius: BorderRadius.circular(8), ), padding: const EdgeInsets.all(12), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'Total:', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), ), Text( '${total.toStringAsFixed(2)} DA', style: const TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: Colors.green, ), ), ], ), ), ), ); } Widget _buildSubmitButton() { return ElevatedButton( style: ElevatedButton.styleFrom( padding: const EdgeInsets.symmetric(vertical: 16), backgroundColor: Colors.blue.shade600, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), elevation: 4, ), onPressed: _submitOrder, child: const Text( 'Valider la Commande', style: TextStyle(fontSize: 16, color: Colors.white), ), ); } Future _submitOrder() async { if (!_formKey.currentState!.validate()) { return; } final itemsInCart = _quantites.entries.where((e) => e.value > 0).toList(); if (itemsInCart.isEmpty) { Get.snackbar( 'Panier vide', 'Veuillez ajouter des produits à votre commande', snackPosition: SnackPosition.BOTTOM, ); return; } // Créer le client final client = Client( nom: _nomController.text, prenom: _prenomController.text, email: _emailController.text, telephone: _telephoneController.text, adresse: _adresseController.text, dateCreation: DateTime.now(), ); // Calculer le total et préparer les détails double total = 0; final details = []; for (final entry in itemsInCart) { final product = _products.firstWhere((p) => p.id == entry.key); total += entry.value * product.price; details.add(DetailCommande( commandeId: 0, // Valeur temporaire, sera remplacée dans la transaction produitId: product.id!, quantite: entry.value, prixUnitaire: product.price, sousTotal: entry.value * product.price, )); } // Créer la commande final commande = Commande( clientId: 0, // sera mis à jour après création du client dateCommande: DateTime.now(), statut: StatutCommande.enAttente, montantTotal: total, notes: 'Commande passée via l\'application', ); try { // Enregistrer la commande dans la base de données await _database.createCommandeComplete(client, commande, details); Get.snackbar( 'Succès', 'Votre commande a été enregistrée', snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.green, colorText: Colors.white, ); // Réinitialiser le formulaire _formKey.currentState!.reset(); setState(() { _quantites.clear(); }); } catch (e) { Get.snackbar( 'Erreur', 'Une erreur est survenue lors de l\'enregistrement de la commande: ${e.toString()}', snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red, colorText: Colors.white, ); } } @override void dispose() { _nomController.dispose(); _prenomController.dispose(); _emailController.dispose(); _telephoneController.dispose(); _adresseController.dispose(); super.dispose(); } }