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
This commit is contained in:
@@ -60,9 +60,10 @@ class _ContributionsPageState extends State<ContributionsPage>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: ColorTokens.background,
|
||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
appBar: UFAppBar(
|
||||
title: 'Cotisations',
|
||||
moduleGradient: ModuleColors.cotisationsGradient,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.bar_chart, size: 20),
|
||||
@@ -76,15 +77,17 @@ class _ContributionsPageState extends State<ContributionsPage>
|
||||
bottom: TabBar(
|
||||
controller: _tabController,
|
||||
onTap: (_) => _loadContributions(),
|
||||
labelColor: ColorTokens.onPrimary,
|
||||
unselectedLabelColor: ColorTokens.onPrimary.withOpacity(0.7),
|
||||
indicatorColor: ColorTokens.onPrimary,
|
||||
labelStyle: AppTypography.badgeText.copyWith(fontWeight: FontWeight.bold),
|
||||
isScrollable: true,
|
||||
labelColor: Colors.white,
|
||||
unselectedLabelColor: Colors.white70,
|
||||
indicatorColor: Colors.white,
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
labelStyle: AppTypography.actionText.copyWith(fontSize: 10, fontWeight: FontWeight.bold),
|
||||
tabs: const [
|
||||
Tab(text: 'Toutes'),
|
||||
Tab(text: 'Payées'),
|
||||
Tab(text: 'Dues'),
|
||||
Tab(text: 'Retard'),
|
||||
Tab(child: Text('TOUTES')),
|
||||
Tab(child: Text('PAYÉES')),
|
||||
Tab(child: Text('DUES')),
|
||||
Tab(child: Text('RETARD')),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -257,18 +260,19 @@ class _ContributionsPageState extends State<ContributionsPage>
|
||||
}
|
||||
|
||||
Widget _buildStatutBadge(ContributionStatus statut, bool enRetard) {
|
||||
final scheme = Theme.of(context).colorScheme;
|
||||
if (enRetard && statut != ContributionStatus.payee) {
|
||||
return const InfoBadge(text: 'RETARD', backgroundColor: Color(0xFFFFEBEB), textColor: ColorTokens.error);
|
||||
return InfoBadge(text: 'RETARD', backgroundColor: scheme.errorContainer, textColor: ColorTokens.error);
|
||||
}
|
||||
|
||||
switch (statut) {
|
||||
case ContributionStatus.payee:
|
||||
return const InfoBadge(text: 'PAYÉE', backgroundColor: Color(0xFFE3F9E5), textColor: ColorTokens.success);
|
||||
return InfoBadge(text: 'PAYÉE', backgroundColor: ColorTokens.successContainer, textColor: ColorTokens.success);
|
||||
case ContributionStatus.nonPayee:
|
||||
case ContributionStatus.enAttente:
|
||||
return const InfoBadge(text: 'DUE', backgroundColor: Color(0xFFFFF4E5), textColor: ColorTokens.warning);
|
||||
return InfoBadge(text: 'DUE', backgroundColor: ColorTokens.warningContainer, textColor: ColorTokens.warning);
|
||||
case ContributionStatus.partielle:
|
||||
return const InfoBadge(text: 'PARTIELLE', backgroundColor: Color(0xFFE5F1FF), textColor: ColorTokens.info);
|
||||
return InfoBadge(text: 'PARTIELLE', backgroundColor: ColorTokens.infoContainer, textColor: ColorTokens.info);
|
||||
case ContributionStatus.annulee:
|
||||
return InfoBadge.neutral('ANNULÉE');
|
||||
default:
|
||||
@@ -279,7 +283,7 @@ class _ContributionsPageState extends State<ContributionsPage>
|
||||
void _showContributionDetails(ContributionModel contribution) {
|
||||
showModalBottomSheet(
|
||||
context: context,
|
||||
backgroundColor: ColorTokens.surface,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(RadiusTokens.lg))),
|
||||
builder: (context) => Padding(
|
||||
padding: const EdgeInsets.all(SpacingTokens.xl),
|
||||
|
||||
@@ -38,11 +38,10 @@ class _MesStatistiquesCotisationsPageState extends State<MesStatistiquesCotisati
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: ColorTokens.background,
|
||||
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
|
||||
appBar: UFAppBar(
|
||||
title: 'Mes statistiques cotisations',
|
||||
backgroundColor: ColorTokens.surface,
|
||||
foregroundColor: ColorTokens.onSurface,
|
||||
title: 'Statistiques Cotisations',
|
||||
moduleGradient: ModuleColors.cotisationsGradient,
|
||||
),
|
||||
body: BlocListener<ContributionsBloc, ContributionsState>(
|
||||
listener: (context, state) {
|
||||
@@ -158,7 +157,7 @@ class _MesStatistiquesCotisationsPageState extends State<MesStatistiquesCotisati
|
||||
'Payé cette année',
|
||||
_currencyFormat.format(totalPayeAnnee),
|
||||
icon: Icons.check_circle_outline,
|
||||
color: AppColors.primaryGreen,
|
||||
color: AppColors.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -272,7 +271,7 @@ class _MesStatistiquesCotisationsPageState extends State<MesStatistiquesCotisati
|
||||
Text('0 %', style: AppTypography.bodyTextSmall.copyWith(color: ColorTokens.onSurfaceVariant)),
|
||||
Text(
|
||||
'${taux.toStringAsFixed(0)} %',
|
||||
style: AppTypography.headerSmall.copyWith(color: AppColors.primaryGreen, fontWeight: FontWeight.w700),
|
||||
style: AppTypography.headerSmall.copyWith(color: AppColors.primary, fontWeight: FontWeight.w700),
|
||||
),
|
||||
Text('100 %', style: AppTypography.bodyTextSmall.copyWith(color: ColorTokens.onSurfaceVariant)),
|
||||
],
|
||||
@@ -294,7 +293,7 @@ class _MesStatistiquesCotisationsPageState extends State<MesStatistiquesCotisati
|
||||
final sections = <PieChartSectionData>[];
|
||||
if (paye > 0) {
|
||||
sections.add(PieChartSectionData(
|
||||
color: AppColors.primaryGreen,
|
||||
color: AppColors.primary,
|
||||
value: paye,
|
||||
title: 'Payé',
|
||||
radius: 60,
|
||||
@@ -345,7 +344,7 @@ class _MesStatistiquesCotisationsPageState extends State<MesStatistiquesCotisati
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
||||
children: [
|
||||
_legendItem(AppColors.primaryGreen, 'Payé', _currencyFormat.format(paye)),
|
||||
_legendItem(AppColors.primary, 'Payé', _currencyFormat.format(paye)),
|
||||
_legendItem(UnionFlowColors.terracotta, 'Dû', _currencyFormat.format(du)),
|
||||
],
|
||||
),
|
||||
@@ -454,11 +453,11 @@ class _MesStatistiquesCotisationsPageState extends State<MesStatistiquesCotisati
|
||||
LineChartBarData(
|
||||
spots: spots,
|
||||
isCurved: true,
|
||||
color: AppColors.primaryGreen,
|
||||
color: AppColors.primary,
|
||||
barWidth: 2,
|
||||
isStrokeCapRound: true,
|
||||
dotData: const FlDotData(show: true),
|
||||
belowBarData: BarAreaData(show: true, color: AppColors.primaryGreen.withOpacity(0.15)),
|
||||
belowBarData: BarAreaData(show: true, color: AppColors.primary.withOpacity(0.15)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import '../../../../core/utils/logger.dart';
|
||||
import '../../../../shared/design_system/tokens/app_colors.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../bloc/contributions_bloc.dart';
|
||||
import '../../bloc/contributions_event.dart';
|
||||
@@ -92,7 +93,7 @@ class _CreateContributionDialogState extends State<CreateContributionDialog> {
|
||||
enabled: false, // Lecture seule
|
||||
)
|
||||
else
|
||||
const Text('Impossible de récupérer votre profil', style: TextStyle(color: Colors.red)),
|
||||
const Text('Impossible de récupérer votre profil', style: TextStyle(color: AppColors.error)),
|
||||
const SizedBox(height: 16),
|
||||
|
||||
// Type de contribution
|
||||
@@ -225,7 +226,7 @@ class _CreateContributionDialogState extends State<CreateContributionDialog> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Profil non chargé'),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: AppColors.error,
|
||||
),
|
||||
);
|
||||
return;
|
||||
@@ -247,7 +248,7 @@ class _CreateContributionDialogState extends State<CreateContributionDialog> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Aucune organisation disponible. Le membre et l\'utilisateur connecté doivent être rattachés à une organisation.'),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: AppColors.error,
|
||||
),
|
||||
);
|
||||
setState(() => _isLoading = false);
|
||||
@@ -276,7 +277,7 @@ class _CreateContributionDialogState extends State<CreateContributionDialog> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Contribution créée avec succès'),
|
||||
backgroundColor: Colors.green,
|
||||
backgroundColor: AppColors.success,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@ library payment_dialog;
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../../shared/design_system/tokens/color_tokens.dart';
|
||||
import '../../../../shared/design_system/tokens/app_colors.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import 'package:unionflow_mobile_apps/core/di/injection.dart';
|
||||
@@ -65,8 +67,8 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
// En-tête
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: const BoxDecoration(
|
||||
color: Color(0xFF10B981),
|
||||
decoration: BoxDecoration(
|
||||
color: ColorTokens.successLight,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(4),
|
||||
topRight: Radius.circular(4),
|
||||
@@ -96,15 +98,16 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
// Informations de la cotisation
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
color: Colors.grey[100],
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.cotisation.membreNomComplet,
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 4),
|
||||
@@ -112,7 +115,7 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
widget.cotisation.libellePeriode,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.grey[600],
|
||||
color: Theme.of(context).colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -121,11 +124,14 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
children: [
|
||||
Text(
|
||||
'Montant total:',
|
||||
style: TextStyle(color: Colors.grey[600]),
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
Text(
|
||||
'${NumberFormat('#,###').format(widget.cotisation.montant)} ${widget.cotisation.devise}',
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -134,11 +140,11 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
children: [
|
||||
Text(
|
||||
'Déjà payé:',
|
||||
style: TextStyle(color: Colors.grey[600]),
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
Text(
|
||||
'${NumberFormat('#,###').format(widget.cotisation.montantPaye ?? 0)} ${widget.cotisation.devise}',
|
||||
style: const TextStyle(color: Colors.green),
|
||||
style: TextStyle(color: ColorTokens.success),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -147,13 +153,13 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
children: [
|
||||
Text(
|
||||
'Restant:',
|
||||
style: TextStyle(color: Colors.grey[600]),
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
|
||||
),
|
||||
Text(
|
||||
'${NumberFormat('#,###').format(widget.cotisation.montantRestant)} ${widget.cotisation.devise}',
|
||||
style: const TextStyle(
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.red,
|
||||
color: ColorTokens.error,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -297,8 +303,8 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[100],
|
||||
border: Border(top: BorderSide(color: Colors.grey[300]!)),
|
||||
color: Theme.of(context).colorScheme.surfaceContainerHighest,
|
||||
border: Border(top: BorderSide(color: Theme.of(context).colorScheme.outline)),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
@@ -311,7 +317,7 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
ElevatedButton(
|
||||
onPressed: _waveLoading ? null : _submitForm,
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFF10B981),
|
||||
backgroundColor: ColorTokens.successLight,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
child: _waveLoading
|
||||
@@ -415,7 +421,7 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Paiement enregistré avec succès'),
|
||||
backgroundColor: Colors.green,
|
||||
backgroundColor: ColorTokens.success,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -426,7 +432,7 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
final phone = _wavePhoneController.text.replaceAll(RegExp(r'\D'), '');
|
||||
if (phone.length < 9) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Indiquez votre numéro Wave (9 chiffres)'), backgroundColor: Colors.orange),
|
||||
const SnackBar(content: Text('Indiquez votre numéro Wave (9 chiffres)'), backgroundColor: AppColors.warning),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -453,7 +459,7 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(result.message),
|
||||
backgroundColor: Colors.green,
|
||||
backgroundColor: AppColors.success,
|
||||
),
|
||||
);
|
||||
context.read<ContributionsBloc>().add(const LoadContributions());
|
||||
@@ -462,7 +468,7 @@ class _PaymentDialogState extends State<PaymentDialog> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Wave: ${e.toString().replaceFirst('Exception: ', '')}'),
|
||||
backgroundColor: Colors.red,
|
||||
backgroundColor: AppColors.error,
|
||||
),
|
||||
);
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user