refactor(#155): phase 2 — panels staff sous widgets/dashboard/.
Déplace les panels/wizards/validation/common partagés hors de widgets/admin/ ; ne conserve que AdminManagementWidget (variante A). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:p_tits_pas/models/assistante_maternelle_model.dart';
|
||||
import 'package:p_tits_pas/models/dossier_list_item.dart';
|
||||
import 'package:p_tits_pas/utils/am_vigilance.dart';
|
||||
import 'package:p_tits_pas/services/auth_service.dart';
|
||||
import 'package:p_tits_pas/services/user_service.dart';
|
||||
import 'package:p_tits_pas/utils/staff_deletion_rights.dart';
|
||||
import 'package:p_tits_pas/widgets/dashboard/am_edit_modal.dart';
|
||||
import 'package:p_tits_pas/widgets/dashboard/user_card.dart';
|
||||
import 'package:p_tits_pas/widgets/dashboard/common/suppression_confirm_dialog.dart';
|
||||
import 'package:p_tits_pas/widgets/dashboard/common/user_list.dart';
|
||||
|
||||
class AssistanteMaternelleManagementWidget extends StatefulWidget {
|
||||
final String searchQuery;
|
||||
final int? capacityMin;
|
||||
|
||||
const AssistanteMaternelleManagementWidget({
|
||||
super.key,
|
||||
required this.searchQuery,
|
||||
this.capacityMin,
|
||||
});
|
||||
|
||||
@override
|
||||
State<AssistanteMaternelleManagementWidget> createState() =>
|
||||
_AssistanteMaternelleManagementWidgetState();
|
||||
}
|
||||
|
||||
class _AssistanteMaternelleManagementWidgetState
|
||||
extends State<AssistanteMaternelleManagementWidget> {
|
||||
bool _isLoading = false;
|
||||
String? _error;
|
||||
List<AssistanteMaternelleModel> _assistantes = [];
|
||||
bool _canDelete = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_loadRights();
|
||||
_loadAssistantes();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() => super.dispose();
|
||||
|
||||
Future<void> _loadRights() async {
|
||||
final user = await AuthService.getCurrentUser();
|
||||
if (!mounted) return;
|
||||
setState(() => _canDelete = canDeleteMetier(user?.role));
|
||||
}
|
||||
|
||||
Future<void> _loadAssistantes() async {
|
||||
setState(() {
|
||||
_isLoading = true;
|
||||
_error = null;
|
||||
});
|
||||
try {
|
||||
final list = await UserService.getAssistantesMaternelles();
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_assistantes = list;
|
||||
_isLoading = false;
|
||||
});
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
setState(() {
|
||||
_error = e.toString();
|
||||
_isLoading = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _confirmDelete(AssistanteMaternelleModel am) async {
|
||||
final num = (am.user.numeroDossier ?? '').trim();
|
||||
final name = formatDossierPersonLabel(
|
||||
nom: am.user.nom,
|
||||
prenom: am.user.prenom,
|
||||
email: am.user.email,
|
||||
);
|
||||
final confirmed = await showSuppressionConfirmDialog(
|
||||
context,
|
||||
title: 'Supprimer l\'assistante maternelle',
|
||||
subtitle: num.isEmpty ? null : 'Dossier $num',
|
||||
people: [SuppressionPersonLine.am(name)],
|
||||
footnotes: const [
|
||||
'Le compte et le dossier AM seront supprimés.',
|
||||
'Les enfants accueillis ne seront pas supprimés '
|
||||
'(placements clos).',
|
||||
],
|
||||
);
|
||||
if (!confirmed || !mounted) return;
|
||||
|
||||
try {
|
||||
final result = await UserService.deleteUser(am.user.id);
|
||||
if (!mounted) return;
|
||||
final msg = (result['message'] ?? 'AM supprimée.').toString();
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg)));
|
||||
await _loadAssistantes();
|
||||
} catch (e) {
|
||||
if (!mounted) return;
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(
|
||||
e is Exception
|
||||
? e.toString().replaceFirst('Exception: ', '')
|
||||
: 'Erreur suppression',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final query = widget.searchQuery.toLowerCase();
|
||||
final filteredAssistantes = _assistantes.where((am) {
|
||||
final matchesName = am.user.fullName.toLowerCase().contains(query) ||
|
||||
am.user.email.toLowerCase().contains(query) ||
|
||||
(am.residenceCity?.toLowerCase().contains(query) ?? false);
|
||||
final matchesCapacity = widget.capacityMin == null ||
|
||||
(am.maxChildren != null && am.maxChildren! >= widget.capacityMin!);
|
||||
return matchesName && matchesCapacity;
|
||||
}).toList();
|
||||
|
||||
return UserList(
|
||||
isLoading: _isLoading,
|
||||
error: _error,
|
||||
isEmpty: filteredAssistantes.isEmpty,
|
||||
emptyMessage: 'Aucune assistante maternelle trouvée.',
|
||||
itemCount: filteredAssistantes.length,
|
||||
itemBuilder: (context, index) {
|
||||
final assistante = filteredAssistantes[index];
|
||||
final vigilance = amPlacesVigilanceMessage(assistante);
|
||||
return UserCard(
|
||||
title: assistante.user.fullName,
|
||||
avatarUrl: assistante.user.photoUrl,
|
||||
fallbackIcon: Icons.face,
|
||||
vigilanceTooltip: vigilance,
|
||||
onCardTap: () => _openAssistanteDetails(assistante),
|
||||
subtitleLines: [
|
||||
assistante.user.email,
|
||||
'Zone : ${assistante.residenceCity ?? 'N/A'} | Capacité : ${assistante.maxChildren ?? 0}',
|
||||
],
|
||||
actions: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.edit),
|
||||
tooltip: 'Modifier',
|
||||
onPressed: () {
|
||||
_openAssistanteDetails(assistante);
|
||||
},
|
||||
),
|
||||
if (_canDelete)
|
||||
suppressionIconButton(
|
||||
onPressed: () => _confirmDelete(assistante),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void _openAssistanteDetails(AssistanteMaternelleModel assistante) {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => AmEditModal(
|
||||
assistante: assistante,
|
||||
onSaved: _loadAssistantes,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user