feat(mobile): Contribution Totale + KPI dashboard membre
- MembreDashboardSyntheseModel: totalCotisationsPayeesToutTemps - DashboardStatsEntity: contributionsAmountOnly (cotisations seules) - Mapping: Mon Solde Total = cotisations tout temps + épargne, Contribution Totale = cotisations seules - Engagement: fallback tauxCotisationsPerso si tauxParticipation absent - Carte Contribution Totale utilise contributionsAmountOnly Made-with: Cursor
This commit is contained in:
@@ -1,275 +1,482 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import '../../../../../shared/design_system/unionflow_design_v2.dart';
|
||||
import '../../bloc/dashboard_bloc.dart';
|
||||
import '../../../../authentication/presentation/bloc/auth_bloc.dart';
|
||||
import '../../../../contributions/presentation/pages/contributions_page_wrapper.dart';
|
||||
import '../../../../epargne/presentation/pages/epargne_page.dart';
|
||||
import '../../../../profile/presentation/pages/profile_page_wrapper.dart';
|
||||
import '../../../../help/presentation/pages/help_support_page.dart';
|
||||
import '../../../../events/presentation/pages/events_page_wrapper.dart';
|
||||
import '../../../../solidarity/presentation/pages/demandes_aide_page_wrapper.dart';
|
||||
|
||||
/// Dashboard simple pour Membre Actif
|
||||
/// Dashboard Membre Actif - Design UnionFlow Enrichi
|
||||
class ActiveMemberDashboard extends StatelessWidget {
|
||||
const ActiveMemberDashboard({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// En-tête de bienvenue
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: const EdgeInsets.all(20),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF00B894), Color(0xFF00CEC9)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
),
|
||||
child: const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Bonjour !',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
Text(
|
||||
'Bienvenue sur votre espace membre',
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 16,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Statistiques rapides
|
||||
const Text(
|
||||
'Mes Statistiques',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
GridView.count(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisCount: 2,
|
||||
childAspectRatio: 1.2,
|
||||
crossAxisSpacing: 16,
|
||||
mainAxisSpacing: 16,
|
||||
children: [
|
||||
_buildStatCard(
|
||||
icon: Icons.event_available,
|
||||
value: '12',
|
||||
title: 'Événements',
|
||||
color: const Color(0xFF00B894),
|
||||
),
|
||||
_buildStatCard(
|
||||
icon: Icons.volunteer_activism,
|
||||
value: '3',
|
||||
title: 'Solidarité',
|
||||
color: const Color(0xFF00CEC9),
|
||||
),
|
||||
_buildStatCard(
|
||||
icon: Icons.payment,
|
||||
value: 'À jour',
|
||||
title: 'Cotisations',
|
||||
color: const Color(0xFF0984E3),
|
||||
),
|
||||
_buildStatCard(
|
||||
icon: Icons.star,
|
||||
value: '4.8',
|
||||
title: 'Engagement',
|
||||
color: const Color(0xFFE17055),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Actions rapides
|
||||
const Text(
|
||||
'Actions Rapides',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
GridView.count(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisCount: 2,
|
||||
childAspectRatio: 1.5,
|
||||
crossAxisSpacing: 16,
|
||||
mainAxisSpacing: 16,
|
||||
children: [
|
||||
_buildActionCard(
|
||||
icon: Icons.event,
|
||||
title: 'Créer Événement',
|
||||
color: const Color(0xFF00B894),
|
||||
onTap: () {},
|
||||
),
|
||||
_buildActionCard(
|
||||
icon: Icons.volunteer_activism,
|
||||
title: 'Demande Aide',
|
||||
color: const Color(0xFF00CEC9),
|
||||
onTap: () {},
|
||||
),
|
||||
_buildActionCard(
|
||||
icon: Icons.account_circle,
|
||||
title: 'Mon Profil',
|
||||
color: const Color(0xFF0984E3),
|
||||
onTap: () {},
|
||||
),
|
||||
_buildActionCard(
|
||||
icon: Icons.message,
|
||||
title: 'Contacter',
|
||||
color: const Color(0xFFE17055),
|
||||
onTap: () {},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Activités récentes
|
||||
const Text(
|
||||
'Activités Récentes',
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
Card(
|
||||
child: Column(
|
||||
children: [
|
||||
_buildActivityItem(
|
||||
icon: Icons.check_circle,
|
||||
title: 'Participation confirmée',
|
||||
subtitle: 'Assemblée Générale - Il y a 2h',
|
||||
color: const Color(0xFF00B894),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
_buildActivityItem(
|
||||
icon: Icons.payment,
|
||||
title: 'Cotisation payée',
|
||||
subtitle: 'Décembre 2024 - Il y a 1j',
|
||||
color: const Color(0xFF0984E3),
|
||||
),
|
||||
const Divider(height: 1),
|
||||
_buildActivityItem(
|
||||
icon: Icons.event,
|
||||
title: 'Événement créé',
|
||||
subtitle: 'Sortie ski de fond - Il y a 3j',
|
||||
color: const Color(0xFF00CEC9),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
return Scaffold(
|
||||
backgroundColor: UnionFlowColors.background,
|
||||
appBar: _buildAppBar(),
|
||||
body: AfricanPatternBackground(
|
||||
child: BlocBuilder<AuthBloc, AuthState>(
|
||||
builder: (context, authState) {
|
||||
final user = (authState is AuthAuthenticated) ? authState.user : null;
|
||||
|
||||
Widget _buildStatCard({
|
||||
required IconData icon,
|
||||
required String value,
|
||||
required String title,
|
||||
required Color color,
|
||||
}) {
|
||||
return Card(
|
||||
elevation: 2,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Icon(icon, color: color, size: 32),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
value,
|
||||
style: const TextStyle(
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.grey[600],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
return BlocBuilder<DashboardBloc, DashboardState>(
|
||||
builder: (context, dashboardState) {
|
||||
if (dashboardState is DashboardLoading) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(color: UnionFlowColors.unionGreen),
|
||||
);
|
||||
}
|
||||
|
||||
final dashboardData = (dashboardState is DashboardLoaded)
|
||||
? dashboardState.dashboardData
|
||||
: null;
|
||||
final stats = dashboardData?.stats;
|
||||
|
||||
return SingleChildScrollView(
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// En-tête
|
||||
AnimatedFadeIn(
|
||||
delay: const Duration(milliseconds: 100),
|
||||
child: _buildUserHeader(user),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Balance principale (données backend réelles)
|
||||
AnimatedSlideIn(
|
||||
delay: const Duration(milliseconds: 200),
|
||||
child: UnionBalanceCard(
|
||||
label: 'Mon Solde Total',
|
||||
amount: _formatAmount(stats?.totalContributionAmount ?? 0),
|
||||
trend: stats != null && stats.monthlyGrowth != 0
|
||||
? '${stats.monthlyGrowth > 0 ? '+' : ''}${stats.monthlyGrowth.toStringAsFixed(1)}% ce mois'
|
||||
: 'Aucune variation',
|
||||
isTrendPositive: (stats?.monthlyGrowth ?? 0) >= 0,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Stats en grille (données backend réelles)
|
||||
AnimatedFadeIn(
|
||||
delay: const Duration(milliseconds: 300),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: UnionStatWidget(
|
||||
label: 'Cotisations',
|
||||
value: '${stats?.totalContributions ?? 0}',
|
||||
icon: Icons.check_circle,
|
||||
color: UnionFlowColors.success,
|
||||
trend: stats != null && stats.monthlyGrowth > 0
|
||||
? '+${stats.monthlyGrowth.toStringAsFixed(0)}%'
|
||||
: null,
|
||||
isTrendUp: (stats?.monthlyGrowth ?? 0) > 0,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: UnionStatWidget(
|
||||
label: 'Engagement',
|
||||
value: stats != null
|
||||
? '${(stats.engagementRate * 100).toStringAsFixed(0)}%'
|
||||
: '0%',
|
||||
icon: Icons.trending_up,
|
||||
color: UnionFlowColors.gold,
|
||||
trend: stats != null && stats.engagementRate > 0.7
|
||||
? 'Excellent'
|
||||
: stats != null && stats.engagementRate > 0.5
|
||||
? 'Bon'
|
||||
: null,
|
||||
isTrendUp: (stats?.engagementRate ?? 0) > 0.7,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
AnimatedFadeIn(
|
||||
delay: const Duration(milliseconds: 400),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: UnionStatWidget(
|
||||
label: 'Contribution Totale',
|
||||
value: _formatAmount(stats?.contributionsAmountOnly ?? stats?.totalContributionAmount ?? 0),
|
||||
icon: Icons.savings,
|
||||
color: UnionFlowColors.amber,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: UnionStatWidget(
|
||||
label: 'Événements',
|
||||
value: '${stats?.upcomingEvents ?? 0}',
|
||||
icon: Icons.event_available,
|
||||
color: UnionFlowColors.terracotta,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
|
||||
// Activité récente (données backend)
|
||||
if (dashboardData != null && dashboardData.hasRecentActivity) ...[
|
||||
AnimatedFadeIn(
|
||||
delay: const Duration(milliseconds: 500),
|
||||
child: const Text(
|
||||
'Activité Récente',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: UnionFlowColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
AnimatedSlideIn(
|
||||
delay: const Duration(milliseconds: 600),
|
||||
child: Column(
|
||||
children: dashboardData.recentActivities.take(3).map((activity) =>
|
||||
Container(
|
||||
margin: const EdgeInsets.only(bottom: 12),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: UnionFlowColors.surface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(color: UnionFlowColors.border, width: 1),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundColor: activity.type == 'contribution'
|
||||
? UnionFlowColors.success.withOpacity(0.2)
|
||||
: activity.type == 'event'
|
||||
? UnionFlowColors.gold.withOpacity(0.2)
|
||||
: UnionFlowColors.indigo.withOpacity(0.2),
|
||||
child: Icon(
|
||||
activity.type == 'contribution'
|
||||
? Icons.payment
|
||||
: activity.type == 'event'
|
||||
? Icons.event
|
||||
: Icons.person_add,
|
||||
size: 18,
|
||||
color: activity.type == 'contribution'
|
||||
? UnionFlowColors.success
|
||||
: activity.type == 'event'
|
||||
? UnionFlowColors.gold
|
||||
: UnionFlowColors.indigo,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
activity.title,
|
||||
style: const TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: UnionFlowColors.textPrimary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
activity.description,
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
color: UnionFlowColors.textSecondary,
|
||||
),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Text(
|
||||
activity.timeAgo,
|
||||
style: const TextStyle(
|
||||
fontSize: 11,
|
||||
color: UnionFlowColors.textTertiary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
).toList(),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
],
|
||||
|
||||
// Actions rapides
|
||||
AnimatedFadeIn(
|
||||
delay: const Duration(milliseconds: 700),
|
||||
child: const Text(
|
||||
'Actions Rapides',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: UnionFlowColors.textPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
AnimatedSlideIn(
|
||||
delay: const Duration(milliseconds: 800),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: UnionActionButton(
|
||||
label: 'Cotiser',
|
||||
icon: Icons.payment,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => const CotisationsPageWrapper(),
|
||||
),
|
||||
);
|
||||
},
|
||||
backgroundColor: UnionFlowColors.unionGreen,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: UnionActionButton(
|
||||
label: 'Épargner',
|
||||
icon: Icons.savings_outlined,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => const EpargnePage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
backgroundColor: UnionFlowColors.gold,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: UnionActionButton(
|
||||
label: 'Crédit',
|
||||
icon: Icons.account_balance_wallet,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => const EpargnePage(),
|
||||
),
|
||||
);
|
||||
},
|
||||
backgroundColor: UnionFlowColors.amber,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
|
||||
AnimatedSlideIn(
|
||||
delay: const Duration(milliseconds: 900),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: UnionActionButton(
|
||||
label: 'Événements',
|
||||
icon: Icons.event,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => const EventsPageWrapper(),
|
||||
),
|
||||
);
|
||||
},
|
||||
backgroundColor: UnionFlowColors.terracotta,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: UnionActionButton(
|
||||
label: 'Solidarité',
|
||||
icon: Icons.favorite_outline,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => const DemandesAidePageWrapper(),
|
||||
),
|
||||
);
|
||||
},
|
||||
backgroundColor: UnionFlowColors.error,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: UnionActionButton(
|
||||
label: 'Profil',
|
||||
icon: Icons.person_outline,
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute<void>(
|
||||
builder: (_) => const ProfilePageWrapper(),
|
||||
),
|
||||
);
|
||||
},
|
||||
backgroundColor: UnionFlowColors.indigo,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionCard({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required Color color,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return Card(
|
||||
elevation: 2,
|
||||
child: InkWell(
|
||||
onTap: onTap,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
PreferredSizeWidget _buildAppBar() {
|
||||
return AppBar(
|
||||
backgroundColor: UnionFlowColors.surface,
|
||||
elevation: 0,
|
||||
title: Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 32,
|
||||
height: 32,
|
||||
decoration: BoxDecoration(
|
||||
gradient: UnionFlowColors.primaryGradient,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: const Text(
|
||||
'U',
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 18,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
const Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Icon(icon, color: color, size: 28),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
'UnionFlow',
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: UnionFlowColors.textPrimary,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Membre Actif',
|
||||
style: TextStyle(
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: UnionFlowColors.textSecondary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
automaticallyImplyLeading: false,
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUserHeader(dynamic user) {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
gradient: UnionFlowColors.warmGradient,
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: const Border(
|
||||
top: BorderSide(color: UnionFlowColors.gold, width: 3),
|
||||
),
|
||||
boxShadow: UnionFlowColors.goldGlowShadow,
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
radius: 28,
|
||||
backgroundColor: Colors.white.withOpacity(0.3),
|
||||
child: Text(
|
||||
user?.initials ?? 'MA',
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
user?.fullName ?? 'Membre Actif',
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
'Depuis ${user?.createdAt.year ?? 2024} • Très Actif',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.white.withOpacity(0.9),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: const Text(
|
||||
'ACTIF',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.w800,
|
||||
color: UnionFlowColors.gold,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActivityItem({
|
||||
required IconData icon,
|
||||
required String title,
|
||||
required String subtitle,
|
||||
required Color color,
|
||||
}) {
|
||||
return ListTile(
|
||||
leading: CircleAvatar(
|
||||
backgroundColor: color.withOpacity(0.1),
|
||||
child: Icon(icon, color: color, size: 20),
|
||||
),
|
||||
title: Text(
|
||||
title,
|
||||
style: const TextStyle(fontWeight: FontWeight.w500),
|
||||
),
|
||||
subtitle: Text(subtitle),
|
||||
trailing: const Icon(Icons.arrow_forward_ios, size: 16),
|
||||
);
|
||||
String _formatAmount(double amount) {
|
||||
if (amount >= 1000000) {
|
||||
return '${(amount / 1000000).toStringAsFixed(1)}M FCFA';
|
||||
} else if (amount >= 1000) {
|
||||
return '${(amount / 1000).toStringAsFixed(0)}K FCFA';
|
||||
}
|
||||
return '${amount.toStringAsFixed(0)} FCFA';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user