Refactoring - Version stable

This commit is contained in:
dahoud
2026-03-28 14:22:16 +00:00
parent 33134f834e
commit 11f9135f90
1167 changed files with 5266 additions and 384530 deletions

View File

@@ -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(),

View File

@@ -1,4 +1,3 @@
import 'dart:convert';
import 'cache_service.dart';
import '../utils/logger.dart';

View File

@@ -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';

View File

@@ -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'),
),
],
),
);
},
),
];
}

View File

@@ -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 {

View File

@@ -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';

View File

@@ -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';

View File

@@ -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(

View File

@@ -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';

View File

@@ -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';

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;

View File

@@ -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';

View File

@@ -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';

View File

@@ -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';

View File

@@ -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,
),

View File

@@ -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

View File

@@ -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;
});
}
}

View File

@@ -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),
),
],
),

View File

@@ -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',

View File

@@ -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) ...[

View File

@@ -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()) {

View File

@@ -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 {

View File

@@ -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';

View File

@@ -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;

View File

@@ -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),

View File

@@ -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 {

View File

@@ -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
///

View File

@@ -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()) {

View File

@@ -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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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';

View File

@@ -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';

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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é.

View File

@@ -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.

View File

@@ -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