feat: livrer ticket #35 et synchroniser les évolutions admin

Intègre en un seul commit les évolutions de develop, avec la création/édition/suppression de gestionnaires via modale unifiée (#35) et les correctifs associés sur la gestion admin.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-24 00:20:33 +01:00
co-authored by Cursor
parent 4d37131301
commit f9477d3fbe
4 changed files with 582 additions and 98 deletions
@@ -1,7 +1,6 @@
import 'package:flutter/material.dart';
import 'package:p_tits_pas/models/relais_model.dart';
import 'package:p_tits_pas/models/user.dart';
import 'package:p_tits_pas/services/relais_service.dart';
import 'package:p_tits_pas/screens/administrateurs/creation/gestionnaires_create.dart';
import 'package:p_tits_pas/services/user_service.dart';
import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart';
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
@@ -24,7 +23,6 @@ class _GestionnaireManagementWidgetState
bool _isLoading = false;
String? _error;
List<AppUser> _gestionnaires = [];
List<RelaisModel> _relais = [];
@override
void initState() {
@@ -42,17 +40,9 @@ class _GestionnaireManagementWidgetState
});
try {
final gestionnaires = await UserService.getGestionnaires();
List<RelaisModel> relais = [];
try {
relais = await RelaisService.getRelais();
} catch (_) {
// L'ecran reste utilisable meme si la route Relais n'est pas disponible.
}
if (!mounted) return;
setState(() {
_gestionnaires = gestionnaires;
_relais = relais;
_isLoading = false;
});
} catch (e) {
@@ -64,81 +54,16 @@ class _GestionnaireManagementWidgetState
}
}
Future<void> _openRelaisAssignmentDialog(AppUser user) async {
String? selectedRelaisId = user.relaisId;
final saved = await showDialog<bool>(
Future<void> _openGestionnaireEditDialog(AppUser user) async {
final changed = await showDialog<bool>(
context: context,
builder: (ctx) {
return StatefulBuilder(
builder: (context, setStateDialog) {
return AlertDialog(
title: Text(
'Rattacher ${user.fullName.isEmpty ? user.email : user.fullName}',
),
content: DropdownButtonFormField<String?>(
value: selectedRelaisId,
isExpanded: true,
decoration: const InputDecoration(
labelText: 'Relais principal',
border: OutlineInputBorder(),
),
items: [
const DropdownMenuItem<String?>(
value: null,
child: Text('Aucun relais'),
),
..._relais.map(
(relais) => DropdownMenuItem<String?>(
value: relais.id,
child: Text(relais.nom),
),
),
],
onChanged: (value) {
setStateDialog(() {
selectedRelaisId = value;
});
},
),
actions: [
TextButton(
onPressed: () => Navigator.of(ctx).pop(false),
child: const Text('Annuler'),
),
FilledButton(
onPressed: () => Navigator.of(ctx).pop(true),
child: const Text('Enregistrer'),
),
],
);
},
);
barrierDismissible: false,
builder: (dialogContext) {
return GestionnaireCreateDialog(initialUser: user);
},
);
if (saved != true) return;
try {
await UserService.updateGestionnaireRelais(
gestionnaireId: user.id,
relaisId: selectedRelaisId,
);
if (!mounted) return;
if (changed == true) {
await _loadGestionnaires();
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Rattachement relais mis a jour.')),
);
} catch (e) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
e.toString().replaceAll('Exception: ', ''),
),
backgroundColor: Colors.red.shade600,
),
);
}
}
@@ -168,16 +93,11 @@ class _GestionnaireManagementWidgetState
'Relais : ${user.relaisNom ?? 'Non rattaché'}',
],
actions: [
IconButton(
icon: const Icon(Icons.location_city_outlined),
tooltip: 'Rattacher un relais',
onPressed: () => _openRelaisAssignmentDialog(user),
),
IconButton(
icon: const Icon(Icons.edit),
tooltip: 'Modifier',
onPressed: () {
// TODO: Modifier gestionnaire.
_openGestionnaireEditDialog(user);
},
),
],
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:p_tits_pas/screens/administrateurs/creation/gestionnaires_create.dart';
import 'package:p_tits_pas/widgets/admin/admin_management_widget.dart';
import 'package:p_tits_pas/widgets/admin/assistante_maternelle_management_widget.dart';
import 'package:p_tits_pas/widgets/admin/dashboard_admin.dart';
@@ -15,6 +16,7 @@ class AdminUserManagementPanel extends StatefulWidget {
class _AdminUserManagementPanelState extends State<AdminUserManagementPanel> {
int _subIndex = 0;
int _gestionnaireRefreshTick = 0;
final TextEditingController _searchController = TextEditingController();
final TextEditingController _amCapacityController = TextEditingController();
String? _parentStatus;
@@ -133,6 +135,7 @@ class _AdminUserManagementPanelState extends State<AdminUserManagementPanel> {
switch (_subIndex) {
case 0:
return GestionnaireManagementWidget(
key: ValueKey('gestionnaires-$_gestionnaireRefreshTick'),
searchQuery: _searchController.text,
);
case 1:
@@ -164,13 +167,40 @@ class _AdminUserManagementPanelState extends State<AdminUserManagementPanel> {
searchController: _searchController,
searchHint: _searchHintForTab(),
filterControl: _subBarFilterControl(),
onAddPressed: () {
// TODO: brancher création selon onglet actif
},
onAddPressed: _handleAddPressed,
addLabel: 'Ajouter',
),
Expanded(child: _buildBody()),
],
);
}
Future<void> _handleAddPressed() async {
if (_subIndex != 0) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text(
'La création est disponible uniquement pour les gestionnaires.',
),
),
);
return;
}
final created = await showDialog<bool>(
context: context,
barrierDismissible: false,
builder: (dialogContext) {
return const GestionnaireCreateDialog();
},
);
if (!mounted) return;
if (created == true) {
setState(() {
_gestionnaireRefreshTick++;
});
}
}
}