Refactoring - Version stable
This commit is contained in:
@@ -10,7 +10,7 @@ import '../../features/authentication/presentation/pages/login_page.dart';
|
||||
import '../../features/about/presentation/pages/about_page.dart';
|
||||
import '../../features/help/presentation/pages/help_support_page.dart';
|
||||
import '../../features/profile/presentation/pages/profile_page_wrapper.dart';
|
||||
import '../../features/organizations/presentation/pages/organizations_page.dart';
|
||||
import '../../features/organizations/presentation/pages/organizations_page_wrapper.dart';
|
||||
import '../../features/members/presentation/pages/members_page_wrapper.dart';
|
||||
import '../../features/events/presentation/pages/events_page_wrapper.dart';
|
||||
import '../../features/solidarity/presentation/pages/demandes_aide_page_wrapper.dart';
|
||||
@@ -49,17 +49,29 @@ class AppRouter {
|
||||
'/about': (context) => const AboutPage(),
|
||||
'/help': (context) => const HelpSupportPage(),
|
||||
'/profile': (context) => const ProfilePageWrapper(),
|
||||
'/organizations': (context) => const OrganizationsPage(),
|
||||
'/organizations': (context) => const OrganizationsPageWrapper(),
|
||||
'/members': (context) => const MembersPageWrapper(),
|
||||
'/events': (context) => const EventsPageWrapper(),
|
||||
'/solidarity': (context) => const DemandesAidePageWrapper(),
|
||||
'/reports': (context) => const ReportsPageWrapper(),
|
||||
'/finances': (context) => const ContributionsPageWrapper(),
|
||||
'/my-finances': (context) => const ContributionsPageWrapper(),
|
||||
'/finances': (context) => const CotisationsPageWrapper(),
|
||||
'/my-finances': (context) => const CotisationsPageWrapper(),
|
||||
'/moderation': (context) => const AdhesionsPageWrapper(),
|
||||
'/communication': (context) => const ConversationsPage(),
|
||||
'/org-settings': (context) => const SystemSettingsPage(),
|
||||
'/analytics': (context) => const AdvancedDashboardPage(organizationId: '', userId: ''),
|
||||
'/analytics': (context) {
|
||||
final authState = context.read<AuthBloc>().state;
|
||||
if (authState is AuthAuthenticated) {
|
||||
final orgId = authState.user.organizationContexts.isNotEmpty
|
||||
? authState.user.organizationContexts.first.organizationId
|
||||
: '';
|
||||
return AdvancedDashboardPage(
|
||||
organizationId: orgId,
|
||||
userId: authState.user.id,
|
||||
);
|
||||
}
|
||||
return const LoginPage();
|
||||
},
|
||||
'/security': (context) => const SystemSettingsPage(),
|
||||
'/system-admin': (context) => const MainNavigationLayout(),
|
||||
'/global-users': (context) => const UserManagementPage(),
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'dart:convert';
|
||||
import 'cache_service.dart';
|
||||
import '../utils/logger.dart';
|
||||
|
||||
|
||||
@@ -9,20 +9,6 @@ import '../../features/dashboard/presentation/pages/role_dashboards/role_dashboa
|
||||
import '../../features/dashboard/presentation/pages/role_dashboards/org_admin_dashboard_loader.dart';
|
||||
import '../../features/members/presentation/pages/members_page_wrapper.dart';
|
||||
import '../../features/events/presentation/pages/events_page_wrapper.dart';
|
||||
import '../../features/contributions/presentation/pages/contributions_page_wrapper.dart';
|
||||
import '../../features/adhesions/presentation/pages/adhesions_page_wrapper.dart';
|
||||
import '../../features/solidarity/presentation/pages/demandes_aide_page_wrapper.dart';
|
||||
import '../../features/admin/presentation/pages/user_management_page.dart';
|
||||
|
||||
import '../../features/about/presentation/pages/about_page.dart';
|
||||
import '../../features/help/presentation/pages/help_support_page.dart';
|
||||
import '../../features/notifications/presentation/pages/notifications_page_wrapper.dart';
|
||||
import '../../features/profile/presentation/pages/profile_page_wrapper.dart';
|
||||
import '../../features/settings/presentation/pages/system_settings_page.dart';
|
||||
import '../../features/backup/presentation/pages/backup_page.dart';
|
||||
import '../../features/logs/presentation/pages/logs_page.dart';
|
||||
import '../../features/reports/presentation/pages/reports_page_wrapper.dart';
|
||||
import '../../features/epargne/presentation/pages/epargne_page.dart';
|
||||
|
||||
import '../../features/dashboard/presentation/bloc/dashboard_bloc.dart';
|
||||
import '../di/injection.dart';
|
||||
|
||||
@@ -16,6 +16,7 @@ import '../../features/contributions/presentation/pages/contributions_page_wrapp
|
||||
import '../../features/adhesions/presentation/pages/adhesions_page_wrapper.dart';
|
||||
import '../../features/solidarity/presentation/pages/demandes_aide_page_wrapper.dart';
|
||||
import '../../features/organizations/presentation/pages/organizations_page_wrapper.dart';
|
||||
import '../../features/profile/presentation/pages/profile_page_wrapper.dart';
|
||||
|
||||
/// Page "Plus" avec les fonctions avancées selon le rôle (Menu Principal Extensif)
|
||||
class MorePage extends StatelessWidget {
|
||||
@@ -43,7 +44,7 @@ class MorePage extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Profil utilisateur
|
||||
_buildUserProfile(state),
|
||||
_buildUserProfile(context, state),
|
||||
const SizedBox(height: SpacingTokens.md),
|
||||
|
||||
// Options selon le rôle
|
||||
@@ -61,8 +62,11 @@ class MorePage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUserProfile(AuthAuthenticated state) {
|
||||
Widget _buildUserProfile(BuildContext context, AuthAuthenticated state) {
|
||||
return CoreCard(
|
||||
onTap: () => Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (context) => const ProfilePageWrapper()),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
MiniAvatar(
|
||||
@@ -89,6 +93,7 @@ class MorePage extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
const Icon(Icons.chevron_right, color: AppColors.textSecondaryLight, size: 16),
|
||||
],
|
||||
),
|
||||
);
|
||||
@@ -219,6 +224,16 @@ class MorePage extends StatelessWidget {
|
||||
List<Widget> _buildCommonOptions(BuildContext context) {
|
||||
return [
|
||||
_buildSectionTitle('Général'),
|
||||
_buildOptionTile(
|
||||
icon: Icons.person_outline,
|
||||
title: 'Mon profil',
|
||||
subtitle: 'Voir et modifier mon profil',
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(builder: (context) => const ProfilePageWrapper()),
|
||||
);
|
||||
},
|
||||
),
|
||||
_buildOptionTile(
|
||||
icon: Icons.payment,
|
||||
title: 'Cotisations',
|
||||
@@ -259,6 +274,36 @@ class MorePage extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
_buildOptionTile(
|
||||
icon: Icons.logout,
|
||||
title: 'Déconnexion',
|
||||
subtitle: 'Se déconnecter de l\'application',
|
||||
color: AppColors.error,
|
||||
onTap: () {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
title: const Text('Déconnexion'),
|
||||
content: const Text('Voulez-vous vraiment vous déconnecter ?'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
child: const Text('Annuler'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(ctx).pop();
|
||||
context.read<AuthBloc>().add(AuthLogoutRequested());
|
||||
},
|
||||
style: TextButton.styleFrom(foregroundColor: AppColors.error),
|
||||
child: const Text('Déconnecter'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ library logger;
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import '../config/environment.dart';
|
||||
import '../constants/app_constants.dart';
|
||||
|
||||
/// Niveaux de log
|
||||
enum LogLevel {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
/// Interface avec l'API backend AdhesionResource
|
||||
library adhesion_repository;
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:unionflow_mobile_apps/core/network/api_client.dart';
|
||||
import '../models/adhesion_model.dart';
|
||||
|
||||
@@ -4,7 +4,6 @@ import 'package:intl/intl.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
import '../../../../shared/widgets/core_card.dart';
|
||||
import '../../../../shared/widgets/info_badge.dart';
|
||||
import '../../../../shared/widgets/mini_avatar.dart';
|
||||
import '../../bloc/adhesions_bloc.dart';
|
||||
import '../../data/models/adhesion_model.dart';
|
||||
import '../widgets/paiement_adhesion_dialog.dart';
|
||||
|
||||
@@ -23,8 +23,8 @@ class AdminUsersBloc extends Bloc<AdminUsersEvent, AdminUsersState> {
|
||||
emit(AdminUsersLoading());
|
||||
try {
|
||||
final result = await _repository.search(
|
||||
page: e.page ?? 0,
|
||||
size: e.size ?? 20,
|
||||
page: e.page,
|
||||
size: e.size,
|
||||
search: e.search,
|
||||
);
|
||||
emit(AdminUsersLoaded(
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/// Repository pour la gestion des utilisateurs admin (API /api/admin/users)
|
||||
library admin_user_repository;
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:unionflow_mobile_apps/core/network/api_client.dart';
|
||||
import '../models/admin_user_model.dart';
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
import 'dart:convert';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:jwt_decoder/jwt_decoder.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../models/user.dart';
|
||||
import '../models/user_role.dart';
|
||||
import 'keycloak_role_mapper.dart';
|
||||
import '../../../../core/config/environment.dart';
|
||||
import '../../../../core/utils/logger.dart';
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../../../core/utils/logger.dart';
|
||||
import '../data/models/contribution_model.dart';
|
||||
import '../data/repositories/contribution_repository.dart' show ContributionPageResult;
|
||||
import '../domain/usecases/get_contributions.dart';
|
||||
import '../domain/usecases/get_contribution_by_id.dart';
|
||||
import '../domain/usecases/create_contribution.dart' as uc;
|
||||
|
||||
@@ -532,7 +532,7 @@ class _MesStatistiquesCotisationsPageState extends State<MesStatistiquesCotisati
|
||||
const months = ['Jan', 'Fév', 'Mar', 'Avr', 'Mai', 'Juin', 'Juil', 'Août', 'Sep', 'Oct', 'Nov', 'Déc'];
|
||||
return '${dt.day} ${months[dt.month - 1]} ${dt.year}';
|
||||
}
|
||||
} catch (e, st) {
|
||||
} catch (e) {
|
||||
AppLogger.warning('MesStatistiquesCotisations: format date invalide', tag: isoOrRaw);
|
||||
}
|
||||
return isoOrRaw;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:unionflow_mobile_apps/core/network/api_client.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
@@ -12,7 +11,6 @@ import '../../../../core/storage/dashboard_cache_manager.dart';
|
||||
class DashboardOfflineService {
|
||||
static const String _offlineQueueKey = 'dashboard_offline_queue';
|
||||
static const String _lastSyncKey = 'dashboard_last_sync';
|
||||
static const String _offlineModeKey = 'dashboard_offline_mode';
|
||||
|
||||
final DashboardCacheManager _cacheManager;
|
||||
final ApiClient _apiClient;
|
||||
|
||||
@@ -7,7 +7,6 @@ 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 '../../domain/entities/dashboard_entity.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
import '../../../../shared/widgets/core_card.dart';
|
||||
import '../../../../core/di/injection_container.dart';
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../../../../shared/design_system/unionflow_design_v2.dart';
|
||||
import '../../bloc/dashboard_bloc.dart';
|
||||
import '../../../../authentication/presentation/bloc/auth_bloc.dart';
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:unionflow_mobile_apps/core/network/api_client.dart';
|
||||
import 'package:unionflow_mobile_apps/core/utils/logger.dart';
|
||||
|
||||
@@ -216,7 +216,7 @@ class _EpargneDetailPageState extends State<EpargneDetailPage> {
|
||||
children: [
|
||||
Text(
|
||||
c.numeroCompte ?? c.id ?? '—',
|
||||
style: TypographyTokens.titleMedium?.copyWith(
|
||||
style: TypographyTokens.titleMedium.copyWith(
|
||||
color: ColorTokens.onSurfaceVariant,
|
||||
letterSpacing: 0.5,
|
||||
),
|
||||
@@ -224,12 +224,12 @@ class _EpargneDetailPageState extends State<EpargneDetailPage> {
|
||||
if (_typeCompteLibelle(c.typeCompte) != null)
|
||||
Text(
|
||||
_typeCompteLibelle(c.typeCompte)!,
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
),
|
||||
const SizedBox(height: SpacingTokens.md),
|
||||
Text(
|
||||
'${c.soldeActuel.toStringAsFixed(0)} XOF',
|
||||
style: TypographyTokens.headlineMedium?.copyWith(
|
||||
style: TypographyTokens.headlineMedium.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: ColorTokens.primary,
|
||||
),
|
||||
@@ -237,18 +237,18 @@ class _EpargneDetailPageState extends State<EpargneDetailPage> {
|
||||
if (c.soldeBloque > 0)
|
||||
Text(
|
||||
'dont ${c.soldeBloque.toStringAsFixed(0)} XOF bloqué(s)',
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
),
|
||||
Text(
|
||||
'Disponible: ${soldeDispo.toStringAsFixed(0)} XOF',
|
||||
style: TypographyTokens.labelMedium?.copyWith(color: ColorTokens.primary),
|
||||
style: TypographyTokens.labelMedium.copyWith(color: ColorTokens.primary),
|
||||
),
|
||||
if (c.dateOuverture != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: SpacingTokens.sm),
|
||||
child: Text(
|
||||
'Ouvert le ${c.dateOuverture!.day.toString().padLeft(2, '0')}/${c.dateOuverture!.month.toString().padLeft(2, '0')}/${c.dateOuverture!.year}',
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
),
|
||||
),
|
||||
if (c.description != null && c.description!.isNotEmpty)
|
||||
@@ -256,7 +256,7 @@ class _EpargneDetailPageState extends State<EpargneDetailPage> {
|
||||
padding: const EdgeInsets.only(top: SpacingTokens.xs),
|
||||
child: Text(
|
||||
c.description!,
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -334,7 +334,7 @@ class _EpargneDetailPageState extends State<EpargneDetailPage> {
|
||||
padding: const EdgeInsets.all(SpacingTokens.lg),
|
||||
child: Text(
|
||||
'Aucune transaction',
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
)
|
||||
@@ -358,12 +358,12 @@ class _EpargneDetailPageState extends State<EpargneDetailPage> {
|
||||
subtitle: t.dateTransaction != null
|
||||
? Text(
|
||||
'${t.dateTransaction!.day.toString().padLeft(2, '0')}/${t.dateTransaction!.month.toString().padLeft(2, '0')}/${t.dateTransaction!.year} ${t.dateTransaction!.hour.toString().padLeft(2, '0')}:${t.dateTransaction!.minute.toString().padLeft(2, '0')}',
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
)
|
||||
: null,
|
||||
trailing: Text(
|
||||
'${t.isCredit ? '+' : '-'}${t.montant.toStringAsFixed(0)} XOF',
|
||||
style: TypographyTokens.titleSmall?.copyWith(
|
||||
style: TypographyTokens.titleSmall.copyWith(
|
||||
color: t.isCredit ? ColorTokens.success : ColorTokens.error,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
|
||||
@@ -198,7 +198,7 @@ class _CreerCompteEpargneDialogState extends State<CreerCompteEpargneDialog> {
|
||||
items: _organisations
|
||||
.map((o) => DropdownMenuItem(
|
||||
value: o.id,
|
||||
child: Text(o.nom ?? o.id ?? '', overflow: TextOverflow.ellipsis, maxLines: 1),
|
||||
child: Text(o.nom, overflow: TextOverflow.ellipsis, maxLines: 1),
|
||||
))
|
||||
.toList(),
|
||||
onChanged: _submitting
|
||||
|
||||
@@ -45,7 +45,6 @@ class _DepotEpargneDialogState extends State<DepotEpargneDialog> {
|
||||
|
||||
/// Seuil LCB-FT récupéré depuis l'API (fallback à 500k XOF).
|
||||
double _seuilLcbFt = kSeuilOrigineFondsObligatoireXOF;
|
||||
bool _seuilLoaded = false;
|
||||
|
||||
/// Pièce justificative pour opérations au-dessus du seuil
|
||||
File? _pieceJustificative;
|
||||
@@ -66,7 +65,6 @@ class _DepotEpargneDialogState extends State<DepotEpargneDialog> {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_seuilLcbFt = seuil.montantSeuil;
|
||||
_seuilLoaded = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ class _HistoriqueEpargneSheetState extends State<HistoriqueEpargneSheet> {
|
||||
? Center(
|
||||
child: Text(
|
||||
'Aucune transaction',
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
@@ -167,12 +167,12 @@ class _HistoriqueEpargneSheetState extends State<HistoriqueEpargneSheet> {
|
||||
if (t.dateTransaction != null)
|
||||
Text(
|
||||
'${t.dateTransaction!.day.toString().padLeft(2, '0')}/${t.dateTransaction!.month.toString().padLeft(2, '0')}/${t.dateTransaction!.year} ${t.dateTransaction!.hour.toString().padLeft(2, '0')}:${t.dateTransaction!.minute.toString().padLeft(2, '0')}',
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
),
|
||||
if (t.motif != null && t.motif!.isNotEmpty)
|
||||
Text(
|
||||
t.motif!,
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
@@ -184,14 +184,14 @@ class _HistoriqueEpargneSheetState extends State<HistoriqueEpargneSheet> {
|
||||
children: [
|
||||
Text(
|
||||
'${t.isCredit ? '+' : '-'}${t.montant.toStringAsFixed(0)} XOF',
|
||||
style: TypographyTokens.titleSmall?.copyWith(
|
||||
style: TypographyTokens.titleSmall.copyWith(
|
||||
color: t.isCredit ? ColorTokens.success : ColorTokens.error,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Solde: ${t.soldeApres.toStringAsFixed(0)}',
|
||||
style: TypographyTokens.labelSmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.labelSmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -44,7 +44,6 @@ class _RetraitEpargneDialogState extends State<RetraitEpargneDialog> {
|
||||
|
||||
/// Seuil LCB-FT récupéré depuis l'API (fallback à 500k XOF).
|
||||
double _seuilLcbFt = kSeuilOrigineFondsObligatoireXOF;
|
||||
bool _seuilLoaded = false;
|
||||
|
||||
/// Pièce justificative pour opérations au-dessus du seuil
|
||||
File? _pieceJustificative;
|
||||
@@ -65,7 +64,6 @@ class _RetraitEpargneDialogState extends State<RetraitEpargneDialog> {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_seuilLcbFt = seuil.montantSeuil;
|
||||
_seuilLoaded = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -197,7 +195,7 @@ class _RetraitEpargneDialogState extends State<RetraitEpargneDialog> {
|
||||
children: [
|
||||
Text(
|
||||
widget.numeroCompte,
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
),
|
||||
Text(
|
||||
'Solde disponible: ${widget.soldeDisponible.toStringAsFixed(0)} XOF',
|
||||
|
||||
@@ -43,7 +43,6 @@ class _TransfertEpargneDialogState extends State<TransfertEpargneDialog> {
|
||||
|
||||
/// Seuil LCB-FT récupéré depuis l'API (fallback à 500k XOF).
|
||||
double _seuilLcbFt = kSeuilOrigineFondsObligatoireXOF;
|
||||
bool _seuilLoaded = false;
|
||||
|
||||
/// Pièce justificative pour opérations au-dessus du seuil
|
||||
File? _pieceJustificative;
|
||||
@@ -77,7 +76,6 @@ class _TransfertEpargneDialogState extends State<TransfertEpargneDialog> {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_seuilLcbFt = seuil.montantSeuil;
|
||||
_seuilLoaded = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -242,7 +240,7 @@ class _TransfertEpargneDialogState extends State<TransfertEpargneDialog> {
|
||||
children: [
|
||||
Text(
|
||||
'De: ${widget.compteSource.numeroCompte ?? widget.compteSource.id}',
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.onSurfaceVariant),
|
||||
),
|
||||
Text(
|
||||
'Solde disponible: ${(widget.compteSource.soldeActuel - widget.compteSource.soldeBloque).toStringAsFixed(0)} XOF',
|
||||
@@ -310,7 +308,7 @@ class _TransfertEpargneDialogState extends State<TransfertEpargneDialog> {
|
||||
padding: const EdgeInsets.only(top: 8),
|
||||
child: Text(
|
||||
'Requis pour les opérations ≥ ${_seuilLcbFt.toStringAsFixed(0)} XOF',
|
||||
style: TypographyTokens.bodySmall?.copyWith(color: ColorTokens.primary),
|
||||
style: TypographyTokens.bodySmall.copyWith(color: ColorTokens.primary),
|
||||
),
|
||||
),
|
||||
if (_origineFondsRequis) ...[
|
||||
|
||||
@@ -13,7 +13,6 @@ import '../domain/usecases/update_event.dart' as uc;
|
||||
import '../domain/usecases/delete_event.dart' as uc;
|
||||
import '../domain/usecases/register_for_event.dart';
|
||||
import '../domain/usecases/cancel_registration.dart';
|
||||
import '../domain/usecases/get_my_registrations.dart';
|
||||
import '../domain/usecases/get_event_participants.dart';
|
||||
import '../domain/repositories/evenement_repository.dart';
|
||||
|
||||
@@ -27,7 +26,6 @@ class EvenementsBloc extends Bloc<EvenementsEvent, EvenementsState> {
|
||||
final uc.DeleteEvent _deleteEvent;
|
||||
final RegisterForEvent _registerForEvent;
|
||||
final CancelRegistration _cancelRegistration;
|
||||
final GetMyRegistrations _getMyRegistrations;
|
||||
final GetEventParticipants _getEventParticipants;
|
||||
final IEvenementRepository _repository; // Pour méthodes non-couvertes par use cases
|
||||
|
||||
@@ -39,7 +37,6 @@ class EvenementsBloc extends Bloc<EvenementsEvent, EvenementsState> {
|
||||
this._deleteEvent,
|
||||
this._registerForEvent,
|
||||
this._cancelRegistration,
|
||||
this._getMyRegistrations,
|
||||
this._getEventParticipants,
|
||||
this._repository,
|
||||
) : super(const EvenementsInitial()) {
|
||||
|
||||
@@ -9,8 +9,6 @@ import '../../../../core/config/environment.dart';
|
||||
import '../../../../core/error/exceptions.dart';
|
||||
import '../models/transaction_approval_model.dart';
|
||||
import '../models/budget_model.dart';
|
||||
import '../../domain/entities/transaction_approval.dart';
|
||||
import '../../domain/entities/budget.dart';
|
||||
|
||||
@lazySingleton
|
||||
class FinanceWorkflowRemoteDatasource {
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../../core/di/injection_container.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../../../core/di/injection_container.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
import '../../domain/entities/transaction_approval.dart';
|
||||
import '../bloc/approval_bloc.dart';
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
||||
import '../../../../core/di/injection_container.dart';
|
||||
import '../../../../shared/models/membre_search_criteria.dart';
|
||||
import '../../../../shared/models/membre_search_result.dart';
|
||||
import '../../../organizations/data/repositories/organization_repository.dart';
|
||||
import '../../../organizations/domain/repositories/organization_repository.dart';
|
||||
import '../../../organizations/data/models/organization_model.dart';
|
||||
import '../../data/services/membre_search_service.dart';
|
||||
import '../widgets/membre_search_results.dart';
|
||||
@@ -43,7 +43,6 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
||||
final List<String> _selectedRoles = [];
|
||||
final List<String> _selectedOrganisations = [];
|
||||
RangeValues _ageRange = const RangeValues(18, 65);
|
||||
DateTimeRange? _adhesionDateRange;
|
||||
bool _includeInactifs = false;
|
||||
bool _membreBureau = false;
|
||||
bool _responsable = false;
|
||||
@@ -84,7 +83,7 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
||||
Future<void> _loadOrganisations() async {
|
||||
if (_organisationsLoaded) return;
|
||||
try {
|
||||
final repo = sl<OrganizationRepository>();
|
||||
final repo = sl<IOrganizationRepository>();
|
||||
final list = await repo.getOrganizations(page: 0, size: 200);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
@@ -683,7 +682,6 @@ class _AdvancedSearchPageState extends State<AdvancedSearchPage>
|
||||
_selectedRoles.clear();
|
||||
_selectedOrganisations.clear();
|
||||
_ageRange = const RangeValues(18, 65);
|
||||
_adhesionDateRange = null;
|
||||
_includeInactifs = false;
|
||||
_membreBureau = false;
|
||||
_responsable = false;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
import '../../../../features/authentication/presentation/bloc/auth_bloc.dart';
|
||||
import '../../../../features/authentication/data/models/user_role.dart';
|
||||
@@ -32,8 +31,6 @@ class _MembersPageState extends State<MembersPage> with TickerProviderStateMixin
|
||||
|
||||
// Filtres avancés
|
||||
final List<String> _selectedRoles = [];
|
||||
List<String> _selectedStatuses = ['Actif', 'Inactif', 'Suspendu', 'En attente'];
|
||||
DateTimeRange? _dateRange;
|
||||
|
||||
// Données de démonstration enrichies
|
||||
final List<Map<String, dynamic>> _allMembers = [
|
||||
@@ -614,8 +611,6 @@ class _MembersPageState extends State<MembersPage> with TickerProviderStateMixin
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedRoles.clear();
|
||||
_selectedStatuses = ['Actif', 'Inactif', 'Suspendu', 'En attente'];
|
||||
_dateRange = null;
|
||||
});
|
||||
},
|
||||
icon: const Icon(Icons.clear_all, size: 16),
|
||||
|
||||
@@ -3,7 +3,6 @@ import 'package:flutter/material.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_v2.dart';
|
||||
import '../../../../shared/design_system/components/uf_app_bar.dart';
|
||||
import '../../../../core/constants/app_constants.dart';
|
||||
import '../widgets/add_member_dialog.dart';
|
||||
|
||||
/// Annuaire des Membres - Design UnionFlow
|
||||
class MembersPageWithDataAndPagination extends StatefulWidget {
|
||||
|
||||
@@ -10,8 +10,6 @@ import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
import '../../../../shared/widgets/core_card.dart';
|
||||
import '../../../../shared/widgets/mini_avatar.dart';
|
||||
import '../../../../shared/widgets/info_badge.dart';
|
||||
import '../../../../shared/design_system/components/uf_app_bar.dart';
|
||||
import '../../../../shared/design_system/components/uf_buttons.dart';
|
||||
|
||||
/// Page Notifications - UnionFlow Mobile
|
||||
///
|
||||
|
||||
@@ -10,8 +10,6 @@ import '../domain/usecases/get_organization_by_id.dart';
|
||||
import '../domain/usecases/create_organization.dart' as uc;
|
||||
import '../domain/usecases/update_organization.dart' as uc;
|
||||
import '../domain/usecases/delete_organization.dart' as uc;
|
||||
import '../domain/usecases/get_organization_members.dart';
|
||||
import '../domain/usecases/update_organization_config.dart';
|
||||
import '../domain/repositories/organization_repository.dart';
|
||||
import 'organizations_event.dart';
|
||||
import 'organizations_state.dart';
|
||||
@@ -24,8 +22,6 @@ class OrganizationsBloc extends Bloc<OrganizationsEvent, OrganizationsState> {
|
||||
final uc.CreateOrganization _createOrganization;
|
||||
final uc.UpdateOrganization _updateOrganization;
|
||||
final uc.DeleteOrganization _deleteOrganization;
|
||||
final GetOrganizationMembers _getOrganizationMembers;
|
||||
final UpdateOrganizationConfig _updateOrganizationConfig;
|
||||
final IOrganizationRepository _repository; // Pour méthodes non-couvertes (activate, suspend, search, stats)
|
||||
final OrganizationService _organizationService; // Pour helpers (sort, filter local)
|
||||
|
||||
@@ -35,8 +31,6 @@ class OrganizationsBloc extends Bloc<OrganizationsEvent, OrganizationsState> {
|
||||
this._createOrganization,
|
||||
this._updateOrganization,
|
||||
this._deleteOrganization,
|
||||
this._getOrganizationMembers,
|
||||
this._updateOrganizationConfig,
|
||||
this._repository,
|
||||
this._organizationService,
|
||||
) : super(const OrganizationsInitial()) {
|
||||
|
||||
@@ -7,10 +7,6 @@ import 'package:injectable/injectable.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import '../../domain/usecases/get_profile.dart';
|
||||
import '../../domain/usecases/update_profile.dart';
|
||||
import '../../domain/usecases/update_avatar.dart';
|
||||
import '../../domain/usecases/change_password.dart';
|
||||
import '../../domain/usecases/update_preferences.dart';
|
||||
import '../../domain/usecases/delete_account.dart';
|
||||
import '../../domain/repositories/profile_repository.dart';
|
||||
import '../../../members/data/models/membre_complete_model.dart';
|
||||
|
||||
@@ -22,19 +18,11 @@ part 'profile_state.dart';
|
||||
class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
|
||||
final GetProfile _getProfile;
|
||||
final UpdateProfile _updateProfile;
|
||||
final UpdateAvatar _updateAvatar;
|
||||
final ChangePassword _changePassword;
|
||||
final UpdatePreferences _updatePreferences;
|
||||
final DeleteAccount _deleteAccount;
|
||||
final IProfileRepository _repository; // Pour méthodes non-couvertes (getProfileByEmail)
|
||||
|
||||
ProfileBloc(
|
||||
this._getProfile,
|
||||
this._updateProfile,
|
||||
this._updateAvatar,
|
||||
this._changePassword,
|
||||
this._updatePreferences,
|
||||
this._deleteAccount,
|
||||
this._repository,
|
||||
) : super(const ProfileInitial()) {
|
||||
on<LoadMe>(_onLoadMe);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'dart:io';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
@@ -42,7 +41,6 @@ class _ProfilePageState extends State<ProfilePage>
|
||||
final _bioController = TextEditingController();
|
||||
|
||||
// État du profil
|
||||
File? _profileImage;
|
||||
bool _isEditing = false;
|
||||
bool _isLoading = false;
|
||||
String? _membreId;
|
||||
|
||||
@@ -4,12 +4,8 @@ library reports_bloc;
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import '../../domain/usecases/get_reports.dart';
|
||||
import '../../domain/usecases/generate_report.dart';
|
||||
import '../../domain/usecases/export_report_pdf.dart';
|
||||
import '../../domain/usecases/export_report_excel.dart';
|
||||
import '../../domain/usecases/schedule_report.dart';
|
||||
import '../../domain/usecases/get_scheduled_reports.dart';
|
||||
import '../../domain/repositories/reports_repository.dart';
|
||||
|
||||
part 'reports_event.dart';
|
||||
@@ -18,21 +14,13 @@ part 'reports_state.dart';
|
||||
/// BLoC pour la gestion des rapports (Clean Architecture)
|
||||
@injectable
|
||||
class ReportsBloc extends Bloc<ReportsEvent, ReportsState> {
|
||||
final GetReports _getReports;
|
||||
final GenerateReport _generateReport;
|
||||
final ExportReportPdf _exportReportPdf;
|
||||
final ExportReportExcel _exportReportExcel;
|
||||
final ScheduleReport _scheduleReport;
|
||||
final GetScheduledReports _getScheduledReports;
|
||||
final IReportsRepository _repository; // Pour méthodes non-couvertes (statistics, analytics)
|
||||
|
||||
ReportsBloc(
|
||||
this._getReports,
|
||||
this._generateReport,
|
||||
this._exportReportPdf,
|
||||
this._exportReportExcel,
|
||||
this._scheduleReport,
|
||||
this._getScheduledReports,
|
||||
this._repository,
|
||||
) : super(const ReportsInitial()) {
|
||||
on<LoadDashboardReports>(_onLoadDashboard);
|
||||
|
||||
@@ -29,7 +29,6 @@ class _ReportsPageState extends State<ReportsPage>
|
||||
Map<String, dynamic> _statsMembres = {};
|
||||
Map<String, dynamic> _statsCotisations = {};
|
||||
Map<String, dynamic> _statsEvenements = {};
|
||||
Map<String, dynamic> _performance = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -52,7 +51,6 @@ class _ReportsPageState extends State<ReportsPage>
|
||||
listener: (context, state) {
|
||||
if (state is ReportsDashboardLoaded) {
|
||||
setState(() {
|
||||
_performance = state.performance;
|
||||
_statsMembres = state.statsMembres;
|
||||
_statsCotisations = state.statsCotisations;
|
||||
_statsEvenements = state.statsEvenements;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
/// Note: le backend doit exposer DemandeAideResource pour que les appels fonctionnent.
|
||||
library demande_aide_repository;
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:unionflow_mobile_apps/core/network/api_client.dart';
|
||||
import '../models/demande_aide_model.dart';
|
||||
|
||||
@@ -3,8 +3,6 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import '../../../../shared/design_system/unionflow_design_system.dart';
|
||||
import '../../../../shared/widgets/core_card.dart';
|
||||
import '../../../../shared/widgets/info_badge.dart';
|
||||
import '../../../../shared/widgets/mini_avatar.dart';
|
||||
import '../../bloc/solidarity_bloc.dart';
|
||||
import '../../data/models/demande_aide_model.dart';
|
||||
import '../../../authentication/presentation/bloc/auth_bloc.dart';
|
||||
|
||||
@@ -8,7 +8,6 @@ import '../../../../shared/widgets/mini_avatar.dart';
|
||||
import '../../bloc/solidarity_bloc.dart';
|
||||
import '../../data/models/demande_aide_model.dart';
|
||||
import 'demande_aide_detail_page.dart';
|
||||
import '../widgets/create_demande_aide_dialog.dart';
|
||||
import '../../../authentication/presentation/bloc/auth_bloc.dart';
|
||||
|
||||
/// Page liste des demandes d'aide (solidarité) - Version Épurée
|
||||
|
||||
@@ -286,6 +286,7 @@ class _UnifiedFeedViewState extends State<_UnifiedFeedView> {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Impossible d\'ouvrir le lien.')),
|
||||
);
|
||||
return false;
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@ import '../../../features/settings/presentation/pages/system_settings_page.dart'
|
||||
import '../../../features/help/presentation/pages/help_support_page.dart';
|
||||
import '../../../shared/design_system/unionflow_design_system.dart';
|
||||
import '../../../shared/widgets/mini_avatar.dart';
|
||||
import '../../../shared/widgets/action_row.dart';
|
||||
import '../../../shared/widgets/info_badge.dart';
|
||||
|
||||
/// UnionFlow Mobile - Composant DRY : Menu Profil Latéral
|
||||
/// Un tiroir (drawer) de style réseau social (Twitter/Facebook) très épuré.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'app_colors.dart';
|
||||
|
||||
/// UnionFlow Mobile App - Typographie Globale (Ultra Minimaliste)
|
||||
/// RÈGLE : AUCUN gros titre. Tailles limitées entre 10px et 14px pour maximiser l'information.
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
import '../design_system/tokens/app_colors.dart';
|
||||
import 'core_card.dart';
|
||||
|
||||
/// UnionFlow Mobile - Composant DRY : CoreShimmer
|
||||
|
||||
Reference in New Issue
Block a user