feat: Filtres membres/secteurs dynamiques et liés (#42)

- Filtrage croisé via box user_sector (UserSectorModel)
- Si secteur sélectionné → membres filtrés (uniquement ce secteur)
- Si membre sélectionné → secteurs filtrés (uniquement ses secteurs)
- Relation : UserSectorModel.opeUserId ↔ UserSectorModel.fkSector
- Import UserSectorModel ajouté
- Simplification dropdown secteurs (liste directe, plus de map)

Comportement :
1. Aucun filtre → tous les membres et tous les secteurs
2. Secteur choisi → liste membres réduite
3. Membre choisi → liste secteurs réduite
4. Les deux choisis → affichage le plus restreint

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-01-26 12:00:28 +01:00
parent 9c837f8adb
commit b3e03ef6e6

View File

@@ -5,6 +5,7 @@ import 'package:geosector_app/core/constants/app_keys.dart';
import 'package:geosector_app/core/services/current_user_service.dart'; import 'package:geosector_app/core/services/current_user_service.dart';
import 'package:geosector_app/core/theme/app_theme.dart'; import 'package:geosector_app/core/theme/app_theme.dart';
import 'package:geosector_app/core/data/models/passage_model.dart'; import 'package:geosector_app/core/data/models/passage_model.dart';
import 'package:geosector_app/core/data/models/user_sector_model.dart';
import 'package:geosector_app/presentation/widgets/passages/passages_list_widget.dart'; import 'package:geosector_app/presentation/widgets/passages/passages_list_widget.dart';
import 'package:geosector_app/presentation/widgets/passage_form_dialog.dart'; import 'package:geosector_app/presentation/widgets/passage_form_dialog.dart';
import 'package:geosector_app/presentation/widgets/app_scaffold.dart'; import 'package:geosector_app/presentation/widgets/app_scaffold.dart';
@@ -621,11 +622,22 @@ class _HistoryContentState extends State<HistoryContent> {
Widget _buildMemberDropdown() { Widget _buildMemberDropdown() {
// Récupérer tous les membres depuis la box Hive // Récupérer tous les membres depuis la box Hive
final membresBox = membreRepository.getMembresBox(); final membresBox = membreRepository.getMembresBox();
final membres = membresBox.values.where((membre) { var membres = membresBox.values.where((membre) {
// Ne garder que les membres ayant un opeUserId (membres actifs dans une opération) // Ne garder que les membres ayant un opeUserId (membres actifs dans une opération)
return membre.opeUserId != null; return membre.opeUserId != null;
}).toList(); }).toList();
// Filtrage dynamique : si un secteur est sélectionné, ne montrer que les membres de ce secteur
if (_selectedSectorId != null) {
final userSectorsBox = Hive.box<UserSectorModel>(AppKeys.userSectorBoxName);
final memberIdsInSector = userSectorsBox.values
.where((us) => us.fkSector == _selectedSectorId)
.map((us) => us.opeUserId)
.toSet();
membres = membres.where((membre) => memberIdsInSector.contains(membre.opeUserId)).toList();
}
// Trier par nom // Trier par nom
membres.sort((a, b) { membres.sort((a, b) {
final nameA = a.name ?? a.firstName ?? ''; final nameA = a.name ?? a.firstName ?? '';
@@ -688,27 +700,22 @@ class _HistoryContentState extends State<HistoryContent> {
/// Construit le dropdown de sélection de secteur (admin uniquement) /// Construit le dropdown de sélection de secteur (admin uniquement)
Widget _buildSectorDropdown() { Widget _buildSectorDropdown() {
// Récupérer les secteurs uniques depuis les passages de l'opération courante // Récupérer tous les secteurs depuis le repository
final sectorIds = <int>{}; var allSectors = sectorRepository.getAllSectors();
for (final passage in _originalPassages) { // Filtrage dynamique : si un membre est sélectionné, ne montrer que ses secteurs
if (passage.fkSector != null && !sectorIds.contains(passage.fkSector)) { if (_selectedMemberId != null) {
sectorIds.add(passage.fkSector!); final userSectorsBox = Hive.box<UserSectorModel>(AppKeys.userSectorBoxName);
} final sectorIdsForMember = userSectorsBox.values
} .where((us) => us.opeUserId == _selectedMemberId)
.map((us) => us.fkSector)
.toSet();
// Récupérer les noms des secteurs depuis le repository allSectors = allSectors.where((sector) => sectorIdsForMember.contains(sector.id)).toList();
final allSectors = sectorRepository.getAllSectors();
final sectorNames = <int, String>{};
for (final sector in allSectors) {
if (sectorIds.contains(sector.id)) {
sectorNames[sector.id] = sector.libelle;
}
} }
// Trier par nom // Trier par nom
final sortedSectors = sectorIds.toList() allSectors.sort((a, b) => a.libelle.compareTo(b.libelle));
..sort((a, b) => (sectorNames[a] ?? '').compareTo(sectorNames[b] ?? ''));
return DropdownButtonFormField<int?>( return DropdownButtonFormField<int?>(
value: _selectedSectorId, value: _selectedSectorId,
@@ -724,11 +731,11 @@ class _HistoryContentState extends State<HistoryContent> {
value: null, value: null,
child: Text('Tous'), child: Text('Tous'),
), ),
...sortedSectors.map((sectorId) { ...allSectors.map((sector) {
return DropdownMenuItem<int?>( return DropdownMenuItem<int?>(
value: sectorId, value: sector.id,
child: Text( child: Text(
sectorNames[sectorId] ?? 'Secteur #$sectorId', sector.libelle,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
); );