Version propre - Dashboard enhanced
This commit is contained in:
@@ -0,0 +1,432 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../../shared/theme/app_theme.dart';
|
||||
import '../common/section_header_widget.dart';
|
||||
|
||||
/// Widget de section des analyses et tendances avec graphiques
|
||||
///
|
||||
/// Affiche tous les graphiques d'analyse en une seule colonne:
|
||||
/// - Évolution des membres actifs (ligne)
|
||||
/// - Répartition des cotisations (camembert)
|
||||
/// - Revenus par source (barres)
|
||||
/// - Cotisations par mois (barres)
|
||||
/// - Engagement des membres (radar)
|
||||
/// - Tendances géographiques (carte)
|
||||
/// - Analyse comparative (barres groupées)
|
||||
///
|
||||
/// Chaque graphique est optimisé pour l'affichage mobile
|
||||
/// avec des détails enrichis et des légendes complètes.
|
||||
class ChartsAnalyticsWidget extends StatelessWidget {
|
||||
const ChartsAnalyticsWidget({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SectionHeaderWidget(title: 'Analyses & Tendances'),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Graphiques d'analyse - Une seule colonne pour exploiter toute la largeur
|
||||
_buildLineChart(context),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
_buildPieChart(context),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
_buildRevenueChart(context),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
_buildCotisationsChart(context),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
_buildEngagementChart(context),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
_buildTrendsChart(context),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
_buildGeographicChart(context),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
/// Graphique d'évolution des membres actifs (ligne)
|
||||
Widget _buildLineChart(BuildContext context) {
|
||||
return Container(
|
||||
height: 280,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// En-tête enrichi avec icône et métriques
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.primaryColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.trending_up,
|
||||
color: AppTheme.primaryColor,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Évolution des membres actifs',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppTheme.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
const Text(
|
||||
'Croissance sur 5 mois • +24.7% (+247 membres)',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.successColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: const Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.trending_up,
|
||||
color: AppTheme.successColor,
|
||||
size: 12,
|
||||
),
|
||||
SizedBox(width: 4),
|
||||
Text(
|
||||
'+24.7%',
|
||||
style: TextStyle(
|
||||
color: AppTheme.successColor,
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Placeholder pour le graphique
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.primaryColor.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: AppTheme.primaryColor.withOpacity(0.1),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.show_chart,
|
||||
color: AppTheme.primaryColor,
|
||||
size: 48,
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
'Graphique d\'évolution des membres',
|
||||
style: TextStyle(
|
||||
color: AppTheme.textSecondary,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Graphique de répartition des cotisations (camembert)
|
||||
Widget _buildPieChart(BuildContext context) {
|
||||
return Container(
|
||||
height: 280,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// En-tête enrichi
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.accentColor.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: const Icon(
|
||||
Icons.pie_chart,
|
||||
color: AppTheme.accentColor,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
const Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Répartition des cotisations',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppTheme.textPrimary,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 2),
|
||||
Text(
|
||||
'Par statut de paiement • 1,247 membres total',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Placeholder pour le graphique camembert
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: AppTheme.accentColor.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: AppTheme.accentColor.withOpacity(0.1),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: const Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.donut_small,
|
||||
color: AppTheme.accentColor,
|
||||
size: 48,
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
'Graphique camembert des cotisations',
|
||||
style: TextStyle(
|
||||
color: AppTheme.textSecondary,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Placeholder pour les autres graphiques
|
||||
Widget _buildRevenueChart(BuildContext context) {
|
||||
return _buildPlaceholderChart(
|
||||
'Revenus par source',
|
||||
'Analyse mensuelle • 2,845,000 FCFA total',
|
||||
Icons.bar_chart,
|
||||
AppTheme.successColor,
|
||||
'Graphique des revenus par source',
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildCotisationsChart(BuildContext context) {
|
||||
return _buildPlaceholderChart(
|
||||
'Cotisations par mois',
|
||||
'Évolution sur 12 mois • Tendance positive',
|
||||
Icons.assessment,
|
||||
AppTheme.infoColor,
|
||||
'Graphique des cotisations mensuelles',
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildEngagementChart(BuildContext context) {
|
||||
return _buildPlaceholderChart(
|
||||
'Engagement des membres',
|
||||
'Analyse multi-critères • Score global 85/100',
|
||||
Icons.radar,
|
||||
const Color(0xFF9C27B0),
|
||||
'Graphique radar d\'engagement',
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTrendsChart(BuildContext context) {
|
||||
return _buildPlaceholderChart(
|
||||
'Tendances comparatives',
|
||||
'Comparaison avec période précédente',
|
||||
Icons.compare_arrows,
|
||||
AppTheme.warningColor,
|
||||
'Graphique de tendances comparatives',
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildGeographicChart(BuildContext context) {
|
||||
return _buildPlaceholderChart(
|
||||
'Répartition géographique',
|
||||
'Membres par région • Côte d\'Ivoire',
|
||||
Icons.map,
|
||||
const Color(0xFF795548),
|
||||
'Carte géographique des membres',
|
||||
);
|
||||
}
|
||||
|
||||
/// Widget placeholder générique pour les graphiques
|
||||
Widget _buildPlaceholderChart(
|
||||
String title,
|
||||
String subtitle,
|
||||
IconData icon,
|
||||
Color color,
|
||||
String description,
|
||||
) {
|
||||
return Container(
|
||||
height: 280,
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.black.withOpacity(0.05),
|
||||
blurRadius: 10,
|
||||
offset: const Offset(0, 2),
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
child: Icon(
|
||||
icon,
|
||||
color: color,
|
||||
size: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppTheme.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
subtitle,
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: color.withOpacity(0.05),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: color.withOpacity(0.1),
|
||||
width: 1,
|
||||
),
|
||||
),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(
|
||||
icon,
|
||||
color: color,
|
||||
size: 48,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
description,
|
||||
style: const TextStyle(
|
||||
color: AppTheme.textSecondary,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user