Refactoring
This commit is contained in:
@@ -132,8 +132,15 @@ class _MembreEditPageState extends State<MembreEditPage>
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider.value(
|
||||
value: _membresBloc,
|
||||
child: WillPopScope(
|
||||
onWillPop: _onWillPop,
|
||||
child: PopScope(
|
||||
canPop: !_hasChanges,
|
||||
onPopInvokedWithResult: (didPop, result) async {
|
||||
if (didPop) return;
|
||||
final shouldPop = await _onWillPop();
|
||||
if (shouldPop && context.mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
backgroundColor: AppTheme.backgroundLight,
|
||||
appBar: _buildAppBar(),
|
||||
|
||||
@@ -14,6 +14,14 @@ import '../widgets/dashboard/members_recent_activities_widget.dart';
|
||||
import '../widgets/dashboard/members_advanced_filters_widget.dart';
|
||||
import '../widgets/dashboard/members_smart_search_widget.dart';
|
||||
import '../widgets/dashboard/members_notifications_widget.dart';
|
||||
import 'membre_edit_page.dart';
|
||||
|
||||
// Import de l'architecture unifiée pour amélioration progressive
|
||||
import '../../../../shared/widgets/common/unified_page_layout.dart';
|
||||
|
||||
// Imports des optimisations de performance
|
||||
import '../../../../core/performance/performance_optimizer.dart';
|
||||
import '../../../../shared/widgets/performance/optimized_list_view.dart';
|
||||
|
||||
class MembresDashboardPage extends StatefulWidget {
|
||||
const MembresDashboardPage({super.key});
|
||||
@@ -73,87 +81,32 @@ class _MembresDashboardPageState extends State<MembresDashboardPage> {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider.value(
|
||||
value: _membresBloc,
|
||||
child: Scaffold(
|
||||
backgroundColor: AppTheme.backgroundLight,
|
||||
appBar: AppBar(
|
||||
title: const Text(
|
||||
'Dashboard Membres',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: 20,
|
||||
),
|
||||
),
|
||||
backgroundColor: AppTheme.primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
elevation: 0,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
child: BlocBuilder<MembresBloc, MembresState>(
|
||||
builder: (context, state) {
|
||||
// Utilisation de UnifiedPageLayout pour améliorer la cohérence
|
||||
// tout en conservant TOUS les widgets spécialisés existants
|
||||
return UnifiedPageLayout(
|
||||
title: 'Dashboard Membres',
|
||||
icon: Icons.people,
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: _loadData,
|
||||
tooltip: 'Actualiser',
|
||||
),
|
||||
],
|
||||
isLoading: state is MembresLoading,
|
||||
errorMessage: state is MembresError ? state.message : null,
|
||||
onRefresh: _loadData,
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _loadData,
|
||||
tooltip: 'Actualiser',
|
||||
backgroundColor: AppTheme.primaryColor,
|
||||
tooltip: 'Actualiser les données',
|
||||
child: const Icon(Icons.refresh, color: Colors.white),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: BlocBuilder<MembresBloc, MembresState>(
|
||||
builder: (context, state) {
|
||||
if (state is MembresLoading) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(),
|
||||
);
|
||||
}
|
||||
|
||||
if (state is MembresError) {
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error_outline,
|
||||
size: 64,
|
||||
color: AppTheme.errorColor,
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
const Text(
|
||||
'Erreur de chargement',
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppTheme.textPrimary,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
state.message,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
ElevatedButton.icon(
|
||||
onPressed: _loadData,
|
||||
icon: const Icon(Icons.refresh),
|
||||
label: const Text('Réessayer'),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: AppTheme.primaryColor,
|
||||
foregroundColor: Colors.white,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return _buildDashboard();
|
||||
},
|
||||
),
|
||||
floatingActionButton: FloatingActionButton(
|
||||
onPressed: _loadData,
|
||||
backgroundColor: AppTheme.primaryColor,
|
||||
tooltip: 'Actualiser les données',
|
||||
child: const Icon(Icons.refresh, color: Colors.white),
|
||||
),
|
||||
body: _buildDashboard(),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -234,14 +187,17 @@ class _MembresDashboardPageState extends State<MembresDashboardPage> {
|
||||
),
|
||||
);
|
||||
},
|
||||
onMemberEdit: (member) {
|
||||
// TODO: Modifier le membre
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Modification de ${member.nomComplet}'),
|
||||
backgroundColor: AppTheme.warningColor,
|
||||
onMemberEdit: (member) async {
|
||||
final result = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MembreEditPage(membre: member),
|
||||
),
|
||||
);
|
||||
|
||||
if (result == true) {
|
||||
// Recharger les données si le membre a été modifié
|
||||
_membresBloc.add(const LoadMembres());
|
||||
}
|
||||
},
|
||||
searchQuery: _currentSearchQuery,
|
||||
filters: _currentFilters,
|
||||
|
||||
@@ -0,0 +1,488 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import '../../../../core/di/injection.dart';
|
||||
import '../../../../shared/widgets/unified_components.dart';
|
||||
import '../../../../shared/theme/app_theme.dart';
|
||||
import '../../../../core/models/membre_model.dart';
|
||||
import '../bloc/membres_bloc.dart';
|
||||
import '../bloc/membres_event.dart';
|
||||
import '../bloc/membres_state.dart';
|
||||
|
||||
/// Dashboard des membres UnionFlow - Version Unifiée
|
||||
///
|
||||
/// Utilise l'architecture unifiée pour une expérience cohérente :
|
||||
/// - Composants standardisés réutilisables
|
||||
/// - Interface homogène avec les autres onglets
|
||||
/// - Performance optimisée avec animations fluides
|
||||
/// - Maintenabilité maximale
|
||||
class MembresDashboardPageUnified extends StatefulWidget {
|
||||
const MembresDashboardPageUnified({super.key});
|
||||
|
||||
@override
|
||||
State<MembresDashboardPageUnified> createState() => _MembresDashboardPageUnifiedState();
|
||||
}
|
||||
|
||||
class _MembresDashboardPageUnifiedState extends State<MembresDashboardPageUnified> {
|
||||
late MembresBloc _membresBloc;
|
||||
Map<String, dynamic> _currentFilters = {};
|
||||
String _currentSearchQuery = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_membresBloc = getIt<MembresBloc>();
|
||||
_loadData();
|
||||
}
|
||||
|
||||
void _loadData() {
|
||||
_membresBloc.add(const LoadMembres());
|
||||
}
|
||||
|
||||
void _onFiltersChanged(Map<String, dynamic> filters) {
|
||||
setState(() {
|
||||
_currentFilters = filters;
|
||||
});
|
||||
_loadData();
|
||||
}
|
||||
|
||||
void _onSearchChanged(String query) {
|
||||
setState(() {
|
||||
_currentSearchQuery = query;
|
||||
});
|
||||
if (query.isNotEmpty) {
|
||||
_membresBloc.add(SearchMembres(query));
|
||||
} else {
|
||||
_loadData();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider.value(
|
||||
value: _membresBloc,
|
||||
child: BlocBuilder<MembresBloc, MembresState>(
|
||||
builder: (context, state) {
|
||||
return UnifiedPageLayout(
|
||||
title: 'Membres',
|
||||
subtitle: 'Gestion des membres de l\'association',
|
||||
icon: Icons.people,
|
||||
iconColor: AppTheme.primaryColor,
|
||||
isLoading: state is MembresLoading,
|
||||
errorMessage: state is MembresError ? state.message : null,
|
||||
onRefresh: _loadData,
|
||||
actions: _buildActions(),
|
||||
body: Column(
|
||||
children: [
|
||||
_buildSearchSection(),
|
||||
const SizedBox(height: AppTheme.spacingLarge),
|
||||
_buildKPISection(state),
|
||||
const SizedBox(height: AppTheme.spacingLarge),
|
||||
_buildQuickActionsSection(),
|
||||
const SizedBox(height: AppTheme.spacingLarge),
|
||||
_buildFiltersSection(),
|
||||
const SizedBox(height: AppTheme.spacingLarge),
|
||||
Expanded(child: _buildMembersList(state)),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Actions de la barre d'outils
|
||||
List<Widget> _buildActions() {
|
||||
return [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.person_add),
|
||||
onPressed: () {
|
||||
// TODO: Navigation vers ajout membre
|
||||
},
|
||||
tooltip: 'Ajouter un membre',
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.import_export),
|
||||
onPressed: () {
|
||||
// TODO: Import/Export des membres
|
||||
},
|
||||
tooltip: 'Import/Export',
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.analytics),
|
||||
onPressed: () {
|
||||
// TODO: Navigation vers analyses détaillées
|
||||
},
|
||||
tooltip: 'Analyses',
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
/// Section de recherche intelligente
|
||||
Widget _buildSearchSection() {
|
||||
return UnifiedCard.outlined(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(AppTheme.spacingMedium),
|
||||
child: Column(
|
||||
children: [
|
||||
TextField(
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Rechercher un membre...',
|
||||
prefixIcon: const Icon(Icons.search),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(AppTheme.borderRadiusMedium),
|
||||
borderSide: BorderSide.none,
|
||||
),
|
||||
filled: true,
|
||||
fillColor: AppTheme.backgroundLight,
|
||||
),
|
||||
onChanged: _onSearchChanged,
|
||||
),
|
||||
if (_currentSearchQuery.isNotEmpty) ...[
|
||||
const SizedBox(height: AppTheme.spacingSmall),
|
||||
Text(
|
||||
'Recherche: "$_currentSearchQuery"',
|
||||
style: AppTheme.bodySmall.copyWith(
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Section des KPI des membres
|
||||
Widget _buildKPISection(MembresState state) {
|
||||
final membres = state is MembresLoaded ? state.membres : <MembreModel>[];
|
||||
final totalMembres = membres.length;
|
||||
final membresActifs = membres.where((m) => m.statut == StatutMembre.actif).length;
|
||||
final nouveauxMembres = membres.where((m) {
|
||||
final now = DateTime.now();
|
||||
final monthAgo = DateTime(now.year, now.month - 1, now.day);
|
||||
return m.dateInscription.isAfter(monthAgo);
|
||||
}).length;
|
||||
final cotisationsAJour = membres.where((m) => m.cotisationAJour).length;
|
||||
|
||||
final kpis = [
|
||||
UnifiedKPIData(
|
||||
title: 'Total',
|
||||
value: totalMembres.toString(),
|
||||
icon: Icons.people,
|
||||
color: AppTheme.primaryColor,
|
||||
trend: UnifiedKPITrend(
|
||||
direction: nouveauxMembres > 0 ? UnifiedKPITrendDirection.up : UnifiedKPITrendDirection.stable,
|
||||
value: '+$nouveauxMembres',
|
||||
label: 'ce mois',
|
||||
),
|
||||
),
|
||||
UnifiedKPIData(
|
||||
title: 'Actifs',
|
||||
value: membresActifs.toString(),
|
||||
icon: Icons.verified_user,
|
||||
color: AppTheme.successColor,
|
||||
trend: UnifiedKPITrend(
|
||||
direction: UnifiedKPITrendDirection.stable,
|
||||
value: '${((membresActifs / totalMembres) * 100).toInt()}%',
|
||||
label: 'du total',
|
||||
),
|
||||
),
|
||||
UnifiedKPIData(
|
||||
title: 'Nouveaux',
|
||||
value: nouveauxMembres.toString(),
|
||||
icon: Icons.person_add,
|
||||
color: AppTheme.accentColor,
|
||||
trend: UnifiedKPITrend(
|
||||
direction: UnifiedKPITrendDirection.up,
|
||||
value: 'Ce mois',
|
||||
label: 'inscriptions',
|
||||
),
|
||||
),
|
||||
UnifiedKPIData(
|
||||
title: 'À jour',
|
||||
value: '${((cotisationsAJour / totalMembres) * 100).toInt()}%',
|
||||
icon: Icons.account_balance_wallet,
|
||||
color: AppTheme.warningColor,
|
||||
trend: UnifiedKPITrend(
|
||||
direction: UnifiedKPITrendDirection.stable,
|
||||
value: '$cotisationsAJour/$totalMembres',
|
||||
label: 'cotisations',
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
return UnifiedKPISection(
|
||||
title: 'Statistiques des membres',
|
||||
kpis: kpis,
|
||||
);
|
||||
}
|
||||
|
||||
/// Section des actions rapides
|
||||
Widget _buildQuickActionsSection() {
|
||||
final actions = [
|
||||
UnifiedQuickAction(
|
||||
id: 'add_member',
|
||||
title: 'Nouveau\nMembre',
|
||||
icon: Icons.person_add,
|
||||
color: AppTheme.primaryColor,
|
||||
),
|
||||
UnifiedQuickAction(
|
||||
id: 'bulk_import',
|
||||
title: 'Import\nGroupé',
|
||||
icon: Icons.upload_file,
|
||||
color: AppTheme.accentColor,
|
||||
),
|
||||
UnifiedQuickAction(
|
||||
id: 'send_message',
|
||||
title: 'Message\nGroupé',
|
||||
icon: Icons.send,
|
||||
color: AppTheme.infoColor,
|
||||
),
|
||||
UnifiedQuickAction(
|
||||
id: 'export_data',
|
||||
title: 'Exporter\nDonnées',
|
||||
icon: Icons.download,
|
||||
color: AppTheme.successColor,
|
||||
),
|
||||
UnifiedQuickAction(
|
||||
id: 'cotisations_reminder',
|
||||
title: 'Rappel\nCotisations',
|
||||
icon: Icons.notification_important,
|
||||
color: AppTheme.warningColor,
|
||||
badgeCount: 12,
|
||||
),
|
||||
UnifiedQuickAction(
|
||||
id: 'member_reports',
|
||||
title: 'Rapports\nMembres',
|
||||
icon: Icons.analytics,
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
];
|
||||
|
||||
return UnifiedQuickActionsSection(
|
||||
title: 'Actions rapides',
|
||||
actions: actions,
|
||||
onActionTap: _handleQuickAction,
|
||||
);
|
||||
}
|
||||
|
||||
/// Section des filtres
|
||||
Widget _buildFiltersSection() {
|
||||
return UnifiedCard.outlined(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(AppTheme.spacingMedium),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.filter_list,
|
||||
color: AppTheme.primaryColor,
|
||||
size: 20,
|
||||
),
|
||||
const SizedBox(width: AppTheme.spacingSmall),
|
||||
Text(
|
||||
'Filtres rapides',
|
||||
style: AppTheme.titleSmall.copyWith(
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: AppTheme.spacingMedium),
|
||||
Wrap(
|
||||
spacing: AppTheme.spacingSmall,
|
||||
runSpacing: AppTheme.spacingSmall,
|
||||
children: [
|
||||
_buildFilterChip('Tous', _currentFilters.isEmpty),
|
||||
_buildFilterChip('Actifs', _currentFilters['statut'] == 'actif'),
|
||||
_buildFilterChip('Inactifs', _currentFilters['statut'] == 'inactif'),
|
||||
_buildFilterChip('Nouveaux', _currentFilters['type'] == 'nouveaux'),
|
||||
_buildFilterChip('Cotisations en retard', _currentFilters['cotisation'] == 'retard'),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Construit un chip de filtre
|
||||
Widget _buildFilterChip(String label, bool isSelected) {
|
||||
return FilterChip(
|
||||
label: Text(label),
|
||||
selected: isSelected,
|
||||
onSelected: (selected) {
|
||||
Map<String, dynamic> newFilters = {};
|
||||
if (selected) {
|
||||
switch (label) {
|
||||
case 'Actifs':
|
||||
newFilters['statut'] = 'actif';
|
||||
break;
|
||||
case 'Inactifs':
|
||||
newFilters['statut'] = 'inactif';
|
||||
break;
|
||||
case 'Nouveaux':
|
||||
newFilters['type'] = 'nouveaux';
|
||||
break;
|
||||
case 'Cotisations en retard':
|
||||
newFilters['cotisation'] = 'retard';
|
||||
break;
|
||||
}
|
||||
}
|
||||
_onFiltersChanged(newFilters);
|
||||
},
|
||||
selectedColor: AppTheme.primaryColor.withOpacity(0.2),
|
||||
checkmarkColor: AppTheme.primaryColor,
|
||||
);
|
||||
}
|
||||
|
||||
/// Liste des membres avec composant unifié
|
||||
Widget _buildMembersList(MembresState state) {
|
||||
if (state is MembresLoaded) {
|
||||
return UnifiedListWidget<MembreModel>(
|
||||
items: state.membres,
|
||||
itemBuilder: (context, membre, index) => _buildMemberCard(membre),
|
||||
isLoading: false,
|
||||
hasReachedMax: true,
|
||||
enableAnimations: true,
|
||||
emptyMessage: 'Aucun membre trouvé',
|
||||
emptyIcon: Icons.people_outline,
|
||||
);
|
||||
}
|
||||
|
||||
return const Center(
|
||||
child: Text('Chargement des membres...'),
|
||||
);
|
||||
}
|
||||
|
||||
/// Construit une carte de membre
|
||||
Widget _buildMemberCard(MembreModel membre) {
|
||||
return UnifiedCard.listItem(
|
||||
onTap: () {
|
||||
// TODO: Navigation vers détails du membre
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(AppTheme.spacingMedium),
|
||||
child: Row(
|
||||
children: [
|
||||
CircleAvatar(
|
||||
backgroundColor: AppTheme.primaryColor.withOpacity(0.1),
|
||||
child: Text(
|
||||
membre.prenom.isNotEmpty ? membre.prenom[0].toUpperCase() : 'M',
|
||||
style: TextStyle(
|
||||
color: AppTheme.primaryColor,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: AppTheme.spacingMedium),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'${membre.prenom} ${membre.nom}',
|
||||
style: AppTheme.bodyLarge.copyWith(
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppTheme.spacingXSmall),
|
||||
Text(
|
||||
membre.email,
|
||||
style: AppTheme.bodySmall.copyWith(
|
||||
color: AppTheme.textSecondary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: AppTheme.spacingSmall,
|
||||
vertical: AppTheme.spacingXSmall,
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: _getStatusColor(membre.statut).withOpacity(0.1),
|
||||
borderRadius: BorderRadius.circular(AppTheme.borderRadiusSmall),
|
||||
),
|
||||
child: Text(
|
||||
_getStatusLabel(membre.statut),
|
||||
style: AppTheme.bodySmall.copyWith(
|
||||
color: _getStatusColor(membre.statut),
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: AppTheme.spacingXSmall),
|
||||
Icon(
|
||||
membre.cotisationAJour ? Icons.check_circle : Icons.warning,
|
||||
color: membre.cotisationAJour ? AppTheme.successColor : AppTheme.warningColor,
|
||||
size: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// Obtient la couleur du statut
|
||||
Color _getStatusColor(StatutMembre statut) {
|
||||
switch (statut) {
|
||||
case StatutMembre.actif:
|
||||
return AppTheme.successColor;
|
||||
case StatutMembre.inactif:
|
||||
return AppTheme.errorColor;
|
||||
case StatutMembre.suspendu:
|
||||
return AppTheme.warningColor;
|
||||
}
|
||||
}
|
||||
|
||||
/// Obtient le libellé du statut
|
||||
String _getStatusLabel(StatutMembre statut) {
|
||||
switch (statut) {
|
||||
case StatutMembre.actif:
|
||||
return 'Actif';
|
||||
case StatutMembre.inactif:
|
||||
return 'Inactif';
|
||||
case StatutMembre.suspendu:
|
||||
return 'Suspendu';
|
||||
}
|
||||
}
|
||||
|
||||
/// Gère les actions rapides
|
||||
void _handleQuickAction(UnifiedQuickAction action) {
|
||||
switch (action.id) {
|
||||
case 'add_member':
|
||||
// TODO: Navigation vers ajout membre
|
||||
break;
|
||||
case 'bulk_import':
|
||||
// TODO: Import groupé
|
||||
break;
|
||||
case 'send_message':
|
||||
// TODO: Message groupé
|
||||
break;
|
||||
case 'export_data':
|
||||
// TODO: Export des données
|
||||
break;
|
||||
case 'cotisations_reminder':
|
||||
// TODO: Rappel cotisations
|
||||
break;
|
||||
case 'member_reports':
|
||||
// TODO: Rapports membres
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_membresBloc.close();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,6 @@ import '../../../../core/auth/services/permission_service.dart';
|
||||
import '../../../../core/services/communication_service.dart';
|
||||
import '../../../../core/services/export_import_service.dart';
|
||||
import '../../../../shared/theme/app_theme.dart';
|
||||
import '../../../../shared/widgets/coming_soon_page.dart';
|
||||
import '../../../../shared/widgets/permission_widget.dart';
|
||||
import '../bloc/membres_bloc.dart';
|
||||
import '../bloc/membres_event.dart';
|
||||
@@ -22,6 +21,7 @@ import '../widgets/membres_view_controls.dart';
|
||||
import '../widgets/membre_enhanced_card.dart';
|
||||
import 'membre_details_page.dart';
|
||||
import 'membre_create_page.dart';
|
||||
import 'membre_edit_page.dart';
|
||||
import '../widgets/error_demo_widget.dart';
|
||||
|
||||
|
||||
@@ -540,7 +540,7 @@ class _MembresListPageState extends State<MembresListPage> with PermissionMixin
|
||||
}
|
||||
|
||||
/// Affiche le dialog d'édition de membre
|
||||
void _showEditMemberDialog(membre) {
|
||||
void _showEditMemberDialog(membre) async {
|
||||
// Vérifier les permissions avant d'ouvrir le formulaire
|
||||
if (!permissionService.canEditMembers) {
|
||||
showPermissionError(context, 'Vous n\'avez pas les permissions pour modifier les membres');
|
||||
@@ -549,16 +549,16 @@ class _MembresListPageState extends State<MembresListPage> with PermissionMixin
|
||||
|
||||
permissionService.logAction('Ouverture formulaire édition membre', details: {'membreId': membre.id});
|
||||
|
||||
// TODO: Implémenter le formulaire d'édition
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => const ComingSoonPage(
|
||||
title: 'Modifier le membre',
|
||||
description: 'Le formulaire de modification sera bientôt disponible.',
|
||||
icon: Icons.edit,
|
||||
color: AppTheme.warningColor,
|
||||
final result = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => MembreEditPage(membre: membre),
|
||||
),
|
||||
);
|
||||
|
||||
// Si le membre a été modifié avec succès, recharger la liste
|
||||
if (result == true) {
|
||||
_membresBloc.add(const RefreshMembres());
|
||||
}
|
||||
}
|
||||
|
||||
/// Affiche la confirmation de suppression
|
||||
|
||||
Reference in New Issue
Block a user