refactor(#155): option C — widgets partagés sans préfixe Admin.
Déplace les composants Admin* du dashboard partagé vers widgets/dashboard/ (ChildDetailModal, AmEditModal, UserCard, Select*, …). Conserve AdminManagementWidget et screens/administrateurs. Rename mécanique, aucun changement de comportement. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,52 @@
|
|||||||
|
# Mini-spec — Rename préfixe `Admin*` dashboard partagé (#155)
|
||||||
|
|
||||||
|
**Ticket** : **#155**
|
||||||
|
**Branche** : `feature/155-rename-admin-prefix-dashboard` (depuis `develop`)
|
||||||
|
**Décision naming** : **option C** — dossier neutre `widgets/dashboard/` + noms **sans** préfixe `Admin`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Principe
|
||||||
|
|
||||||
|
Les widgets partagés **admin + gestionnaire** ne doivent plus s’appeler `Admin*`.
|
||||||
|
On garde `Admin*` seulement là où c’est vraiment le rôle administrateur.
|
||||||
|
|
||||||
|
## Gardé `Admin*` (hors rename)
|
||||||
|
|
||||||
|
| Élément | Raison |
|
||||||
|
|---------|--------|
|
||||||
|
| `AdminManagementWidget` | Onglet **Administrateurs** |
|
||||||
|
| `screens/administrateurs/*` | `AdminDashboardScreen`, `AdminCreateDialog`, `AdminUserFormDialog` |
|
||||||
|
| `EnfantAdminModel` | Modèle API (pas un widget) — hors scope ticket |
|
||||||
|
|
||||||
|
## Renames faits
|
||||||
|
|
||||||
|
| Avant | Après |
|
||||||
|
|-------|--------|
|
||||||
|
| `widgets/admin/common/admin_child_detail_modal.dart` → `AdminChildDetailModal` | `widgets/dashboard/child_detail_modal.dart` → `ChildDetailModal` |
|
||||||
|
| `admin_am_edit_modal` → `AdminAmEditModal` | `am_edit_modal` → `AmEditModal` |
|
||||||
|
| `admin_parent_edit_modal` → `AdminParentEditModal` | `parent_edit_modal` → `ParentEditModal` |
|
||||||
|
| `admin_user_card` → `AdminUserCard` | `user_card` → `UserCard` |
|
||||||
|
| `admin_enfant_user_card` → `AdminEnfantUserCard` | `enfant_user_card` → `EnfantUserCard` |
|
||||||
|
| `admin_am_photo_frame` → `AdminAmPhotoFrame` | `am_photo_frame` → `AmPhotoFrame` |
|
||||||
|
| `admin_am_children_capacity_grid` | `am_children_capacity_grid` → `AmChildrenCapacityGrid` |
|
||||||
|
| `admin_children_affiliation_panel` | `children_affiliation_panel` → `ChildrenAffiliationPanel` |
|
||||||
|
| `admin_select_*` / `AdminSelect*` / `AdminFamilleFoyer` | `select_*` / `Select*` / `FamilleFoyer` |
|
||||||
|
| `admin_status_capsule` | `status_capsule` → `StatusCapsule` |
|
||||||
|
| `admin_list_state` → `AdminListState` | `user_list_state` → `UserListState` |
|
||||||
|
| `admin_detail_modal` → `AdminDetailModal` / `AdminDetailField` | `detail_modal` → `DetailModal` / `DetailField` |
|
||||||
|
| `dashboard_admin.dart` | `user_management_sub_bar.dart` (`DashboardUserManagementSubBar` inchangé) |
|
||||||
|
|
||||||
|
Dossier `widgets/admin/` conserve les panels métier (`user_management_panel`, wizards, etc.) + `AdminManagementWidget`.
|
||||||
|
|
||||||
|
## Hors scope
|
||||||
|
|
||||||
|
- Refonte UX modales (ticket dédié)
|
||||||
|
- Rename API / back
|
||||||
|
- Déplacer tout `widgets/admin/` → `widgets/dashboard/` (panels) — possible follow-up
|
||||||
|
|
||||||
|
## Critères
|
||||||
|
|
||||||
|
- [x] Plus de préfixe `Admin` sur les composants **partagés** listés
|
||||||
|
- [ ] Build Flutter / recette dashboard admin + gestionnaire OK
|
||||||
|
- [x] Pas de changement comportemental (rename mécanique)
|
||||||
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:p_tits_pas/models/user.dart';
|
import 'package:p_tits_pas/models/user.dart';
|
||||||
import 'package:p_tits_pas/services/auth_service.dart';
|
import 'package:p_tits_pas/services/auth_service.dart';
|
||||||
import 'package:p_tits_pas/services/configuration_service.dart';
|
import 'package:p_tits_pas/services/configuration_service.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/dashboard_admin.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_management_sub_bar.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/parametres_panel.dart';
|
import 'package:p_tits_pas/widgets/admin/parametres_panel.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/user_management_panel.dart';
|
import 'package:p_tits_pas/widgets/admin/user_management_panel.dart';
|
||||||
import 'package:p_tits_pas/widgets/app_footer.dart';
|
import 'package:p_tits_pas/widgets/app_footer.dart';
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import 'package:p_tits_pas/screens/administrateurs/creation/gestionnaires_create
|
|||||||
import 'package:p_tits_pas/services/auth_service.dart';
|
import 'package:p_tits_pas/services/auth_service.dart';
|
||||||
import 'package:p_tits_pas/services/user_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/utils/staff_deletion_rights.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_card.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ class _AdminManagementWidgetState extends State<AdminManagementWidget> {
|
|||||||
final isSuperAdmin = _isSuperAdmin(user);
|
final isSuperAdmin = _isSuperAdmin(user);
|
||||||
final canEdit = _canEditAdmin(user);
|
final canEdit = _canEditAdmin(user);
|
||||||
final canDelete = _canDeleteAdmin(user);
|
final canDelete = _canDeleteAdmin(user);
|
||||||
return AdminUserCard(
|
return UserCard(
|
||||||
title: user.fullName,
|
title: user.fullName,
|
||||||
fallbackIcon: isSuperAdmin
|
fallbackIcon: isSuperAdmin
|
||||||
? Icons.verified_user_outlined
|
? Icons.verified_user_outlined
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ import 'package:p_tits_pas/utils/name_format_utils.dart';
|
|||||||
import 'package:p_tits_pas/utils/nir_utils.dart';
|
import 'package:p_tits_pas/utils/nir_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/phone_utils.dart';
|
import 'package:p_tits_pas/utils/phone_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/postal_utils.dart';
|
import 'package:p_tits_pas/utils/postal_utils.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_am_photo_frame.dart';
|
import 'package:p_tits_pas/widgets/dashboard/am_photo_frame.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_detail_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/detail_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
|
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/validation_refus_form.dart';
|
import 'package:p_tits_pas/widgets/admin/validation_refus_form.dart';
|
||||||
@@ -221,32 +221,32 @@ class _AmDossierWizardState extends State<AmDossierWizard> {
|
|||||||
|
|
||||||
void _emitStep() => widget.onStepChanged?.call(_step, _stepCount);
|
void _emitStep() => widget.onStepChanged?.call(_step, _stepCount);
|
||||||
|
|
||||||
List<AdminDetailField> _photoProFields(DossierAM d) {
|
List<DetailField> _photoProFields(DossierAM d) {
|
||||||
final u = d.user;
|
final u = d.user;
|
||||||
return [
|
return [
|
||||||
AdminDetailField(label: 'NIR', value: _formatNirForDisplay(d.nir)),
|
DetailField(label: 'NIR', value: _formatNirForDisplay(d.nir)),
|
||||||
AdminDetailField(
|
DetailField(
|
||||||
label: 'Date de naissance',
|
label: 'Date de naissance',
|
||||||
value: formatIsoDateFr(u.dateNaissance),
|
value: formatIsoDateFr(u.dateNaissance),
|
||||||
),
|
),
|
||||||
AdminDetailField(
|
DetailField(
|
||||||
label: 'Ville de naissance',
|
label: 'Ville de naissance',
|
||||||
value: _v(u.lieuNaissanceVille),
|
value: _v(u.lieuNaissanceVille),
|
||||||
),
|
),
|
||||||
AdminDetailField(
|
DetailField(
|
||||||
label: 'Pays de naissance',
|
label: 'Pays de naissance',
|
||||||
value: _v(u.lieuNaissancePays),
|
value: _v(u.lieuNaissancePays),
|
||||||
),
|
),
|
||||||
AdminDetailField(label: 'N° Agrément', value: _v(d.numeroAgrement)),
|
DetailField(label: 'N° Agrément', value: _v(d.numeroAgrement)),
|
||||||
AdminDetailField(
|
DetailField(
|
||||||
label: 'Date d’agrément',
|
label: 'Date d’agrément',
|
||||||
value: formatIsoDateFr(d.dateAgrement),
|
value: formatIsoDateFr(d.dateAgrement),
|
||||||
),
|
),
|
||||||
AdminDetailField(
|
DetailField(
|
||||||
label: 'Capacité max (enfants)',
|
label: 'Capacité max (enfants)',
|
||||||
value: d.nbMaxEnfants != null ? d.nbMaxEnfants.toString() : '–',
|
value: d.nbMaxEnfants != null ? d.nbMaxEnfants.toString() : '–',
|
||||||
),
|
),
|
||||||
AdminDetailField(
|
DetailField(
|
||||||
label: 'Places disponibles',
|
label: 'Places disponibles',
|
||||||
value: d.placesDisponibles != null
|
value: d.placesDisponibles != null
|
||||||
? d.placesDisponibles.toString()
|
? d.placesDisponibles.toString()
|
||||||
@@ -741,14 +741,14 @@ class _AmDossierWizardState extends State<AmDossierWizard> {
|
|||||||
|
|
||||||
Widget _buildStep1() {
|
Widget _buildStep1() {
|
||||||
// Modale calée sur les TF ; photo étirée sur toute la hauteur utile
|
// Modale calée sur les TF ; photo étirée sur toute la hauteur utile
|
||||||
// (largeur = [AdminAmPhotoFrame.columnWidthForHeight], cadre inclus).
|
// (largeur = [AmPhotoFrame.columnWidthForHeight], cadre inclus).
|
||||||
return LayoutBuilder(
|
return LayoutBuilder(
|
||||||
builder: (context, c) {
|
builder: (context, c) {
|
||||||
final maxRowW = c.maxWidth;
|
final maxRowW = c.maxWidth;
|
||||||
final maxRowH = c.maxHeight.clamp(0.0, double.infinity);
|
final maxRowH = c.maxHeight.clamp(0.0, double.infinity);
|
||||||
final maxPhotoW = (maxRowW - _photoProGap - _proColumnMinWidth)
|
final maxPhotoW = (maxRowW - _photoProGap - _proColumnMinWidth)
|
||||||
.clamp(0.0, double.infinity);
|
.clamp(0.0, double.infinity);
|
||||||
var photoW = AdminAmPhotoFrame.columnWidthForHeight(maxRowH)
|
var photoW = AmPhotoFrame.columnWidthForHeight(maxRowH)
|
||||||
.clamp(_photoColumnMinWidth, 360.0);
|
.clamp(_photoColumnMinWidth, 360.0);
|
||||||
if (photoW > maxPhotoW) photoW = maxPhotoW;
|
if (photoW > maxPhotoW) photoW = maxPhotoW;
|
||||||
|
|
||||||
@@ -762,7 +762,7 @@ class _AmDossierWizardState extends State<AmDossierWizard> {
|
|||||||
|
|
||||||
final Widget photo;
|
final Widget photo;
|
||||||
if (_isCreate) {
|
if (_isCreate) {
|
||||||
photo = AdminAmPhotoFrame(
|
photo = AmPhotoFrame(
|
||||||
imageBytes: _photoBytes,
|
imageBytes: _photoBytes,
|
||||||
onTap: _pickPhoto,
|
onTap: _pickPhoto,
|
||||||
onClear: _photoBytes != null ? _clearPhoto : null,
|
onClear: _photoBytes != null ? _clearPhoto : null,
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import 'package:p_tits_pas/utils/am_vigilance.dart';
|
|||||||
import 'package:p_tits_pas/services/auth_service.dart';
|
import 'package:p_tits_pas/services/auth_service.dart';
|
||||||
import 'package:p_tits_pas/services/user_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/utils/staff_deletion_rights.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_am_edit_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/am_edit_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_card.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
||||||
|
|
||||||
@@ -130,7 +130,7 @@ class _AssistanteMaternelleManagementWidgetState
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final assistante = filteredAssistantes[index];
|
final assistante = filteredAssistantes[index];
|
||||||
final vigilance = amPlacesVigilanceMessage(assistante);
|
final vigilance = amPlacesVigilanceMessage(assistante);
|
||||||
return AdminUserCard(
|
return UserCard(
|
||||||
title: assistante.user.fullName,
|
title: assistante.user.fullName,
|
||||||
avatarUrl: assistante.user.photoUrl,
|
avatarUrl: assistante.user.photoUrl,
|
||||||
fallbackIcon: Icons.face,
|
fallbackIcon: Icons.face,
|
||||||
@@ -161,7 +161,7 @@ class _AssistanteMaternelleManagementWidgetState
|
|||||||
void _openAssistanteDetails(AssistanteMaternelleModel assistante) {
|
void _openAssistanteDetails(AssistanteMaternelleModel assistante) {
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AdminAmEditModal(
|
builder: (context) => AmEditModal(
|
||||||
assistante: assistante,
|
assistante: assistante,
|
||||||
onSaved: _loadAssistantes,
|
onSaved: _loadAssistantes,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_list_state.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_list_state.dart';
|
||||||
|
|
||||||
class UserList extends StatelessWidget {
|
class UserList extends StatelessWidget {
|
||||||
final bool isLoading;
|
final bool isLoading;
|
||||||
@@ -28,7 +28,7 @@ class UserList extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
AdminListState(
|
UserListState(
|
||||||
isLoading: isLoading,
|
isLoading: isLoading,
|
||||||
error: error,
|
error: error,
|
||||||
isEmpty: isEmpty,
|
isEmpty: isEmpty,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'package:p_tits_pas/utils/email_utils.dart';
|
|||||||
import 'package:p_tits_pas/utils/nir_utils.dart';
|
import 'package:p_tits_pas/utils/nir_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/phone_utils.dart';
|
import 'package:p_tits_pas/utils/phone_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/postal_utils.dart';
|
import 'package:p_tits_pas/utils/postal_utils.dart';
|
||||||
import 'admin_detail_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/detail_modal.dart';
|
||||||
|
|
||||||
/// Réglages des formulaires validation / wizard AM — **jouer sur ces 3 leviers**.
|
/// Réglages des formulaires validation / wizard AM — **jouer sur ces 3 leviers**.
|
||||||
class ValidationFormMetrics {
|
class ValidationFormMetrics {
|
||||||
@@ -60,7 +60,7 @@ class ValidationFormMetrics {
|
|||||||
class ValidationDetailSection extends StatelessWidget {
|
class ValidationDetailSection extends StatelessWidget {
|
||||||
/// Si null ou vide, pas de bandeau titre (gain de place vertical, ex. wizard AM).
|
/// Si null ou vide, pas de bandeau titre (gain de place vertical, ex. wizard AM).
|
||||||
final String? title;
|
final String? title;
|
||||||
final List<AdminDetailField> fields;
|
final List<DetailField> fields;
|
||||||
|
|
||||||
/// Nombre de champs par ligne (1 = plein largeur, 2 = deux côte à côte). Ex. [2, 2, 1, 2] pour identité.
|
/// Nombre de champs par ligne (1 = plein largeur, 2 = deux côte à côte). Ex. [2, 2, 1, 2] pour identité.
|
||||||
final List<int>? rowLayout;
|
final List<int>? rowLayout;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_card.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
||||||
|
|
||||||
/// Carte dossier unifiée (#153) — fond neutre, accent couleur sur l’icône.
|
/// Carte dossier unifiée (#153) — fond neutre, accent couleur sur l’icône.
|
||||||
@@ -54,7 +54,7 @@ class DossierListCard extends StatelessWidget {
|
|||||||
if (!emptyKids && countLabel != null) countLabel,
|
if (!emptyKids && countLabel != null) countLabel,
|
||||||
];
|
];
|
||||||
|
|
||||||
return AdminUserCard(
|
return UserCard(
|
||||||
title: num,
|
title: num,
|
||||||
subtitleLines: subtitle,
|
subtitleLines: subtitle,
|
||||||
avatarUrl: !isFamille && avatar.isNotEmpty ? avatar : null,
|
avatarUrl: !isFamille && avatar.isNotEmpty ? avatar : null,
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import 'package:p_tits_pas/models/enfant_admin_model.dart';
|
|||||||
import 'package:p_tits_pas/services/auth_service.dart';
|
import 'package:p_tits_pas/services/auth_service.dart';
|
||||||
import 'package:p_tits_pas/services/user_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/utils/staff_deletion_rights.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_child_detail_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/child_detail_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_enfant_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/enfant_user_card.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
||||||
|
|
||||||
@@ -68,7 +68,7 @@ class _EnfantManagementWidgetState extends State<EnfantManagementWidget> {
|
|||||||
Future<void> _openEnfant(EnfantAdminModel enfant) async {
|
Future<void> _openEnfant(EnfantAdminModel enfant) async {
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AdminChildDetailModal(
|
builder: (ctx) => ChildDetailModal(
|
||||||
enfant: enfant,
|
enfant: enfant,
|
||||||
onSaved: _loadEnfants,
|
onSaved: _loadEnfants,
|
||||||
onDeleted: _loadEnfants,
|
onDeleted: _loadEnfants,
|
||||||
@@ -224,7 +224,7 @@ class _EnfantManagementWidgetState extends State<EnfantManagementWidget> {
|
|||||||
itemCount: filtered.length,
|
itemCount: filtered.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final enfant = filtered[index];
|
final enfant = filtered[index];
|
||||||
return AdminEnfantUserCard.fromEnfant(
|
return EnfantUserCard.fromEnfant(
|
||||||
enfant,
|
enfant,
|
||||||
onCardTap: () => _openEnfant(enfant),
|
onCardTap: () => _openEnfant(enfant),
|
||||||
actions: [
|
actions: [
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import 'package:p_tits_pas/screens/administrateurs/creation/gestionnaires_create
|
|||||||
import 'package:p_tits_pas/services/auth_service.dart';
|
import 'package:p_tits_pas/services/auth_service.dart';
|
||||||
import 'package:p_tits_pas/services/user_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/utils/staff_deletion_rights.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_card.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
||||||
|
|
||||||
@@ -141,7 +141,7 @@ class _GestionnaireManagementWidgetState
|
|||||||
final user = filteredGestionnaires[index];
|
final user = filteredGestionnaires[index];
|
||||||
final isSelf =
|
final isSelf =
|
||||||
_currentUserId != null && _currentUserId == user.id;
|
_currentUserId != null && _currentUserId == user.id;
|
||||||
return AdminUserCard(
|
return UserCard(
|
||||||
title: user.fullName,
|
title: user.fullName,
|
||||||
fallbackIcon: Icons.assignment_ind_outlined,
|
fallbackIcon: Icons.assignment_ind_outlined,
|
||||||
avatarUrl: user.photoUrl,
|
avatarUrl: user.photoUrl,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import 'package:p_tits_pas/utils/enfant_status_utils.dart';
|
|||||||
import 'package:p_tits_pas/utils/name_format_utils.dart';
|
import 'package:p_tits_pas/utils/name_format_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/phone_utils.dart';
|
import 'package:p_tits_pas/utils/phone_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/postal_utils.dart';
|
import 'package:p_tits_pas/utils/postal_utils.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_am_photo_frame.dart';
|
import 'package:p_tits_pas/widgets/dashboard/am_photo_frame.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
|
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/validation_refus_form.dart';
|
import 'package:p_tits_pas/widgets/admin/validation_refus_form.dart';
|
||||||
@@ -860,7 +860,7 @@ class _ParentDossierWizardState extends State<ParentDossierWizard> {
|
|||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: pw,
|
width: pw,
|
||||||
height: ph,
|
height: ph,
|
||||||
child: AdminAmPhotoFrame(
|
child: AmPhotoFrame(
|
||||||
photoUrl: child.photoBytes == null
|
photoUrl: child.photoBytes == null
|
||||||
? child.existingPhotoUrl
|
? child.existingPhotoUrl
|
||||||
: null,
|
: null,
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import 'package:p_tits_pas/models/parent_model.dart';
|
|||||||
import 'package:p_tits_pas/services/auth_service.dart';
|
import 'package:p_tits_pas/services/auth_service.dart';
|
||||||
import 'package:p_tits_pas/services/user_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/utils/staff_deletion_rights.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_parent_edit_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/parent_edit_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_card.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
import 'package:p_tits_pas/widgets/admin/common/user_list.dart';
|
||||||
|
|
||||||
@@ -146,7 +146,7 @@ class _ParentManagementWidgetState extends State<ParentManagementWidget> {
|
|||||||
itemCount: filteredParents.length,
|
itemCount: filteredParents.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final parent = filteredParents[index];
|
final parent = filteredParents[index];
|
||||||
return AdminUserCard(
|
return UserCard(
|
||||||
title: parent.user.fullName,
|
title: parent.user.fullName,
|
||||||
fallbackIcon: Icons.supervisor_account_outlined,
|
fallbackIcon: Icons.supervisor_account_outlined,
|
||||||
avatarUrl: parent.user.photoUrl,
|
avatarUrl: parent.user.photoUrl,
|
||||||
@@ -189,7 +189,7 @@ class _ParentManagementWidgetState extends State<ParentManagementWidget> {
|
|||||||
void _openParentDetails(ParentModel parent) {
|
void _openParentDetails(ParentModel parent) {
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => AdminParentEditModal(
|
builder: (context) => ParentEditModal(
|
||||||
parent: parent,
|
parent: parent,
|
||||||
onSaved: _loadParents,
|
onSaved: _loadParents,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import 'package:p_tits_pas/screens/administrateurs/creation/gestionnaires_create
|
|||||||
import 'package:p_tits_pas/widgets/admin/admin_management_widget.dart';
|
import 'package:p_tits_pas/widgets/admin/admin_management_widget.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/am_dossier_create_modal.dart';
|
import 'package:p_tits_pas/widgets/admin/am_dossier_create_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/assistante_maternelle_management_widget.dart';
|
import 'package:p_tits_pas/widgets/admin/assistante_maternelle_management_widget.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_child_detail_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/child_detail_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/dashboard_admin.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_management_sub_bar.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/dossiers_management_widget.dart';
|
import 'package:p_tits_pas/widgets/admin/dossiers_management_widget.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/enfant_management_widget.dart';
|
import 'package:p_tits_pas/widgets/admin/enfant_management_widget.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/gestionnaire_management_widget.dart';
|
import 'package:p_tits_pas/widgets/admin/gestionnaire_management_widget.dart';
|
||||||
@@ -348,7 +348,7 @@ class _UserManagementPanelState extends State<UserManagementPanel> {
|
|||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (dialogContext) {
|
builder: (dialogContext) {
|
||||||
return AdminChildDetailModal.create(
|
return ChildDetailModal.create(
|
||||||
onSaved: () {
|
onSaved: () {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
setState(() => _enfantRefreshTick++);
|
setState(() => _enfantRefreshTick++);
|
||||||
|
|||||||
+2
-2
@@ -5,7 +5,7 @@ import 'package:p_tits_pas/utils/date_display_utils.dart';
|
|||||||
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
||||||
|
|
||||||
/// Grille 2×2 des places d'accueil AM (max 4, limitée à [capacity]).
|
/// Grille 2×2 des places d'accueil AM (max 4, limitée à [capacity]).
|
||||||
class AdminAmChildrenCapacityGrid extends StatelessWidget {
|
class AmChildrenCapacityGrid extends StatelessWidget {
|
||||||
static const int _gridSlots = 4;
|
static const int _gridSlots = 4;
|
||||||
static const double _slotHeight = 44;
|
static const double _slotHeight = 44;
|
||||||
static const double _gridPadding = 10;
|
static const double _gridPadding = 10;
|
||||||
@@ -23,7 +23,7 @@ class AdminAmChildrenCapacityGrid extends StatelessWidget {
|
|||||||
/// Clic sur une case libre → même flux que « Rattacher un enfant » (#149).
|
/// Clic sur une case libre → même flux que « Rattacher un enfant » (#149).
|
||||||
final VoidCallback? onAttachEmpty;
|
final VoidCallback? onAttachEmpty;
|
||||||
|
|
||||||
const AdminAmChildrenCapacityGrid({
|
const AmChildrenCapacityGrid({
|
||||||
super.key,
|
super.key,
|
||||||
required this.children,
|
required this.children,
|
||||||
required this.capacity,
|
required this.capacity,
|
||||||
+15
-15
@@ -7,31 +7,31 @@ import 'package:p_tits_pas/utils/date_display_utils.dart';
|
|||||||
import 'package:p_tits_pas/utils/nir_utils.dart';
|
import 'package:p_tits_pas/utils/nir_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/phone_utils.dart';
|
import 'package:p_tits_pas/utils/phone_utils.dart';
|
||||||
import 'package:p_tits_pas/services/user_service.dart';
|
import 'package:p_tits_pas/services/user_service.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_am_children_capacity_grid.dart';
|
import 'package:p_tits_pas/widgets/dashboard/am_children_capacity_grid.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_am_photo_frame.dart';
|
import 'package:p_tits_pas/widgets/dashboard/am_photo_frame.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_child_detail_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/child_detail_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_select_enfant_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/select_enfant_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_status_capsule.dart';
|
import 'package:p_tits_pas/widgets/dashboard/status_capsule.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
|
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
|
||||||
import 'package:p_tits_pas/widgets/common/identity_block.dart';
|
import 'package:p_tits_pas/widgets/common/identity_block.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
||||||
|
|
||||||
/// Fiche AM éditable (ticket #131) — identité | fiche pro (photo) | enfants.
|
/// Fiche AM éditable (ticket #131) — identité | fiche pro (photo) | enfants.
|
||||||
class AdminAmEditModal extends StatefulWidget {
|
class AmEditModal extends StatefulWidget {
|
||||||
final AssistanteMaternelleModel assistante;
|
final AssistanteMaternelleModel assistante;
|
||||||
final VoidCallback? onSaved;
|
final VoidCallback? onSaved;
|
||||||
|
|
||||||
const AdminAmEditModal({
|
const AmEditModal({
|
||||||
super.key,
|
super.key,
|
||||||
required this.assistante,
|
required this.assistante,
|
||||||
this.onSaved,
|
this.onSaved,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AdminAmEditModal> createState() => _AdminAmEditModalState();
|
State<AmEditModal> createState() => _AmEditModalState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AdminAmEditModalState extends State<AdminAmEditModal>
|
class _AmEditModalState extends State<AmEditModal>
|
||||||
with SingleTickerProviderStateMixin {
|
with SingleTickerProviderStateMixin {
|
||||||
late final TabController _tabCtrl;
|
late final TabController _tabCtrl;
|
||||||
late final TextEditingController _nomCtrl;
|
late final TextEditingController _nomCtrl;
|
||||||
@@ -404,7 +404,7 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AdminChildDetailModal(
|
builder: (ctx) => ChildDetailModal(
|
||||||
enfant: enfant,
|
enfant: enfant,
|
||||||
onSaved: _refreshChildrenDetails,
|
onSaved: _refreshChildrenDetails,
|
||||||
),
|
),
|
||||||
@@ -450,7 +450,7 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
|
|
||||||
Future<void> _attachChild() async {
|
Future<void> _attachChild() async {
|
||||||
if (_capacityFull || !mounted) return;
|
if (_capacityFull || !mounted) return;
|
||||||
final selected = await AdminSelectEnfantModal.show(
|
final selected = await SelectEnfantModal.show(
|
||||||
context,
|
context,
|
||||||
excludeIds: _children.map((c) => c.id).toSet(),
|
excludeIds: _children.map((c) => c.id).toSet(),
|
||||||
title: 'Rattacher un enfant',
|
title: 'Rattacher un enfant',
|
||||||
@@ -589,7 +589,7 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
final maxRowH =
|
final maxRowH =
|
||||||
c.maxHeight.isFinite ? c.maxHeight : _proTabHeight;
|
c.maxHeight.isFinite ? c.maxHeight : _proTabHeight;
|
||||||
final bodyH = maxRowH;
|
final bodyH = maxRowH;
|
||||||
final idealPhotoW = bodyH * AdminAmPhotoFrame.idPhotoAspectRatio + 16;
|
final idealPhotoW = bodyH * AmPhotoFrame.idPhotoAspectRatio + 16;
|
||||||
final maxPhotoW = (maxRowW - _photoProGap - _proColumnMinWidth)
|
final maxPhotoW = (maxRowW - _photoProGap - _proColumnMinWidth)
|
||||||
.clamp(0.0, double.infinity);
|
.clamp(0.0, double.infinity);
|
||||||
var photoW = idealPhotoW.clamp(_photoColumnMinWidth, 220.0);
|
var photoW = idealPhotoW.clamp(_photoColumnMinWidth, 220.0);
|
||||||
@@ -600,7 +600,7 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
children: [
|
children: [
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: photoW,
|
width: photoW,
|
||||||
child: AdminAmPhotoFrame(
|
child: AmPhotoFrame(
|
||||||
photoUrl: widget.assistante.user.photoUrl,
|
photoUrl: widget.assistante.user.photoUrl,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -728,7 +728,7 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
AdminAmChildrenCapacityGrid(
|
AmChildrenCapacityGrid(
|
||||||
children: _children,
|
children: _children,
|
||||||
capacity: capacity,
|
capacity: capacity,
|
||||||
onOpen: _openChild,
|
onOpen: _openChild,
|
||||||
@@ -820,7 +820,7 @@ class _AdminAmEditModalState extends State<AdminAmEditModal>
|
|||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 160,
|
width: 160,
|
||||||
child: AdminStatusCapsule(
|
child: StatusCapsule(
|
||||||
statut: _statut,
|
statut: _statut,
|
||||||
onChanged: (v) => setState(() {
|
onChanged: (v) => setState(() {
|
||||||
_statut = v;
|
_statut = v;
|
||||||
+2
-2
@@ -5,7 +5,7 @@ import 'package:p_tits_pas/services/api/api_config.dart';
|
|||||||
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
||||||
|
|
||||||
/// Cadre photo identité AM / enfant (35×45 mm) — même logique que [ValidationAmWizard].
|
/// Cadre photo identité AM / enfant (35×45 mm) — même logique que [ValidationAmWizard].
|
||||||
class AdminAmPhotoFrame extends StatelessWidget {
|
class AmPhotoFrame extends StatelessWidget {
|
||||||
final String? photoUrl;
|
final String? photoUrl;
|
||||||
final Uint8List? imageBytes;
|
final Uint8List? imageBytes;
|
||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
@@ -14,7 +14,7 @@ class AdminAmPhotoFrame extends StatelessWidget {
|
|||||||
|
|
||||||
static const double idPhotoAspectRatio = 35 / 45;
|
static const double idPhotoAspectRatio = 35 / 45;
|
||||||
|
|
||||||
const AdminAmPhotoFrame({
|
const AmPhotoFrame({
|
||||||
super.key,
|
super.key,
|
||||||
this.photoUrl,
|
this.photoUrl,
|
||||||
this.imageBytes,
|
this.imageBytes,
|
||||||
+17
-17
@@ -11,24 +11,24 @@ import 'package:p_tits_pas/utils/date_display_utils.dart';
|
|||||||
import 'package:p_tits_pas/utils/enfant_status_utils.dart';
|
import 'package:p_tits_pas/utils/enfant_status_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/name_format_utils.dart';
|
import 'package:p_tits_pas/utils/name_format_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/staff_deletion_rights.dart';
|
import 'package:p_tits_pas/utils/staff_deletion_rights.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_am_edit_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/am_edit_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_am_photo_frame.dart';
|
import 'package:p_tits_pas/widgets/dashboard/am_photo_frame.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_parent_edit_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/parent_edit_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_select_am_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/select_am_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_select_famille_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/select_famille_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
import 'package:p_tits_pas/widgets/admin/common/suppression_confirm_dialog.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
|
import 'package:p_tits_pas/widgets/admin/common/validation_detail_section.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
||||||
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
||||||
|
|
||||||
/// Fiche enfant consultation / édition (#138) ou création (#132).
|
/// Fiche enfant consultation / édition (#138) ou création (#132).
|
||||||
class AdminChildDetailModal extends StatefulWidget {
|
class ChildDetailModal extends StatefulWidget {
|
||||||
final EnfantAdminModel? enfant;
|
final EnfantAdminModel? enfant;
|
||||||
final VoidCallback? onSaved;
|
final VoidCallback? onSaved;
|
||||||
final VoidCallback? onDeleted;
|
final VoidCallback? onDeleted;
|
||||||
final bool isCreating;
|
final bool isCreating;
|
||||||
|
|
||||||
const AdminChildDetailModal({
|
const ChildDetailModal({
|
||||||
super.key,
|
super.key,
|
||||||
required EnfantAdminModel this.enfant,
|
required EnfantAdminModel this.enfant,
|
||||||
this.onSaved,
|
this.onSaved,
|
||||||
@@ -36,7 +36,7 @@ class AdminChildDetailModal extends StatefulWidget {
|
|||||||
}) : isCreating = false;
|
}) : isCreating = false;
|
||||||
|
|
||||||
/// Création depuis l'onglet Enfants (#132).
|
/// Création depuis l'onglet Enfants (#132).
|
||||||
const AdminChildDetailModal.create({
|
const ChildDetailModal.create({
|
||||||
super.key,
|
super.key,
|
||||||
this.onSaved,
|
this.onSaved,
|
||||||
}) : enfant = null,
|
}) : enfant = null,
|
||||||
@@ -44,10 +44,10 @@ class AdminChildDetailModal extends StatefulWidget {
|
|||||||
isCreating = true;
|
isCreating = true;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AdminChildDetailModal> createState() => _AdminChildDetailModalState();
|
State<ChildDetailModal> createState() => _ChildDetailModalState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
class _ChildDetailModalState extends State<ChildDetailModal> {
|
||||||
late final TextEditingController _prenomCtrl;
|
late final TextEditingController _prenomCtrl;
|
||||||
late final TextEditingController _nomCtrl;
|
late final TextEditingController _nomCtrl;
|
||||||
late final TextEditingController _birthCtrl;
|
late final TextEditingController _birthCtrl;
|
||||||
@@ -65,7 +65,7 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
|||||||
String? _baselineAmUserId;
|
String? _baselineAmUserId;
|
||||||
|
|
||||||
/// Famille choisie en mode création (#132).
|
/// Famille choisie en mode création (#132).
|
||||||
AdminFamilleFoyer? _selectedFamily;
|
FamilleFoyer? _selectedFamily;
|
||||||
|
|
||||||
/// Liens parents locaux (édition) — mis à jour après rattachement foyer (#157).
|
/// Liens parents locaux (édition) — mis à jour après rattachement foyer (#157).
|
||||||
List<EnfantParentLink>? _localParentLinks;
|
List<EnfantParentLink>? _localParentLinks;
|
||||||
@@ -283,7 +283,7 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
|||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AdminParentEditModal(
|
builder: (ctx) => ParentEditModal(
|
||||||
parent: parent,
|
parent: parent,
|
||||||
onSaved: () => widget.onSaved?.call(),
|
onSaved: () => widget.onSaved?.call(),
|
||||||
),
|
),
|
||||||
@@ -624,7 +624,7 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
|||||||
if (am == null) return;
|
if (am == null) return;
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AdminAmEditModal(
|
builder: (ctx) => AmEditModal(
|
||||||
assistante: am,
|
assistante: am,
|
||||||
onSaved: () async {
|
onSaved: () async {
|
||||||
await _reloadPlacementFromServer();
|
await _reloadPlacementFromServer();
|
||||||
@@ -676,7 +676,7 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final selected = await AdminSelectAmModal.show(
|
final selected = await SelectAmModal.show(
|
||||||
context,
|
context,
|
||||||
excludeIds: {
|
excludeIds: {
|
||||||
if (_linkedAm != null) _linkedAm!.user.id,
|
if (_linkedAm != null) _linkedAm!.user.id,
|
||||||
@@ -986,7 +986,7 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
|||||||
final maxRowW = c.maxWidth;
|
final maxRowW = c.maxWidth;
|
||||||
final maxRowH = c.maxHeight;
|
final maxRowH = c.maxHeight;
|
||||||
final idealPhotoW =
|
final idealPhotoW =
|
||||||
maxRowH * AdminAmPhotoFrame.idPhotoAspectRatio + 16;
|
maxRowH * AmPhotoFrame.idPhotoAspectRatio + 16;
|
||||||
final maxPhotoW = (maxRowW - _photoProGap - _proColumnMinWidth)
|
final maxPhotoW = (maxRowW - _photoProGap - _proColumnMinWidth)
|
||||||
.clamp(0.0, double.infinity);
|
.clamp(0.0, double.infinity);
|
||||||
var photoW = idealPhotoW.clamp(_photoColumnMinWidth, _photoColumnMaxWidth);
|
var photoW = idealPhotoW.clamp(_photoColumnMinWidth, _photoColumnMaxWidth);
|
||||||
@@ -1001,7 +1001,7 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: AdminAmPhotoFrame(
|
child: AmPhotoFrame(
|
||||||
photoUrl: widget.isCreating
|
photoUrl: widget.isCreating
|
||||||
? null
|
? null
|
||||||
: widget.enfant?.photoUrl,
|
: widget.enfant?.photoUrl,
|
||||||
@@ -1329,7 +1329,7 @@ class _AdminChildDetailModalState extends State<AdminChildDetailModal> {
|
|||||||
|
|
||||||
Future<void> _pickFamily() async {
|
Future<void> _pickFamily() async {
|
||||||
if (_busy) return;
|
if (_busy) return;
|
||||||
final selected = await AdminSelectFamilleModal.show(
|
final selected = await SelectFamilleModal.show(
|
||||||
context,
|
context,
|
||||||
title: 'Choisir une famille',
|
title: 'Choisir une famille',
|
||||||
);
|
);
|
||||||
+4
-4
@@ -1,9 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:p_tits_pas/models/parent_child_summary.dart';
|
import 'package:p_tits_pas/models/parent_child_summary.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_enfant_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/enfant_user_card.dart';
|
||||||
|
|
||||||
/// Liste scrollable d'enfants rattachés (fiche parent / fiche AM).
|
/// Liste scrollable d'enfants rattachés (fiche parent / fiche AM).
|
||||||
class AdminChildrenAffiliationPanel extends StatelessWidget {
|
class ChildrenAffiliationPanel extends StatelessWidget {
|
||||||
final List<ParentChildSummary> children;
|
final List<ParentChildSummary> children;
|
||||||
final ScrollController scrollController;
|
final ScrollController scrollController;
|
||||||
final void Function(ParentChildSummary child) onOpen;
|
final void Function(ParentChildSummary child) onOpen;
|
||||||
@@ -14,7 +14,7 @@ class AdminChildrenAffiliationPanel extends StatelessWidget {
|
|||||||
static const double _itemHeight = 58;
|
static const double _itemHeight = 58;
|
||||||
static const double defaultViewportHeight = _itemHeight * 2.5 + 8;
|
static const double defaultViewportHeight = _itemHeight * 2.5 + 8;
|
||||||
|
|
||||||
const AdminChildrenAffiliationPanel({
|
const ChildrenAffiliationPanel({
|
||||||
super.key,
|
super.key,
|
||||||
required this.children,
|
required this.children,
|
||||||
required this.scrollController,
|
required this.scrollController,
|
||||||
@@ -62,7 +62,7 @@ class AdminChildrenAffiliationPanel extends StatelessWidget {
|
|||||||
itemCount: children.length,
|
itemCount: children.length,
|
||||||
itemBuilder: (_, i) {
|
itemBuilder: (_, i) {
|
||||||
final c = children[i];
|
final c = children[i];
|
||||||
return AdminEnfantUserCard.fromSummary(
|
return EnfantUserCard.fromSummary(
|
||||||
c,
|
c,
|
||||||
onCardTap: () => onOpen(c),
|
onCardTap: () => onOpen(c),
|
||||||
actions: [
|
actions: [
|
||||||
+5
-5
@@ -1,23 +1,23 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AdminDetailField {
|
class DetailField {
|
||||||
final String label;
|
final String label;
|
||||||
final String value;
|
final String value;
|
||||||
|
|
||||||
const AdminDetailField({
|
const DetailField({
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.value,
|
required this.value,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
class AdminDetailModal extends StatelessWidget {
|
class DetailModal extends StatelessWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final String? subtitle;
|
final String? subtitle;
|
||||||
final List<AdminDetailField> fields;
|
final List<DetailField> fields;
|
||||||
final VoidCallback onEdit;
|
final VoidCallback onEdit;
|
||||||
final VoidCallback onDelete;
|
final VoidCallback onDelete;
|
||||||
|
|
||||||
const AdminDetailModal({
|
const DetailModal({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.subtitle,
|
this.subtitle,
|
||||||
+8
-8
@@ -4,7 +4,7 @@ import 'package:p_tits_pas/models/parent_child_summary.dart';
|
|||||||
import 'package:p_tits_pas/utils/date_display_utils.dart';
|
import 'package:p_tits_pas/utils/date_display_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/enfant_status_utils.dart';
|
import 'package:p_tits_pas/utils/enfant_status_utils.dart';
|
||||||
import 'package:p_tits_pas/utils/enfant_vigilance.dart';
|
import 'package:p_tits_pas/utils/enfant_vigilance.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_card.dart';
|
||||||
|
|
||||||
List<String> enfantAdminSubtitleLines({
|
List<String> enfantAdminSubtitleLines({
|
||||||
required String status,
|
required String status,
|
||||||
@@ -29,7 +29,7 @@ List<String> enfantAdminSubtitleLines({
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Carte enfant admin (photo, nom, âge) — même rendu onglet Enfants / fiche parent.
|
/// Carte enfant admin (photo, nom, âge) — même rendu onglet Enfants / fiche parent.
|
||||||
class AdminEnfantUserCard extends StatelessWidget {
|
class EnfantUserCard extends StatelessWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final String? photoUrl;
|
final String? photoUrl;
|
||||||
final List<String> subtitleLines;
|
final List<String> subtitleLines;
|
||||||
@@ -40,7 +40,7 @@ class AdminEnfantUserCard extends StatelessWidget {
|
|||||||
final Color? borderColor;
|
final Color? borderColor;
|
||||||
final String? vigilanceTooltip;
|
final String? vigilanceTooltip;
|
||||||
|
|
||||||
const AdminEnfantUserCard({
|
const EnfantUserCard({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
this.photoUrl,
|
this.photoUrl,
|
||||||
@@ -53,7 +53,7 @@ class AdminEnfantUserCard extends StatelessWidget {
|
|||||||
this.vigilanceTooltip,
|
this.vigilanceTooltip,
|
||||||
});
|
});
|
||||||
|
|
||||||
factory AdminEnfantUserCard.fromEnfant(
|
factory EnfantUserCard.fromEnfant(
|
||||||
EnfantAdminModel enfant, {
|
EnfantAdminModel enfant, {
|
||||||
List<String> extraSubtitleLines = const [],
|
List<String> extraSubtitleLines = const [],
|
||||||
List<Widget> actions = const [],
|
List<Widget> actions = const [],
|
||||||
@@ -67,7 +67,7 @@ class AdminEnfantUserCard extends StatelessWidget {
|
|||||||
.map((l) => l.parentName ?? 'Parent')
|
.map((l) => l.parentName ?? 'Parent')
|
||||||
.join(', ');
|
.join(', ');
|
||||||
final orphan = enfantHasNoResponsable(enfant);
|
final orphan = enfantHasNoResponsable(enfant);
|
||||||
return AdminEnfantUserCard(
|
return EnfantUserCard(
|
||||||
title: enfant.fullName,
|
title: enfant.fullName,
|
||||||
photoUrl: enfant.photoUrl,
|
photoUrl: enfant.photoUrl,
|
||||||
subtitleLines: enfantAdminSubtitleLines(
|
subtitleLines: enfantAdminSubtitleLines(
|
||||||
@@ -92,7 +92,7 @@ class AdminEnfantUserCard extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
factory AdminEnfantUserCard.fromSummary(
|
factory EnfantUserCard.fromSummary(
|
||||||
ParentChildSummary child, {
|
ParentChildSummary child, {
|
||||||
List<String> extraSubtitleLines = const [],
|
List<String> extraSubtitleLines = const [],
|
||||||
List<Widget> actions = const [],
|
List<Widget> actions = const [],
|
||||||
@@ -100,7 +100,7 @@ class AdminEnfantUserCard extends StatelessWidget {
|
|||||||
EdgeInsetsGeometry? margin,
|
EdgeInsetsGeometry? margin,
|
||||||
EdgeInsetsGeometry? contentPadding,
|
EdgeInsetsGeometry? contentPadding,
|
||||||
}) {
|
}) {
|
||||||
return AdminEnfantUserCard(
|
return EnfantUserCard(
|
||||||
title: child.fullName,
|
title: child.fullName,
|
||||||
photoUrl: child.photoUrl,
|
photoUrl: child.photoUrl,
|
||||||
subtitleLines: enfantAdminSubtitleLines(
|
subtitleLines: enfantAdminSubtitleLines(
|
||||||
@@ -118,7 +118,7 @@ class AdminEnfantUserCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AdminUserCard(
|
return UserCard(
|
||||||
title: title,
|
title: title,
|
||||||
fallbackIcon: Icons.child_care_outlined,
|
fallbackIcon: Icons.child_care_outlined,
|
||||||
avatarUrl: photoUrl,
|
avatarUrl: photoUrl,
|
||||||
+13
-13
@@ -4,30 +4,30 @@ import 'package:p_tits_pas/models/parent_child_summary.dart';
|
|||||||
import 'package:p_tits_pas/models/parent_model.dart';
|
import 'package:p_tits_pas/models/parent_model.dart';
|
||||||
import 'package:p_tits_pas/models/user.dart';
|
import 'package:p_tits_pas/models/user.dart';
|
||||||
import 'package:p_tits_pas/services/user_service.dart';
|
import 'package:p_tits_pas/services/user_service.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_child_detail_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/child_detail_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_children_affiliation_panel.dart';
|
import 'package:p_tits_pas/widgets/dashboard/children_affiliation_panel.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_select_enfant_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/select_enfant_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_status_capsule.dart';
|
import 'package:p_tits_pas/widgets/dashboard/status_capsule.dart';
|
||||||
import 'package:p_tits_pas/widgets/common/identity_block.dart';
|
import 'package:p_tits_pas/widgets/common/identity_block.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
||||||
|
|
||||||
/// Fiche parent éditable (doc 28 §6.1, tickets #131 / #138).
|
/// Fiche parent éditable (doc 28 §6.1, tickets #131 / #138).
|
||||||
/// Shell et typo alignés sur [ValidationDossierModal] / wizards validation.
|
/// Shell et typo alignés sur [ValidationDossierModal] / wizards validation.
|
||||||
class AdminParentEditModal extends StatefulWidget {
|
class ParentEditModal extends StatefulWidget {
|
||||||
final ParentModel parent;
|
final ParentModel parent;
|
||||||
final VoidCallback? onSaved;
|
final VoidCallback? onSaved;
|
||||||
|
|
||||||
const AdminParentEditModal({
|
const ParentEditModal({
|
||||||
super.key,
|
super.key,
|
||||||
required this.parent,
|
required this.parent,
|
||||||
this.onSaved,
|
this.onSaved,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AdminParentEditModal> createState() => _AdminParentEditModalState();
|
State<ParentEditModal> createState() => _ParentEditModalState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AdminParentEditModalState extends State<AdminParentEditModal> {
|
class _ParentEditModalState extends State<ParentEditModal> {
|
||||||
late final TextEditingController _nomCtrl;
|
late final TextEditingController _nomCtrl;
|
||||||
late final TextEditingController _prenomCtrl;
|
late final TextEditingController _prenomCtrl;
|
||||||
late final TextEditingController _emailCtrl;
|
late final TextEditingController _emailCtrl;
|
||||||
@@ -129,7 +129,7 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
|
|||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AdminParentEditModal(
|
builder: (ctx) => ParentEditModal(
|
||||||
parent: parent,
|
parent: parent,
|
||||||
onSaved: () async {
|
onSaved: () async {
|
||||||
try {
|
try {
|
||||||
@@ -244,7 +244,7 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
|
|||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AdminChildDetailModal(
|
builder: (ctx) => ChildDetailModal(
|
||||||
enfant: enfant,
|
enfant: enfant,
|
||||||
onSaved: _reloadChildren,
|
onSaved: _reloadChildren,
|
||||||
),
|
),
|
||||||
@@ -322,7 +322,7 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
|
|||||||
|
|
||||||
Future<void> _attachChild() async {
|
Future<void> _attachChild() async {
|
||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
final selected = await AdminSelectEnfantModal.show(
|
final selected = await SelectEnfantModal.show(
|
||||||
context,
|
context,
|
||||||
excludeIds: _children.map((c) => c.id).toSet(),
|
excludeIds: _children.map((c) => c.id).toSet(),
|
||||||
title: 'Rattacher un enfant',
|
title: 'Rattacher un enfant',
|
||||||
@@ -350,7 +350,7 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _childrenPanel() {
|
Widget _childrenPanel() {
|
||||||
return AdminChildrenAffiliationPanel(
|
return ChildrenAffiliationPanel(
|
||||||
children: _children,
|
children: _children,
|
||||||
scrollController: _childrenScrollCtrl,
|
scrollController: _childrenScrollCtrl,
|
||||||
onOpen: _openChild,
|
onOpen: _openChild,
|
||||||
@@ -437,7 +437,7 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
|
|||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 160,
|
width: 160,
|
||||||
child: AdminStatusCapsule(
|
child: StatusCapsule(
|
||||||
statut: _statut,
|
statut: _statut,
|
||||||
onChanged: (v) => setState(() {
|
onChanged: (v) => setState(() {
|
||||||
_statut = v;
|
_statut = v;
|
||||||
+10
-10
@@ -3,9 +3,9 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:p_tits_pas/models/assistante_maternelle_model.dart';
|
import 'package:p_tits_pas/models/assistante_maternelle_model.dart';
|
||||||
import 'package:p_tits_pas/services/user_service.dart';
|
import 'package:p_tits_pas/services/user_service.dart';
|
||||||
import 'package:p_tits_pas/utils/am_vigilance.dart';
|
import 'package:p_tits_pas/utils/am_vigilance.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_am_edit_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/am_edit_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_select_list_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/select_list_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_card.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
||||||
|
|
||||||
List<String> _amSelectSubtitleLines(AssistanteMaternelleModel am) {
|
List<String> _amSelectSubtitleLines(AssistanteMaternelleModel am) {
|
||||||
@@ -28,22 +28,22 @@ List<String> _amSelectSubtitleLines(AssistanteMaternelleModel am) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sélection d'une AM à rattacher (fiche enfant) — ticket #147.
|
/// Sélection d'une AM à rattacher (fiche enfant) — ticket #147.
|
||||||
/// S'appuie sur [AdminSelectListModal] (shell partagé avec #146).
|
/// S'appuie sur [SelectListModal] (shell partagé avec #146).
|
||||||
class AdminSelectAmModal {
|
class SelectAmModal {
|
||||||
AdminSelectAmModal._();
|
SelectAmModal._();
|
||||||
|
|
||||||
static Future<AssistanteMaternelleModel?> show(
|
static Future<AssistanteMaternelleModel?> show(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
Set<String> excludeIds = const {},
|
Set<String> excludeIds = const {},
|
||||||
String title = 'Choisir une assistante maternelle',
|
String title = 'Choisir une assistante maternelle',
|
||||||
}) {
|
}) {
|
||||||
return AdminSelectListModal.show<AssistanteMaternelleModel>(
|
return SelectListModal.show<AssistanteMaternelleModel>(
|
||||||
context,
|
context,
|
||||||
title: title,
|
title: title,
|
||||||
searchHint: 'Rechercher par nom, prénom ou zone…',
|
searchHint: 'Rechercher par nom, prénom ou zone…',
|
||||||
emptyMessage: 'Aucune assistante maternelle disponible',
|
emptyMessage: 'Aucune assistante maternelle disponible',
|
||||||
noResultsMessage: 'Aucune AM avec place libre pour cette recherche',
|
noResultsMessage: 'Aucune AM avec place libre pour cette recherche',
|
||||||
toggleFilter: const AdminSelectToggleFilter<AssistanteMaternelleModel>(
|
toggleFilter: const SelectToggleFilter<AssistanteMaternelleModel>(
|
||||||
label: 'Libre',
|
label: 'Libre',
|
||||||
initialValue: true,
|
initialValue: true,
|
||||||
whenEnabled: amHasFreePlace,
|
whenEnabled: amHasFreePlace,
|
||||||
@@ -76,7 +76,7 @@ class AdminSelectAmModal {
|
|||||||
_resolveAmSelection(ctx, am, reload),
|
_resolveAmSelection(ctx, am, reload),
|
||||||
itemBuilder: (context, am, onSelect) {
|
itemBuilder: (context, am, onSelect) {
|
||||||
final full = !amHasFreePlace(am);
|
final full = !amHasFreePlace(am);
|
||||||
return AdminUserCard(
|
return UserCard(
|
||||||
title: am.user.fullName,
|
title: am.user.fullName,
|
||||||
avatarUrl: am.user.photoUrl,
|
avatarUrl: am.user.photoUrl,
|
||||||
fallbackIcon: Icons.face,
|
fallbackIcon: Icons.face,
|
||||||
@@ -150,7 +150,7 @@ class _AmNoPlaceWarningDialogState extends State<_AmNoPlaceWarningDialog> {
|
|||||||
if (!mounted) return;
|
if (!mounted) return;
|
||||||
await showDialog<void>(
|
await showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AdminAmEditModal(
|
builder: (ctx) => AmEditModal(
|
||||||
assistante: _am,
|
assistante: _am,
|
||||||
onSaved: () async {
|
onSaved: () async {
|
||||||
try {
|
try {
|
||||||
+8
-8
@@ -2,13 +2,13 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:p_tits_pas/models/enfant_admin_model.dart';
|
import 'package:p_tits_pas/models/enfant_admin_model.dart';
|
||||||
import 'package:p_tits_pas/services/user_service.dart';
|
import 'package:p_tits_pas/services/user_service.dart';
|
||||||
import 'package:p_tits_pas/utils/enfant_status_utils.dart';
|
import 'package:p_tits_pas/utils/enfant_status_utils.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_enfant_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/enfant_user_card.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_select_list_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/select_list_modal.dart';
|
||||||
|
|
||||||
/// Sélection d'un enfant à rattacher (fiche AM / fiche parent) — ticket #146.
|
/// Sélection d'un enfant à rattacher (fiche AM / fiche parent) — ticket #146.
|
||||||
/// S'appuie sur [AdminSelectListModal] (shell partagé avec #147).
|
/// S'appuie sur [SelectListModal] (shell partagé avec #147).
|
||||||
class AdminSelectEnfantModal {
|
class SelectEnfantModal {
|
||||||
AdminSelectEnfantModal._();
|
SelectEnfantModal._();
|
||||||
|
|
||||||
static Future<EnfantAdminModel?> show(
|
static Future<EnfantAdminModel?> show(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
@@ -17,7 +17,7 @@ class AdminSelectEnfantModal {
|
|||||||
/// Affiché uniquement depuis la fiche AM : filtre les enfants déjà en garde.
|
/// Affiché uniquement depuis la fiche AM : filtre les enfants déjà en garde.
|
||||||
bool showSansGardeFilter = false,
|
bool showSansGardeFilter = false,
|
||||||
}) {
|
}) {
|
||||||
return AdminSelectListModal.show<EnfantAdminModel>(
|
return SelectListModal.show<EnfantAdminModel>(
|
||||||
context,
|
context,
|
||||||
title: title,
|
title: title,
|
||||||
searchHint: 'Rechercher par nom ou prénom…',
|
searchHint: 'Rechercher par nom ou prénom…',
|
||||||
@@ -26,7 +26,7 @@ class AdminSelectEnfantModal {
|
|||||||
? 'Aucun enfant sans garde pour cette recherche'
|
? 'Aucun enfant sans garde pour cette recherche'
|
||||||
: 'Aucun résultat pour cette recherche',
|
: 'Aucun résultat pour cette recherche',
|
||||||
toggleFilter: showSansGardeFilter
|
toggleFilter: showSansGardeFilter
|
||||||
? AdminSelectToggleFilter<EnfantAdminModel>(
|
? SelectToggleFilter<EnfantAdminModel>(
|
||||||
label: 'Sans garde',
|
label: 'Sans garde',
|
||||||
initialValue: true,
|
initialValue: true,
|
||||||
whenEnabled: (e) =>
|
whenEnabled: (e) =>
|
||||||
@@ -50,7 +50,7 @@ class AdminSelectEnfantModal {
|
|||||||
return name.contains(q) || fn.contains(q) || ln.contains(q);
|
return name.contains(q) || fn.contains(q) || ln.contains(q);
|
||||||
},
|
},
|
||||||
itemBuilder: (context, e, onSelect) {
|
itemBuilder: (context, e, onSelect) {
|
||||||
return AdminEnfantUserCard.fromEnfant(
|
return EnfantUserCard.fromEnfant(
|
||||||
e,
|
e,
|
||||||
onCardTap: onSelect,
|
onCardTap: onSelect,
|
||||||
margin: const EdgeInsets.only(bottom: 4),
|
margin: const EdgeInsets.only(bottom: 4),
|
||||||
+12
-12
@@ -1,11 +1,11 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:p_tits_pas/models/parent_model.dart';
|
import 'package:p_tits_pas/models/parent_model.dart';
|
||||||
import 'package:p_tits_pas/services/user_service.dart';
|
import 'package:p_tits_pas/services/user_service.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_select_list_modal.dart';
|
import 'package:p_tits_pas/widgets/dashboard/select_list_modal.dart';
|
||||||
import 'package:p_tits_pas/widgets/admin/common/admin_user_card.dart';
|
import 'package:p_tits_pas/widgets/dashboard/user_card.dart';
|
||||||
|
|
||||||
/// Foyer / famille sélectionnable pour rattacher un nouvel enfant (#132 / #157).
|
/// Foyer / famille sélectionnable pour rattacher un nouvel enfant (#132 / #157).
|
||||||
class AdminFamilleFoyer {
|
class FamilleFoyer {
|
||||||
/// Parent pivot pour `POST /enfants` (`parent_user_id`).
|
/// Parent pivot pour `POST /enfants` (`parent_user_id`).
|
||||||
final String pivotParentUserId;
|
final String pivotParentUserId;
|
||||||
/// Co-parent éventuel (rattachement foyer #157).
|
/// Co-parent éventuel (rattachement foyer #157).
|
||||||
@@ -14,7 +14,7 @@ class AdminFamilleFoyer {
|
|||||||
final String displayTitle;
|
final String displayTitle;
|
||||||
final List<String> parentNames;
|
final List<String> parentNames;
|
||||||
|
|
||||||
const AdminFamilleFoyer({
|
const FamilleFoyer({
|
||||||
required this.pivotParentUserId,
|
required this.pivotParentUserId,
|
||||||
required this.displayTitle,
|
required this.displayTitle,
|
||||||
required this.parentNames,
|
required this.parentNames,
|
||||||
@@ -42,10 +42,10 @@ class AdminFamilleFoyer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Construit la liste des foyers uniques à partir de `GET /parents`.
|
/// Construit la liste des foyers uniques à partir de `GET /parents`.
|
||||||
List<AdminFamilleFoyer> buildFamilleFoyers(List<ParentModel> parents) {
|
List<FamilleFoyer> buildFamilleFoyers(List<ParentModel> parents) {
|
||||||
final seenDossiers = <String>{};
|
final seenDossiers = <String>{};
|
||||||
final seenUserIds = <String>{};
|
final seenUserIds = <String>{};
|
||||||
final foyers = <AdminFamilleFoyer>[];
|
final foyers = <FamilleFoyer>[];
|
||||||
|
|
||||||
for (final p in parents) {
|
for (final p in parents) {
|
||||||
final dossier = (p.user.numeroDossier ?? '').trim();
|
final dossier = (p.user.numeroDossier ?? '').trim();
|
||||||
@@ -70,7 +70,7 @@ List<AdminFamilleFoyer> buildFamilleFoyers(List<ParentModel> parents) {
|
|||||||
: (names.isNotEmpty ? names.first : 'Famille');
|
: (names.isNotEmpty ? names.first : 'Famille');
|
||||||
|
|
||||||
foyers.add(
|
foyers.add(
|
||||||
AdminFamilleFoyer(
|
FamilleFoyer(
|
||||||
pivotParentUserId: p.user.id,
|
pivotParentUserId: p.user.id,
|
||||||
coParentUserId: co?.id,
|
coParentUserId: co?.id,
|
||||||
numeroDossier: dossier.isNotEmpty ? dossier : null,
|
numeroDossier: dossier.isNotEmpty ? dossier : null,
|
||||||
@@ -87,14 +87,14 @@ List<AdminFamilleFoyer> buildFamilleFoyers(List<ParentModel> parents) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sélection d'une famille / dossier pour créer un enfant — ticket #132.
|
/// Sélection d'une famille / dossier pour créer un enfant — ticket #132.
|
||||||
class AdminSelectFamilleModal {
|
class SelectFamilleModal {
|
||||||
AdminSelectFamilleModal._();
|
SelectFamilleModal._();
|
||||||
|
|
||||||
static Future<AdminFamilleFoyer?> show(
|
static Future<FamilleFoyer?> show(
|
||||||
BuildContext context, {
|
BuildContext context, {
|
||||||
String title = 'Choisir une famille',
|
String title = 'Choisir une famille',
|
||||||
}) {
|
}) {
|
||||||
return AdminSelectListModal.show<AdminFamilleFoyer>(
|
return SelectListModal.show<FamilleFoyer>(
|
||||||
context,
|
context,
|
||||||
title: title,
|
title: title,
|
||||||
searchHint: 'Rechercher par dossier, nom…',
|
searchHint: 'Rechercher par dossier, nom…',
|
||||||
@@ -111,7 +111,7 @@ class AdminSelectFamilleModal {
|
|||||||
return dossier.contains(q) || title.contains(q) || names.contains(q);
|
return dossier.contains(q) || title.contains(q) || names.contains(q);
|
||||||
},
|
},
|
||||||
itemBuilder: (context, f, onSelect) {
|
itemBuilder: (context, f, onSelect) {
|
||||||
return AdminUserCard(
|
return UserCard(
|
||||||
title: f.displayTitle,
|
title: f.displayTitle,
|
||||||
fallbackIcon: Icons.family_restroom,
|
fallbackIcon: Icons.family_restroom,
|
||||||
subtitleLines: [
|
subtitleLines: [
|
||||||
+10
-10
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
import 'package:p_tits_pas/widgets/admin/validation_modal_theme.dart';
|
||||||
|
|
||||||
/// Filtre optionnel (switch) sur la même ligne que la barre de recherche.
|
/// Filtre optionnel (switch) sur la même ligne que la barre de recherche.
|
||||||
class AdminSelectToggleFilter<T> {
|
class SelectToggleFilter<T> {
|
||||||
final String label;
|
final String label;
|
||||||
final bool initialValue;
|
final bool initialValue;
|
||||||
|
|
||||||
@@ -10,7 +10,7 @@ class AdminSelectToggleFilter<T> {
|
|||||||
/// [whenEnabled] renvoie `true`.
|
/// [whenEnabled] renvoie `true`.
|
||||||
final bool Function(T item) whenEnabled;
|
final bool Function(T item) whenEnabled;
|
||||||
|
|
||||||
const AdminSelectToggleFilter({
|
const SelectToggleFilter({
|
||||||
required this.label,
|
required this.label,
|
||||||
required this.whenEnabled,
|
required this.whenEnabled,
|
||||||
this.initialValue = true,
|
this.initialValue = true,
|
||||||
@@ -19,7 +19,7 @@ class AdminSelectToggleFilter<T> {
|
|||||||
|
|
||||||
/// Shell générique « rechercher + liste + sélection » pour les modales admin.
|
/// Shell générique « rechercher + liste + sélection » pour les modales admin.
|
||||||
/// Utilisé par la sélection d'enfant (#146) et la sélection d'AM (#147).
|
/// Utilisé par la sélection d'enfant (#146) et la sélection d'AM (#147).
|
||||||
class AdminSelectListModal<T> extends StatefulWidget {
|
class SelectListModal<T> extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final String searchHint;
|
final String searchHint;
|
||||||
final Future<List<T>> Function() loadItems;
|
final Future<List<T>> Function() loadItems;
|
||||||
@@ -40,7 +40,7 @@ class AdminSelectListModal<T> extends StatefulWidget {
|
|||||||
final int minVisibleCards;
|
final int minVisibleCards;
|
||||||
|
|
||||||
/// Switch optionnel à droite du champ de recherche (ex. « Sans garde », « Libre »).
|
/// Switch optionnel à droite du champ de recherche (ex. « Sans garde », « Libre »).
|
||||||
final AdminSelectToggleFilter<T>? toggleFilter;
|
final SelectToggleFilter<T>? toggleFilter;
|
||||||
|
|
||||||
/// Si fourni, appelé avant de valider la sélection.
|
/// Si fourni, appelé avant de valider la sélection.
|
||||||
/// Retourne l'élément à pop (éventuellement rafraîchi), ou `null` pour annuler.
|
/// Retourne l'élément à pop (éventuellement rafraîchi), ou `null` pour annuler.
|
||||||
@@ -50,7 +50,7 @@ class AdminSelectListModal<T> extends StatefulWidget {
|
|||||||
Future<void> Function() reload,
|
Future<void> Function() reload,
|
||||||
)? resolveSelect;
|
)? resolveSelect;
|
||||||
|
|
||||||
const AdminSelectListModal({
|
const SelectListModal({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.loadItems,
|
required this.loadItems,
|
||||||
@@ -82,7 +82,7 @@ class AdminSelectListModal<T> extends StatefulWidget {
|
|||||||
double modalWidth = 930,
|
double modalWidth = 930,
|
||||||
double cardExtent = 52,
|
double cardExtent = 52,
|
||||||
int minVisibleCards = 8,
|
int minVisibleCards = 8,
|
||||||
AdminSelectToggleFilter<T>? toggleFilter,
|
SelectToggleFilter<T>? toggleFilter,
|
||||||
Future<T?> Function(
|
Future<T?> Function(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
T item,
|
T item,
|
||||||
@@ -91,7 +91,7 @@ class AdminSelectListModal<T> extends StatefulWidget {
|
|||||||
}) {
|
}) {
|
||||||
return showDialog<T>(
|
return showDialog<T>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (ctx) => AdminSelectListModal<T>(
|
builder: (ctx) => SelectListModal<T>(
|
||||||
title: title,
|
title: title,
|
||||||
loadItems: loadItems,
|
loadItems: loadItems,
|
||||||
matchesQuery: matchesQuery,
|
matchesQuery: matchesQuery,
|
||||||
@@ -109,11 +109,11 @@ class AdminSelectListModal<T> extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AdminSelectListModal<T>> createState() =>
|
State<SelectListModal<T>> createState() =>
|
||||||
_AdminSelectListModalState<T>();
|
_SelectListModalState<T>();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AdminSelectListModalState<T> extends State<AdminSelectListModal<T>> {
|
class _SelectListModalState<T> extends State<SelectListModal<T>> {
|
||||||
final _searchCtrl = TextEditingController();
|
final _searchCtrl = TextEditingController();
|
||||||
List<T> _all = [];
|
List<T> _all = [];
|
||||||
bool _loading = true;
|
bool _loading = true;
|
||||||
+2
-2
@@ -1,13 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
/// Gélule de sélection du statut utilisateur (fiches admin parent / AM).
|
/// Gélule de sélection du statut utilisateur (fiches admin parent / AM).
|
||||||
class AdminStatusCapsule extends StatelessWidget {
|
class StatusCapsule extends StatelessWidget {
|
||||||
final String statut;
|
final String statut;
|
||||||
final ValueChanged<String>? onChanged;
|
final ValueChanged<String>? onChanged;
|
||||||
|
|
||||||
static const statuts = ['actif', 'en_attente', 'suspendu', 'refuse'];
|
static const statuts = ['actif', 'en_attente', 'suspendu', 'refuse'];
|
||||||
|
|
||||||
const AdminStatusCapsule({
|
const StatusCapsule({
|
||||||
super.key,
|
super.key,
|
||||||
required this.statut,
|
required this.statut,
|
||||||
this.onChanged,
|
this.onChanged,
|
||||||
+4
-4
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:p_tits_pas/services/api/api_config.dart';
|
import 'package:p_tits_pas/services/api/api_config.dart';
|
||||||
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
import 'package:p_tits_pas/widgets/common/auth_network_image.dart';
|
||||||
|
|
||||||
class AdminUserCard extends StatefulWidget {
|
class UserCard extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
final List<String> subtitleLines;
|
final List<String> subtitleLines;
|
||||||
final String? avatarUrl;
|
final String? avatarUrl;
|
||||||
@@ -21,7 +21,7 @@ class AdminUserCard extends StatefulWidget {
|
|||||||
final EdgeInsetsGeometry? margin;
|
final EdgeInsetsGeometry? margin;
|
||||||
final EdgeInsetsGeometry? contentPadding;
|
final EdgeInsetsGeometry? contentPadding;
|
||||||
|
|
||||||
const AdminUserCard({
|
const UserCard({
|
||||||
super.key,
|
super.key,
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.subtitleLines,
|
required this.subtitleLines,
|
||||||
@@ -41,10 +41,10 @@ class AdminUserCard extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<AdminUserCard> createState() => _AdminUserCardState();
|
State<UserCard> createState() => _UserCardState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AdminUserCardState extends State<AdminUserCard> {
|
class _UserCardState extends State<UserCard> {
|
||||||
bool _isHovered = false;
|
bool _isHovered = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
+2
-2
@@ -1,13 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
class AdminListState extends StatelessWidget {
|
class UserListState extends StatelessWidget {
|
||||||
final bool isLoading;
|
final bool isLoading;
|
||||||
final String? error;
|
final String? error;
|
||||||
final bool isEmpty;
|
final bool isEmpty;
|
||||||
final String emptyMessage;
|
final String emptyMessage;
|
||||||
final Widget list;
|
final Widget list;
|
||||||
|
|
||||||
const AdminListState({
|
const UserListState({
|
||||||
super.key,
|
super.key,
|
||||||
required this.isLoading,
|
required this.isLoading,
|
||||||
required this.error,
|
required this.error,
|
||||||
Reference in New Issue
Block a user