feat: Ajout filtres membre/secteur dans historique admin (#42)
- Ajout de 2 dropdowns de filtres dans history_page.dart (admin uniquement) - Filtre par membre (fkUser) : liste dynamique depuis passages - Filtre par secteur (fkSector) : liste dynamique depuis passages - Valeurs par défaut : "Tous" pour chaque filtre - Tri alphabétique des dropdowns - Mise à jour du planning : #42 validée (26/01) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
140
app/lib/presentation/pages/history_page.dart
Normal file → Executable file
140
app/lib/presentation/pages/history_page.dart
Normal file → Executable file
@@ -55,6 +55,8 @@ class _HistoryContentState extends State<HistoryContent> {
|
||||
String _selectedTypeFilter = 'Tous les types';
|
||||
String _searchQuery = '';
|
||||
int? selectedTypeId;
|
||||
int? _selectedMemberId; // null = "Tous" (admin uniquement)
|
||||
int? _selectedSectorId; // null = "Tous" (admin uniquement)
|
||||
|
||||
// Contrôleur de recherche
|
||||
final TextEditingController _searchController = TextEditingController();
|
||||
@@ -221,6 +223,20 @@ class _HistoryContentState extends State<HistoryContent> {
|
||||
}
|
||||
}
|
||||
|
||||
// Filtre par membre (admin uniquement)
|
||||
if (isAdmin && _selectedMemberId != null) {
|
||||
if (passage.fkUser != _selectedMemberId) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Filtre par secteur (admin uniquement)
|
||||
if (isAdmin && _selectedSectorId != null) {
|
||||
if (passage.fkSector != _selectedSectorId) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Filtre par recherche textuelle
|
||||
if (_searchQuery.isNotEmpty) {
|
||||
final query = _searchQuery.toLowerCase();
|
||||
@@ -302,6 +318,7 @@ class _HistoryContentState extends State<HistoryContent> {
|
||||
children: [
|
||||
// Barre de recherche
|
||||
Expanded(
|
||||
flex: 3,
|
||||
child: TextFormField(
|
||||
controller: _searchController,
|
||||
decoration: const InputDecoration(
|
||||
@@ -319,6 +336,21 @@ class _HistoryContentState extends State<HistoryContent> {
|
||||
},
|
||||
),
|
||||
),
|
||||
// Filtres admin uniquement
|
||||
if (isAdmin) ...[
|
||||
const SizedBox(width: 8),
|
||||
// Filtre par membre
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _buildMemberDropdown(),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
// Filtre par secteur
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: _buildSectorDropdown(),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -563,4 +595,112 @@ class _HistoryContentState extends State<HistoryContent> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Construit le dropdown de sélection de membre (admin uniquement)
|
||||
Widget _buildMemberDropdown() {
|
||||
// Récupérer les membres uniques depuis les passages de l'opération courante
|
||||
final memberIds = <int>{};
|
||||
final memberNames = <int, String>{};
|
||||
|
||||
for (final passage in _originalPassages) {
|
||||
if (!memberIds.contains(passage.fkUser)) {
|
||||
memberIds.add(passage.fkUser);
|
||||
// Utiliser le nom du passage (qui contient prenom + nom)
|
||||
memberNames[passage.fkUser] = passage.name.isNotEmpty ? passage.name : 'Membre #${passage.fkUser}';
|
||||
}
|
||||
}
|
||||
|
||||
// Trier par nom
|
||||
final sortedMembers = memberIds.toList()
|
||||
..sort((a, b) => (memberNames[a] ?? '').compareTo(memberNames[b] ?? ''));
|
||||
|
||||
return DropdownButtonFormField<int?>(
|
||||
value: _selectedMemberId,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
isDense: true,
|
||||
labelText: 'Membre',
|
||||
prefixIcon: Icon(Icons.person, size: 20),
|
||||
),
|
||||
items: [
|
||||
const DropdownMenuItem<int?>(
|
||||
value: null,
|
||||
child: Text('Tous'),
|
||||
),
|
||||
...sortedMembers.map((memberId) {
|
||||
return DropdownMenuItem<int?>(
|
||||
value: memberId,
|
||||
child: Text(
|
||||
memberNames[memberId] ?? 'Membre #$memberId',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
onChanged: (int? newValue) {
|
||||
setState(() {
|
||||
_selectedMemberId = newValue;
|
||||
});
|
||||
_applyFilters();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// Construit le dropdown de sélection de secteur (admin uniquement)
|
||||
Widget _buildSectorDropdown() {
|
||||
// Récupérer les secteurs uniques depuis les passages de l'opération courante
|
||||
final sectorIds = <int>{};
|
||||
|
||||
for (final passage in _originalPassages) {
|
||||
if (passage.fkSector != null && !sectorIds.contains(passage.fkSector)) {
|
||||
sectorIds.add(passage.fkSector!);
|
||||
}
|
||||
}
|
||||
|
||||
// Récupérer les noms des secteurs depuis le repository
|
||||
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
|
||||
final sortedSectors = sectorIds.toList()
|
||||
..sort((a, b) => (sectorNames[a] ?? '').compareTo(sectorNames[b] ?? ''));
|
||||
|
||||
return DropdownButtonFormField<int?>(
|
||||
value: _selectedSectorId,
|
||||
decoration: const InputDecoration(
|
||||
border: OutlineInputBorder(),
|
||||
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
|
||||
isDense: true,
|
||||
labelText: 'Secteur',
|
||||
prefixIcon: Icon(Icons.location_on, size: 20),
|
||||
),
|
||||
items: [
|
||||
const DropdownMenuItem<int?>(
|
||||
value: null,
|
||||
child: Text('Tous'),
|
||||
),
|
||||
...sortedSectors.map((sectorId) {
|
||||
return DropdownMenuItem<int?>(
|
||||
value: sectorId,
|
||||
child: Text(
|
||||
sectorNames[sectorId] ?? 'Secteur #$sectorId',
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
onChanged: (int? newValue) {
|
||||
setState(() {
|
||||
_selectedSectorId = newValue;
|
||||
});
|
||||
_applyFilters();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
25
docs/PLANNING-2026-Q1.md
Normal file → Executable file
25
docs/PLANNING-2026-Q1.md
Normal file → Executable file
@@ -31,11 +31,9 @@
|
||||
|-------|------------|--------------------------------------------|--------|
|
||||
| 19/01 | `#13` Jour 1 | ✅ `#204` Design couleurs flashy | à livrer v3.6.3 |
|
||||
| 19/01 | | ✅ `#205` Écrans utilisateurs simplifiés | à livrer v3.6.3 |
|
||||
| 20/01 | `#13` Jour 2 | `#113` Couleur repasses orange | |
|
||||
| 20/01 | | `#72`Épaisseur police lisibilité | |
|
||||
| 21/01 | `#13` Jour 3 | `#71`Visibilité bouton "Envoyer message" | |
|
||||
| 21/01 | | `#59`Listing rues invisible (clavier) | |
|
||||
| 22/01 | `#13` Jour 4 | `#42`Historique adresses cliquables | |
|
||||
| 20/01 | `#13` Jour 2 | ✅ `#113` Couleur repasses orange | ✅ Validé 26/01 |
|
||||
| 20/01 | | ✅ `#72` Épaisseur police lisibilité (theme + BtnPassages) | ✅ Livré 26/01 |
|
||||
| 21/01 | `#13` Jour 3 | ✅ `#42` Filtres membre/secteur history (admin) | ✅ Livré 26/01 |
|
||||
| 23/01 | `#13` Jour 5 | `#74`Simplifier DashboardLayout/AppScaffold | |
|
||||
| 24/01 | | `#28`Gestion reçus Flutter nouveaux champs | |
|
||||
| 25/01 | | `#50`Modifier secteur au clic | |
|
||||
@@ -143,17 +141,28 @@
|
||||
|
||||
---
|
||||
|
||||
## PHASE 7 : DIVERS (sans date)
|
||||
### Tâches diverses - À planifier ultérieurement
|
||||
|
||||
| ID | Tâche | Cat | Statut |
|
||||
|------|----------------------------------------|------|--------|
|
||||
| `#71` | Visibilité bouton "Envoyer message" | UX | |
|
||||
| `#59` | Listing rues invisible (clavier) | UX | |
|
||||
|
||||
---
|
||||
|
||||
## RÉCAPITULATIF
|
||||
|
||||
| Phase | Période | Jours | Tâches | Focus |
|
||||
|-----------|--------------|-------|--------|---------------------|
|
||||
| 1 | 16-18/01 | 3 | 5 | Bugs critiques |
|
||||
| 2 | 19-25/01 | 7 | 10 | Stripe iOS + UX |
|
||||
| 1 | 16-18/01 | 3 | 7 | Bugs critiques |
|
||||
| 2 | 19-25/01 | 7 | 8 | Stripe iOS + UX |
|
||||
| 3 | 26/01-07/02 | 10 | 25 | MAP / Carte |
|
||||
| 4 | 08-14/02 | 6 | 11 | Stripe + Passages |
|
||||
| 5 | 15-22/02 | 7 | 22 | Admin + Membres |
|
||||
| 6 | 23-28/02 | 5 | 15 | Export + Divers |
|
||||
| **TOTAL** | **44 jours** | | **88** | |
|
||||
| 7 | Sans date | - | 2 | Divers |
|
||||
| **TOTAL** | **44 jours** | | **90** | |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user