Files
unionflow-mobile-apps/lib/features/dashboard/presentation/widgets/dashboard_widgets.dart
dahoud 120434aba0 feat(features): refontes adhesions/admin/auth/backup/contributions/dashboard/epargne/events
- adhesions : bloc complet avec events/states/model, dialogs paiement/rejet
- admin : users bloc, user management list/detail pages
- authentication : bloc + keycloak auth service + webview
- backup : bloc complet, repository, models
- contributions : bloc + widgets + export
- dashboard : widgets connectés (activities, events, notifications, search)
  + charts + monitoring + shortcuts
- epargne : repository, transactions, dialogs
- events : bloc complet, pages (detail, connected, wrapper), models
2026-04-15 20:26:48 +00:00

259 lines
6.3 KiB
Dart

import 'package:flutter/material.dart';
import '../../../../shared/design_system/unionflow_design_system.dart';
import '../../../../shared/widgets/core_card.dart';
/// Widget de statistique simple pour les dashboards de rôle
class DashboardStat extends StatelessWidget {
final String title;
final String value;
final IconData icon;
final Color? color;
const DashboardStat({
super.key,
required this.title,
required this.value,
required this.icon,
this.color,
});
@override
Widget build(BuildContext context) {
return CoreCard(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Icon(
icon,
color: color ?? AppColors.primary,
size: 20,
),
const Spacer(),
Text(
value,
style: AppTypography.headerSmall.copyWith(
color: color ?? AppColors.primary,
fontSize: 18,
),
),
],
),
const SizedBox(height: 8),
Text(
title.toUpperCase(),
style: AppTypography.subtitleSmall.copyWith(
fontWeight: FontWeight.bold,
fontSize: 10,
letterSpacing: 1.1,
),
),
],
),
);
}
}
/// Widget de grille de statistiques
class DashboardStatsGrid extends StatelessWidget {
final List<DashboardStat> stats;
final Function(String)? onStatTap;
const DashboardStatsGrid({
super.key,
required this.stats,
this.onStatTap,
});
@override
Widget build(BuildContext context) {
return GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1.3,
children: stats,
);
}
}
/// Widget de grille d'actions rapides
class DashboardQuickActionsGrid extends StatelessWidget {
final List<Widget> children;
const DashboardQuickActionsGrid({
super.key,
required this.children,
});
@override
Widget build(BuildContext context) {
return GridView.count(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2,
mainAxisSpacing: 12,
crossAxisSpacing: 12,
childAspectRatio: 1.4,
children: children,
);
}
}
/// Widget d'action rapide
class DashboardQuickAction extends StatelessWidget {
final String title;
final IconData icon;
final VoidCallback onTap;
final Color? color;
const DashboardQuickAction({
super.key,
required this.title,
required this.icon,
required this.onTap,
this.color,
});
@override
Widget build(BuildContext context) {
return CoreCard(
onTap: onTap,
padding: const EdgeInsets.all(12),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: (color ?? AppColors.primary).withOpacity(0.1),
shape: BoxShape.circle,
),
child: Icon(
icon,
color: color ?? AppColors.primary,
size: 24,
),
),
const SizedBox(height: 12),
Text(
title,
style: AppTypography.actionText.copyWith(
fontSize: 12,
fontWeight: FontWeight.w600,
),
textAlign: TextAlign.center,
),
],
),
);
}
}
/// Widget de section d'activités récentes
class DashboardRecentActivitySection extends StatelessWidget {
final List<Widget> children;
const DashboardRecentActivitySection({
super.key,
required this.children,
});
@override
Widget build(BuildContext context) {
return CoreCard(
padding: const EdgeInsets.all(16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'ACTIVITÉS RÉCENTES',
style: AppTypography.subtitleSmall.copyWith(
fontWeight: FontWeight.bold,
letterSpacing: 1.1,
),
),
const SizedBox(height: 16),
...children,
],
),
);
}
}
/// Widget d'activité
class DashboardActivity extends StatelessWidget {
final String title;
final String subtitle;
final String time;
final IconData icon;
final Color? color;
const DashboardActivity({
super.key,
required this.title,
required this.subtitle,
required this.time,
required this.icon,
this.color,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 12),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(6),
decoration: BoxDecoration(
color: (color ?? AppColors.primary).withOpacity(0.1),
borderRadius: BorderRadius.circular(4),
),
child: Icon(
icon,
color: color ?? AppColors.primary,
size: 14,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: AppTypography.actionText.copyWith(
fontWeight: FontWeight.w600,
fontSize: 12,
),
),
Text(
subtitle,
style: AppTypography.subtitleSmall.copyWith(fontSize: 10),
),
],
),
),
Builder(
builder: (ctx) {
final isDark = Theme.of(ctx).brightness == Brightness.dark;
return Text(
time,
style: AppTypography.subtitleSmall.copyWith(
color: isDark ? AppColors.textSecondaryDark : AppColors.textSecondary,
fontSize: 9,
),
);
},
),
],
),
);
}
}