feat: Version 3.3.5 - Optimisations pages, améliorations ergonomie et affichages dynamiques stats

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
pierre
2025-10-06 15:32:32 +02:00
parent b6584c83fa
commit 2b3d05c981
31 changed files with 1982 additions and 1442 deletions

View File

@@ -140,12 +140,14 @@ class _HistoryContentState extends State<HistoryContent> {
// Sauvegarder aussi dans Hive pour la persistance
_saveMemberFilter(widget.memberId!);
} else if (!isAdmin) {
// Pour un user standard, toujours filtrer sur son propre ID
selectedMemberId = currentUserId;
} else {
// Admin sans memberId spécifique, charger les filtres depuis Hive
// Pour tous les autres cas (admin et user), charger les filtres depuis Hive
_loadPreselectedFilters();
// Pour un user standard, toujours filtrer sur son propre ID
if (!isAdmin) {
selectedMemberId = currentUserId;
}
}
_initializeNewFilters();
@@ -385,7 +387,7 @@ class _HistoryContentState extends State<HistoryContent> {
// Filtre Type de passage
Expanded(
child: DropdownButtonFormField<String>(
initialValue: _selectedTypeFilter,
value: _selectedTypeFilter,
decoration: const InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
@@ -418,7 +420,7 @@ class _HistoryContentState extends State<HistoryContent> {
// Filtre Mode de règlement
Expanded(
child: DropdownButtonFormField<String>(
initialValue: _selectedPaymentFilter,
value: _selectedPaymentFilter,
decoration: const InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
@@ -473,7 +475,7 @@ class _HistoryContentState extends State<HistoryContent> {
final sectors = sectorsBox.values.toList();
return DropdownButtonFormField<int?>(
initialValue: _selectedSectorId,
value: _selectedSectorId,
decoration: const InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
@@ -520,37 +522,30 @@ class _HistoryContentState extends State<HistoryContent> {
const SizedBox(width: 12),
if (isAdmin)
Expanded(
child: ValueListenableBuilder<Box<UserModel>>(
valueListenable: Hive.box<UserModel>(AppKeys.userBoxName).listenable(),
builder: (context, usersBox, child) {
final users = usersBox.values.where((user) => user.role == 1).toList();
return DropdownButtonFormField<int?>(
initialValue: _selectedUserId,
decoration: const InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
isDense: true,
),
items: [
const DropdownMenuItem<int?>(
value: null,
child: Text('Membres'),
),
...users.map((UserModel user) {
return DropdownMenuItem<int?>(
value: user.id,
child: Text('${user.firstName ?? ''} ${user.name ?? ''}'),
);
}),
],
onChanged: (int? newValue) {
setState(() {
_selectedUserId = newValue;
});
_notifyFiltersChanged();
},
);
child: DropdownButtonFormField<int?>(
value: _selectedUserId,
decoration: const InputDecoration(
border: OutlineInputBorder(),
contentPadding: EdgeInsets.symmetric(horizontal: 12, vertical: 8),
isDense: true,
),
items: [
const DropdownMenuItem<int?>(
value: null,
child: Text('Membres'),
),
..._users.map((UserModel user) {
return DropdownMenuItem<int?>(
value: user.id,
child: Text('${user.firstName ?? ''} ${user.name ?? ''}'),
);
}),
],
onChanged: (int? newValue) {
setState(() {
_selectedUserId = newValue;
});
_notifyFiltersChanged();
},
),
)
@@ -896,6 +891,7 @@ class _HistoryContentState extends State<HistoryContent> {
if (memberId != null && memberId is int) {
setState(() {
selectedMemberId = memberId;
_selectedUserId = memberId; // Synchroniser avec le nouveau filtre
});
debugPrint('HistoryPage: Membre présélectionné chargé: $memberId');
}
@@ -906,6 +902,7 @@ class _HistoryContentState extends State<HistoryContent> {
if (sectorId != null && sectorId is int) {
setState(() {
selectedSectorId = sectorId;
_selectedSectorId = sectorId; // Synchroniser avec le nouveau filtre
});
debugPrint('HistoryPage: Secteur présélectionné chargé: $sectorId');
}
@@ -917,6 +914,10 @@ class _HistoryContentState extends State<HistoryContent> {
selectedTypeId = typeId;
final typeInfo = AppKeys.typesPassages[typeId];
selectedType = typeInfo != null ? typeInfo['titre'] as String : 'Inconnu';
// Synchroniser avec le nouveau filtre
if (typeInfo != null) {
_selectedTypeFilter = typeInfo['titre'] as String;
}
});
debugPrint('HistoryPage: Type de passage présélectionné: $typeId');
}
@@ -926,6 +927,12 @@ class _HistoryContentState extends State<HistoryContent> {
if (paymentTypeId != null && paymentTypeId is int) {
setState(() {
selectedPaymentTypeId = paymentTypeId;
_selectedPaymentTypeId = paymentTypeId; // Synchroniser avec le nouveau filtre
// Mettre à jour aussi le label du filtre
final paymentInfo = AppKeys.typesReglements[paymentTypeId];
if (paymentInfo != null) {
_selectedPaymentFilter = paymentInfo['titre'] as String;
}
});
debugPrint('HistoryPage: Type de règlement présélectionné: $paymentTypeId');
}
@@ -1592,8 +1599,11 @@ class _HistoryContentState extends State<HistoryContent> {
orElse: () => PassageModel.fromJson(passageMap),
);
// Vérifier les permissions : admin peut tout éditer, user seulement ses propres passages
if (isAdmin || passage.fkUser == currentUserId) {
// Vérifier les permissions :
// - Admin peut tout éditer
// - User peut éditer ses propres passages
// - Type 2 (À finaliser) : éditable par tous les utilisateurs
if (isAdmin || passage.fkUser == currentUserId || passage.fkType == 2) {
_handlePassageEdit(passage);
} else {
ScaffoldMessenger.of(context).showSnackBar(