Files
unionflow-mobile-apps/lib/features/dashboard/presentation/pages/advanced_dashboard_page.dart
2026-03-28 14:22:16 +00:00

484 lines
15 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../widgets/connected/connected_stats_card.dart';
import '../widgets/connected/connected_recent_activities.dart';
import '../widgets/connected/connected_upcoming_events.dart';
import '../widgets/charts/dashboard_chart_widget.dart';
import '../widgets/metrics/real_time_metrics_widget.dart';
import '../widgets/notifications/dashboard_notifications_widget.dart';
import '../bloc/dashboard_bloc.dart';
import '../../../../shared/design_system/unionflow_design_system.dart';
import '../../../../shared/widgets/core_card.dart';
import '../../../../core/di/injection_container.dart';
import '../../../settings/presentation/pages/system_settings_page.dart';
/// Page dashboard avancée avec graphiques et analytics
class AdvancedDashboardPage extends StatefulWidget {
final String organizationId;
final String userId;
const AdvancedDashboardPage({
super.key,
required this.organizationId,
required this.userId,
});
@override
State<AdvancedDashboardPage> createState() => _AdvancedDashboardPageState();
}
class _AdvancedDashboardPageState extends State<AdvancedDashboardPage>
with TickerProviderStateMixin {
late DashboardBloc _dashboardBloc;
late TabController _tabController;
@override
void initState() {
super.initState();
_dashboardBloc = sl<DashboardBloc>();
_tabController = TabController(length: 3, vsync: this);
_loadDashboardData();
}
void _loadDashboardData() {
_dashboardBloc.add(LoadDashboardData(
organizationId: widget.organizationId,
userId: widget.userId,
));
}
void _refreshDashboardData() {
_dashboardBloc.add(RefreshDashboardData(
organizationId: widget.organizationId,
userId: widget.userId,
));
}
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => _dashboardBloc,
child: Scaffold(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
appBar: const UFAppBar(
title: 'DASHBOARD AVANCÉ',
),
body: Column(
children: [
_buildTabBar(),
Expanded(
child: TabBarView(
controller: _tabController,
children: [
_buildOverviewTab(),
_buildAnalyticsTab(),
_buildReportsTab(),
],
),
),
],
),
floatingActionButton: _buildFloatingActionButton(),
),
);
}
Widget _buildSliverAppBar() {
return SliverAppBar(
expandedHeight: 200,
floating: false,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
background: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [AppColors.primaryGreen, AppColors.brandGreen],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
),
),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.end,
children: [
Row(
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2),
borderRadius: BorderRadius.circular(12),
),
child: const Icon(
Icons.dashboard_outlined,
color: Colors.white,
size: 32,
),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'DASHBOARD AVANCÉ',
style: AppTypography.headerSmall.copyWith(
color: Colors.white,
fontSize: 24,
fontWeight: FontWeight.bold,
letterSpacing: 1.2,
),
),
const SizedBox(height: 4),
Text(
'ANALYTICS & INSIGHTS',
style: AppTypography.subtitleSmall.copyWith(
color: Colors.white.withOpacity(0.9),
fontWeight: FontWeight.w500,
letterSpacing: 1.1,
),
),
],
),
),
],
),
const SizedBox(height: 16),
BlocBuilder<DashboardBloc, DashboardState>(
builder: (context, state) {
if (state is DashboardLoaded || state is DashboardRefreshing) {
final data = state is DashboardLoaded
? state.dashboardData
: (state as DashboardRefreshing).dashboardData;
return Row(
children: [
_buildQuickStat(
'Membres',
'${data.stats.activeMembers}/${data.stats.totalMembers}',
Icons.people_outline,
),
const SizedBox(width: 16),
_buildQuickStat(
'Événements',
'${data.stats.upcomingEvents}',
Icons.event_outlined,
),
const SizedBox(width: 16),
_buildQuickStat(
'Croissance',
'${data.stats.monthlyGrowth.toStringAsFixed(1)}%',
Icons.trending_up,
),
],
);
}
return const SizedBox.shrink();
},
),
],
),
),
),
),
),
actions: [
IconButton(
onPressed: _refreshDashboardData,
icon: const Icon(
Icons.refresh_outlined,
color: Colors.white,
),
),
IconButton(
onPressed: () {
Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => const SystemSettingsPage(),
),
);
},
icon: const Icon(
Icons.settings_outlined,
color: Colors.white,
),
),
],
);
}
Widget _buildQuickStat(String label, String value, IconData icon) {
return Container(
padding: const EdgeInsets.symmetric(
horizontal: 12,
vertical: 8,
),
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.15),
borderRadius: BorderRadius.circular(8),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(
icon,
color: Colors.white,
size: 14,
),
const SizedBox(width: 8),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
value,
style: AppTypography.actionText.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 12,
),
),
Text(
label.toUpperCase(),
style: AppTypography.badgeText.copyWith(
color: Colors.white.withOpacity(0.8),
fontSize: 8,
letterSpacing: 0.5,
),
),
],
),
],
),
);
}
Widget _buildTabBar() {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).cardColor,
border: Border(bottom: BorderSide(color: AppColors.lightBorder, width: 1)),
),
child: TabBar(
controller: _tabController,
labelColor: AppColors.primaryGreen,
unselectedLabelColor: AppColors.textSecondaryLight,
indicatorColor: AppColors.primaryGreen,
indicatorWeight: 3,
labelStyle: AppTypography.actionText.copyWith(fontSize: 10, fontWeight: FontWeight.bold, letterSpacing: 1),
tabs: const [
Tab(text: 'VUE D\'ENSEMBLE'),
Tab(text: 'ANALYTICS'),
Tab(text: 'RAPPORTS'),
],
),
);
}
Widget _buildOverviewTab() {
return RefreshIndicator(
onRefresh: () async => _refreshDashboardData(),
color: AppColors.primaryGreen,
child: SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
// Métriques temps réel
RealTimeMetricsWidget(
organizationId: widget.organizationId,
userId: widget.userId,
),
const SizedBox(height: 16),
// Grille de statistiques
_buildStatsGrid(),
const SizedBox(height: 16),
// Notifications
const DashboardNotificationsWidget(maxNotifications: 3),
const SizedBox(height: 16),
// Activités et événements
const Row(
children: [
Expanded(
child: ConnectedRecentActivities(maxItems: 3),
),
SizedBox(width: 16),
Expanded(
child: ConnectedUpcomingEvents(maxItems: 2),
),
],
),
],
),
),
);
}
Widget _buildAnalyticsTab() {
return const SingleChildScrollView(
padding: EdgeInsets.all(16),
child: Column(
children: [
Row(
children: [
Expanded(
child: DashboardChartWidget(
title: 'Activité des Membres',
chartType: DashboardChartType.memberActivity,
height: 250,
),
),
SizedBox(width: 12),
Expanded(
child: DashboardChartWidget(
title: 'Croissance Mensuelle',
chartType: DashboardChartType.monthlyGrowth,
height: 250,
),
),
],
),
SizedBox(height: 16),
DashboardChartWidget(
title: 'Tendance des Contributions',
chartType: DashboardChartType.contributionTrend,
height: 300,
),
SizedBox(height: 16),
DashboardChartWidget(
title: 'Participation aux Événements',
chartType: DashboardChartType.eventParticipation,
height: 250,
),
],
),
);
}
Widget _buildReportsTab() {
return SingleChildScrollView(
padding: const EdgeInsets.all(16),
child: Column(
children: [
_buildReportCard(
'Rapport Mensuel',
'Synthèse complète des activités du mois',
Icons.calendar_month_outlined,
AppColors.primaryGreen,
),
const SizedBox(height: 12),
_buildReportCard(
'Rapport Financier',
'État des contributions et finances',
Icons.account_balance_wallet_outlined,
AppColors.success,
),
const SizedBox(height: 12),
_buildReportCard(
'Rapport d\'Activité',
'Analyse de l\'engagement des membres',
Icons.trending_up,
AppColors.info,
),
const SizedBox(height: 12),
_buildReportCard(
'Rapport Événements',
'Statistiques des événements organisés',
Icons.event_note_outlined,
AppColors.warning,
),
],
),
);
}
Widget _buildStatsGrid() {
return GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 1.25,
children: [
ConnectedStatsCard(
title: 'Membres',
icon: Icons.people_outline,
valueExtractor: (stats) => stats.totalMembers.toString(),
subtitleExtractor: (stats) => '${stats.activeMembers} actifs',
),
ConnectedStatsCard(
title: 'Finances',
icon: Icons.account_balance_wallet_outlined,
valueExtractor: (stats) => stats.formattedContributionAmount,
subtitleExtractor: (stats) => '${stats.totalContributions} versements',
customColor: AppColors.success,
),
ConnectedStatsCard(
title: 'Événements',
icon: Icons.event_outlined,
valueExtractor: (stats) => stats.totalEvents.toString(),
subtitleExtractor: (stats) => '${stats.upcomingEvents} à venir',
customColor: AppColors.info,
),
ConnectedStatsCard(
title: 'Engagement',
icon: Icons.star_outline,
valueExtractor: (stats) => '${(stats.engagementRate * 100).toStringAsFixed(0)}%',
subtitleExtractor: (stats) => stats.isHighEngagement ? 'Excellent' : 'Stable',
customColor: AppColors.warning,
),
],
);
}
Widget _buildReportCard(String title, String description, IconData icon, Color color) {
return CoreCard(
padding: const EdgeInsets.all(12),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: color.withOpacity(0.1),
borderRadius: BorderRadius.circular(8),
),
child: Icon(icon, color: color, size: 20),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: AppTypography.actionText.copyWith(fontSize: 12)),
Text(description, style: AppTypography.subtitleSmall.copyWith(fontSize: 10)),
],
),
),
const Icon(Icons.download_outlined, color: AppColors.textSecondaryLight, size: 18),
],
),
);
}
Widget _buildFloatingActionButton() {
return FloatingActionButton(
onPressed: () {
// Actions rapides
},
backgroundColor: AppColors.primaryGreen,
child: const Icon(Icons.add, color: Colors.white),
);
}
@override
void dispose() {
_tabController.dispose();
_dashboardBloc.close();
super.dispose();
}
}