import 'package:geosector_app/app.dart'; // Pour accéder aux instances globales import 'package:flutter/material.dart'; import 'package:geosector_app/core/theme/app_theme.dart'; import 'package:geosector_app/core/constants/app_keys.dart'; import 'package:geosector_app/presentation/widgets/passages/passages_list_widget.dart'; import 'package:geosector_app/presentation/widgets/charts/charts.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:geosector_app/core/data/models/passage_model.dart'; class UserDashboardHomePage extends StatefulWidget { const UserDashboardHomePage({super.key}); @override State createState() => _UserDashboardHomePageState(); } class _UserDashboardHomePageState extends State { // Formater une date au format JJ/MM/YYYY String _formatDate(DateTime date) { return '${date.day.toString().padLeft(2, '0')}/${date.month.toString().padLeft(2, '0')}/${date.year}'; } @override Widget build(BuildContext context) { final theme = Theme.of(context); final size = MediaQuery.of(context).size; final isDesktop = size.width > 900; return Scaffold( backgroundColor: Colors.transparent, body: SafeArea( child: SingleChildScrollView( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Builder(builder: (context) { // Récupérer l'opération actuelle final operation = userRepository.getCurrentOperation(); if (operation != null) { return Text( '${operation.name} (${_formatDate(operation.dateDebut)}-${_formatDate(operation.dateFin)})', style: TextStyle( fontSize: AppTheme.r(context, 20), fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), ); } else { return Text( 'Tableau de bord', style: TextStyle( fontSize: AppTheme.r(context, 20), fontWeight: FontWeight.bold, color: theme.colorScheme.primary, ), ); } }), const SizedBox(height: 24), // Synthèse des passages _buildSummaryCards(isDesktop), const SizedBox(height: 24), // Graphique des passages _buildPassagesChart(context, theme), const SizedBox(height: 24), // Derniers passages _buildRecentPassages(context, theme), ], ), ), ), ); } // Construction des cartes de synthèse Widget _buildSummaryCards(bool isDesktop) { return Column( children: [ _buildCombinedPassagesCard(context, isDesktop), const SizedBox(height: 16), _buildCombinedPaymentsCard(isDesktop), ], ); } // Construction d'une carte combinée pour les règlements (liste + graphique) Widget _buildCombinedPaymentsCard(bool isDesktop) { return PaymentSummaryCard( title: 'Mes règlements', titleColor: AppTheme.accentColor, titleIcon: Icons.payments, height: 300, useValueListenable: true, userId: userRepository.getCurrentUser()?.id, showAllPayments: false, isDesktop: isDesktop, backgroundIcon: Icons.euro_symbol, backgroundIconColor: Colors.blue, backgroundIconOpacity: 0.07, backgroundIconSize: 180, customTotalDisplay: (totalAmount) { // Calculer le nombre de passages avec règlement pour le titre personnalisé final currentUser = userRepository.getCurrentUser(); if (currentUser == null) return '${totalAmount.toStringAsFixed(2)} €'; final passagesBox = Hive.box(AppKeys.passagesBoxName); int passagesCount = 0; for (final passage in passagesBox.values) { if (passage.fkUser == currentUser.id) { double montant = 0.0; try { String montantStr = passage.montant.replaceAll(',', '.'); montant = double.tryParse(montantStr) ?? 0.0; } catch (e) { // Ignorer les erreurs } if (montant > 0) passagesCount++; } } return '${totalAmount.toStringAsFixed(2)} € sur $passagesCount passages'; }, ); } // Construction d'une carte combinée pour les passages (liste + graphique) Widget _buildCombinedPassagesCard(BuildContext context, bool isDesktop) { return PassageSummaryCard( title: 'Mes passages', titleColor: AppTheme.primaryColor, titleIcon: Icons.route, height: 300, useValueListenable: true, userId: userRepository.getCurrentUser()?.id, showAllPassages: false, excludePassageTypes: const [2], // Exclure "À finaliser" isDesktop: isDesktop, ); } // Construction du graphique des passages Widget _buildPassagesChart(BuildContext context, ThemeData theme) { return Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: Padding( padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ SizedBox( height: 350, child: ActivityChart( useValueListenable: true, // Utiliser le système réactif excludePassageTypes: const [ 2 ], // Exclure les passages "À finaliser" daysToShow: 15, periodType: 'Jour', height: 350, userId: userRepository.getCurrentUser()?.id, title: 'Dernière activité enregistrée sur 15 jours', ), ), ], ), ), ); } // Construction de la liste des derniers passages Widget _buildRecentPassages(BuildContext context, ThemeData theme) { // Utilisation directe du widget PassagesListWidget sans Card wrapper return ValueListenableBuilder( valueListenable: Hive.box(AppKeys.passagesBoxName).listenable(), builder: (context, Box passagesBox, child) { final recentPassages = _getRecentPassages(passagesBox); // Debug : afficher le nombre de passages récupérés debugPrint( 'UserDashboardHomePage: ${recentPassages.length} passages récents récupérés'); if (recentPassages.isEmpty) { return Card( elevation: 4, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(16), ), child: Padding( padding: EdgeInsets.all(32.0), child: Center( child: Text( 'Aucun passage récent', style: TextStyle( color: Colors.grey, fontSize: AppTheme.r(context, 14), ), ), ), ), ); } // Utiliser une hauteur fixe pour le widget dans le dashboard return SizedBox( height: 450, // Hauteur légèrement augmentée pour compenser l'absence de Card child: PassagesListWidget( passages: recentPassages, showFilters: false, showSearch: false, showActions: true, maxPassages: 20, // Ne pas appliquer de filtres supplémentaires car les passages // sont déjà filtrés dans _getRecentPassages excludePassageTypes: null, // Pas de filtre, déjà géré dans _getRecentPassages filterByUserId: null, // Pas de filtre, déjà géré dans _getRecentPassages periodFilter: null, // Pas de filtre de période // Le widget gère maintenant le flux conditionnel par défaut onPassageSelected: null, onDetailsView: (passage) { debugPrint('Affichage des détails: ${passage['id']}'); }, onPassageEdit: (passage) { debugPrint('Modification du passage: ${passage['id']}'); }, onReceiptView: (passage) { debugPrint('Affichage du reçu pour le passage: ${passage['id']}'); }, onPassageDelete: (passage) { // Pas besoin de faire quoi que ce soit ici // Le ValueListenableBuilder se rafraîchira automatiquement // après la suppression dans Hive via le repository }, ), ); }, ); } /// Récupère les passages récents pour la liste List> _getRecentPassages(Box passagesBox) { final currentUserId = userRepository.getCurrentUser()?.id; // Filtrer les passages : // - Avoir une date passedAt // - Exclure le type 2 ("À finaliser") // - Appartenir à l'utilisateur courant final allPassages = passagesBox.values.where((p) { if (p.passedAt == null) return false; if (p.fkType == 2) return false; // Exclure les passages "À finaliser" if (currentUserId != null && p.fkUser != currentUserId) return false; // Filtrer par utilisateur return true; }).toList(); // Trier par date décroissante allPassages.sort((a, b) => b.passedAt!.compareTo(a.passedAt!)); // Limiter aux 20 passages les plus récents final recentPassagesModels = allPassages.take(20).toList(); // Convertir les modèles de passage au format attendu par le widget PassagesListWidget return recentPassagesModels.map((passage) { // Construire l'adresse complète à partir des champs disponibles final String address = '${passage.numero} ${passage.rue}${passage.rueBis.isNotEmpty ? ' ${passage.rueBis}' : ''}, ${passage.ville}'; // Convertir le montant en double double amount = 0.0; try { if (passage.montant.isNotEmpty) { // Gérer les formats possibles (virgule ou point) String montantStr = passage.montant.replaceAll(',', '.'); amount = double.tryParse(montantStr) ?? 0.0; } } catch (e) { debugPrint('Erreur de conversion du montant: ${passage.montant}'); amount = 0.0; } return { 'id': passage.id, // Garder l'ID comme int, pas besoin de toString() 'address': address, 'amount': amount, 'date': passage.passedAt ?? DateTime.now(), 'type': passage.fkType, 'payment': passage.fkTypeReglement, 'name': passage.name, 'notes': passage.remarque, 'hasReceipt': passage.nomRecu.isNotEmpty, 'hasError': passage.emailErreur.isNotEmpty, 'fkUser': passage.fkUser, 'isOwnedByCurrentUser': passage.fkUser == userRepository .getCurrentUser() ?.id, // Ajout du champ pour le widget }; }).toList(); } }