import 'package:flutter/material.dart'; /// Widget réutilisable pour afficher une carte de statistique /// /// Composant générique utilisé dans tous les dashboards pour afficher /// des métriques avec icône, valeur, titre et sous-titre. class StatCard extends StatelessWidget { /// Titre principal de la statistique final String title; /// Valeur numérique ou textuelle à afficher final String value; /// Sous-titre ou description complémentaire final String subtitle; /// Icône représentative de la métrique final IconData icon; /// Couleur thématique de la carte final Color color; /// Callback optionnel lors du tap sur la carte final VoidCallback? onTap; /// Taille de la carte (compact, normal, large) final StatCardSize size; /// Style de la carte (minimal, elevated, outlined) final StatCardStyle style; const StatCard({ super.key, required this.title, required this.value, required this.subtitle, required this.icon, required this.color, this.onTap, this.size = StatCardSize.normal, this.style = StatCardStyle.elevated, }); /// Constructeur pour une carte KPI simplifiée const StatCard.kpi({ super.key, required this.title, required this.value, required this.subtitle, required this.icon, required this.color, this.onTap, }) : size = StatCardSize.compact, style = StatCardStyle.elevated; /// Constructeur pour une carte de métrique système const StatCard.metric({ super.key, required this.title, required this.value, required this.subtitle, required this.icon, required this.color, this.onTap, }) : size = StatCardSize.normal, style = StatCardStyle.minimal; @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( padding: _getPadding(), decoration: _getDecoration(), child: _buildContent(), ), ); } /// Contenu principal de la carte Widget _buildContent() { switch (size) { case StatCardSize.compact: return _buildCompactContent(); case StatCardSize.normal: return _buildNormalContent(); case StatCardSize.large: return _buildLargeContent(); } } /// Contenu compact pour les KPIs Widget _buildCompactContent() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Icon(icon, color: color, size: 20), const Spacer(), Text( value, style: TextStyle( fontWeight: FontWeight.bold, color: color, fontSize: 18, ), ), ], ), const SizedBox(height: 4), Text( title, style: const TextStyle( fontWeight: FontWeight.w600, color: Colors.black87, fontSize: 12, ), ), Text( subtitle, style: const TextStyle( color: Colors.grey, fontSize: 10, ), ), ], ); } /// Contenu normal pour les métriques Widget _buildNormalContent() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(8), ), child: Icon(icon, color: color, size: 20), ), const Spacer(), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( value, style: TextStyle( fontWeight: FontWeight.bold, color: color, fontSize: 20, ), ), if (subtitle.isNotEmpty) Text( subtitle, style: TextStyle( color: Colors.grey[600], fontSize: 10, ), ), ], ), ], ), const SizedBox(height: 12), Text( title, style: const TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF1F2937), fontSize: 14, ), ), ], ); } /// Contenu large pour les dashboards principaux Widget _buildLargeContent() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(12), ), child: Icon(icon, color: color, size: 24), ), const Spacer(), Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Text( value, style: TextStyle( fontWeight: FontWeight.bold, color: color, fontSize: 24, ), ), if (subtitle.isNotEmpty) Text( subtitle, style: TextStyle( color: Colors.grey[600], fontSize: 12, ), ), ], ), ], ), const SizedBox(height: 16), Text( title, style: const TextStyle( fontWeight: FontWeight.w600, color: Color(0xFF1F2937), fontSize: 16, ), ), ], ); } /// Padding selon la taille EdgeInsets _getPadding() { switch (size) { case StatCardSize.compact: return const EdgeInsets.all(8); case StatCardSize.normal: return const EdgeInsets.all(12); case StatCardSize.large: return const EdgeInsets.all(16); } } /// Décoration selon le style BoxDecoration _getDecoration() { switch (style) { case StatCardStyle.minimal: return BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), ); case StatCardStyle.elevated: return BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 8, offset: const Offset(0, 2), ), ], ); case StatCardStyle.outlined: return BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(8), border: Border.all( color: color.withOpacity(0.2), width: 1, ), ); } } } /// Énumération des tailles de carte enum StatCardSize { compact, normal, large, } /// Énumération des styles de carte enum StatCardStyle { minimal, elevated, outlined, }