import 'package:flutter/material.dart'; import '../../../../core/widgets/unified_card.dart'; import '../../../../core/theme/app_colors.dart'; import '../../../../core/theme/app_text_styles.dart'; import '../../domain/entities/notification.dart'; /// Widget de recherche et filtrage des notifications class NotificationSearchWidget extends StatefulWidget { final Function(String) onSearchChanged; final Function({ Set? types, Set? statuts, }) onFiltersChanged; final Set selectedTypes; final Set selectedStatuts; const NotificationSearchWidget({ super.key, required this.onSearchChanged, required this.onFiltersChanged, required this.selectedTypes, required this.selectedStatuts, }); @override State createState() => _NotificationSearchWidgetState(); } class _NotificationSearchWidgetState extends State { final TextEditingController _searchController = TextEditingController(); bool _showFilters = false; @override void dispose() { _searchController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return UnifiedCard( variant: UnifiedCardVariant.outlined, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Barre de recherche Row( children: [ Expanded( child: TextField( controller: _searchController, decoration: InputDecoration( hintText: 'Rechercher dans les notifications...', hintStyle: AppTextStyles.bodyMedium.copyWith( color: AppColors.onSurface.withOpacity(0.6), ), prefixIcon: Icon( Icons.search, color: AppColors.onSurface.withOpacity(0.6), ), suffixIcon: _searchController.text.isNotEmpty ? IconButton( icon: const Icon(Icons.clear), onPressed: () { _searchController.clear(); widget.onSearchChanged(''); }, ) : null, border: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: AppColors.outline.withOpacity(0.3), ), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: AppColors.outline.withOpacity(0.3), ), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(12), borderSide: BorderSide( color: AppColors.primary, width: 2, ), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 12, ), ), onChanged: widget.onSearchChanged, ), ), const SizedBox(width: 12), // Bouton de filtres IconButton( onPressed: () { setState(() { _showFilters = !_showFilters; }); }, icon: Icon( Icons.filter_list, color: _hasActiveFilters() ? AppColors.primary : AppColors.onSurface.withOpacity(0.6), ), style: IconButton.styleFrom( backgroundColor: _hasActiveFilters() ? AppColors.primary.withOpacity(0.1) : AppColors.surface, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), side: BorderSide( color: _hasActiveFilters() ? AppColors.primary : AppColors.outline.withOpacity(0.3), ), ), ), ), ], ), // Panneau de filtres (conditionnel) if (_showFilters) ...[ const SizedBox(height: 16), _buildFiltersPanel(), ], ], ), ), ); } Widget _buildFiltersPanel() { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // En-tête des filtres Row( children: [ Text( 'Filtres', style: AppTextStyles.titleSmall.copyWith( fontWeight: FontWeight.w600, ), ), const Spacer(), if (_hasActiveFilters()) TextButton( onPressed: _clearAllFilters, child: Text( 'Tout effacer', style: AppTextStyles.labelMedium.copyWith( color: AppColors.primary, ), ), ), ], ), const SizedBox(height: 12), // Filtres par type Text( 'Types de notification', style: AppTextStyles.labelLarge.copyWith( fontWeight: FontWeight.w500, ), ), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 8, children: _getPopularTypes() .map((type) => _buildTypeChip(type)) .toList(), ), const SizedBox(height: 16), // Filtres par statut Text( 'Statuts', style: AppTextStyles.labelLarge.copyWith( fontWeight: FontWeight.w500, ), ), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 8, children: _getPopularStatuts() .map((statut) => _buildStatutChip(statut)) .toList(), ), const SizedBox(height: 16), // Boutons d'action Row( children: [ Expanded( child: OutlinedButton( onPressed: () { setState(() { _showFilters = false; }); }, child: const Text('Fermer'), ), ), const SizedBox(width: 12), Expanded( child: ElevatedButton( onPressed: () { setState(() { _showFilters = false; }); // Les filtres sont déjà appliqués en temps réel }, child: const Text('Appliquer'), ), ), ], ), ], ); } Widget _buildTypeChip(TypeNotification type) { final isSelected = widget.selectedTypes.contains(type); return FilterChip( label: Text( type.libelle, style: AppTextStyles.labelMedium.copyWith( color: isSelected ? AppColors.onPrimary : AppColors.onSurface, ), ), selected: isSelected, onSelected: (selected) { final newTypes = Set.from(widget.selectedTypes); if (selected) { newTypes.add(type); } else { newTypes.remove(type); } widget.onFiltersChanged(types: newTypes); }, selectedColor: AppColors.primary, backgroundColor: AppColors.surface, side: BorderSide( color: isSelected ? AppColors.primary : AppColors.outline.withOpacity(0.3), ), avatar: isSelected ? null : Icon( _getTypeIcon(type), size: 16, color: _getTypeColor(type), ), ); } Widget _buildStatutChip(StatutNotification statut) { final isSelected = widget.selectedStatuts.contains(statut); return FilterChip( label: Text( statut.libelle, style: AppTextStyles.labelMedium.copyWith( color: isSelected ? AppColors.onPrimary : AppColors.onSurface, ), ), selected: isSelected, onSelected: (selected) { final newStatuts = Set.from(widget.selectedStatuts); if (selected) { newStatuts.add(statut); } else { newStatuts.remove(statut); } widget.onFiltersChanged(statuts: newStatuts); }, selectedColor: AppColors.primary, backgroundColor: AppColors.surface, side: BorderSide( color: isSelected ? AppColors.primary : AppColors.outline.withOpacity(0.3), ), avatar: isSelected ? null : Container( width: 8, height: 8, decoration: BoxDecoration( color: _getStatutColor(statut), shape: BoxShape.circle, ), ), ); } List _getPopularTypes() { return [ TypeNotification.nouvelEvenement, TypeNotification.cotisationDue, TypeNotification.nouvelleDemandeAide, TypeNotification.nouveauMembre, TypeNotification.annonceGenerale, TypeNotification.messagePrive, ]; } List _getPopularStatuts() { return [ StatutNotification.nonLue, StatutNotification.lue, StatutNotification.marqueeImportante, StatutNotification.archivee, ]; } IconData _getTypeIcon(TypeNotification type) { switch (type.icone) { case 'event': return Icons.event; case 'payment': return Icons.payment; case 'help': return Icons.help; case 'person_add': return Icons.person_add; case 'campaign': return Icons.campaign; case 'mail': return Icons.mail; default: return Icons.notifications; } } Color _getTypeColor(TypeNotification type) { try { return Color(int.parse(type.couleur.replaceFirst('#', '0xFF'))); } catch (e) { return AppColors.primary; } } Color _getStatutColor(StatutNotification statut) { try { return Color(int.parse(statut.couleur.replaceFirst('#', '0xFF'))); } catch (e) { return AppColors.primary; } } bool _hasActiveFilters() { return widget.selectedTypes.isNotEmpty || widget.selectedStatuts.isNotEmpty; } void _clearAllFilters() { widget.onFiltersChanged( types: {}, statuts: {}, ); } }