feat(#131): en-tête fiche parent avec nom et co-parent.

Affiche le prénom/nom du parent en titre et le co-parent en sous-titre ; note handoff back dans archive/temporaires.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-24 23:37:04 +02:00
co-authored by Cursor
parent d55f240f56
commit ebf794e1ac
4 changed files with 188 additions and 7 deletions
+9
View File
@@ -3,11 +3,13 @@ import 'package:p_tits_pas/models/user.dart';
class ParentModel {
final AppUser user;
final AppUser? coParent;
final int childrenCount;
final List<ParentChildSummary> children;
ParentModel({
required this.user,
this.coParent,
this.childrenCount = 0,
this.children = const [],
});
@@ -20,12 +22,19 @@ class ParentModel {
}
final user = AppUser.fromJson(userJson);
AppUser? coParent;
final coParentRaw = root['co_parent'];
if (coParentRaw is Map) {
coParent = AppUser.fromJson(Map<String, dynamic>.from(coParentRaw));
}
final children = _parseChildren(root);
final links = root['parentChildren'] ?? root['parent_children'];
final linkCount = links is List ? links.length : 0;
return ParentModel(
user: user,
coParent: coParent,
childrenCount: children.isNotEmpty ? children.length : linkCount,
children: children,
);
@@ -3,6 +3,7 @@ import 'package:p_tits_pas/models/enfant_admin_model.dart';
import 'package:p_tits_pas/utils/phone_utils.dart';
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/user.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/admin/common/admin_enfant_user_card.dart';
@@ -36,6 +37,7 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
late String _statut;
late List<ParentChildSummary> _children;
AppUser? _coParent;
late final ScrollController _childrenScrollCtrl;
bool _saving = false;
bool _dirty = false;
@@ -62,6 +64,7 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
_villeCtrl = TextEditingController(text: u.ville ?? '');
_cpCtrl = TextEditingController(text: u.codePostal ?? '');
_statut = u.statut ?? 'en_attente';
_coParent = widget.parent.coParent;
_children = List.of(widget.parent.children);
_childrenScrollCtrl = ScrollController();
for (final c in [
@@ -75,9 +78,15 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
]) {
c.addListener(_markDirty);
}
_nomCtrl.addListener(_onNameFieldChanged);
_prenomCtrl.addListener(_onNameFieldChanged);
_reloadChildren();
}
void _onNameFieldChanged() {
setState(() {});
}
@override
void dispose() {
for (final c in [
@@ -99,6 +108,22 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
if (!_dirty) setState(() => _dirty = true);
}
String _headerTitle() {
final fn = _prenomCtrl.text.trim();
final ln = _nomCtrl.text.trim();
if (fn.isEmpty && ln.isEmpty) {
final fallback = widget.parent.user.fullName.trim();
return fallback.isNotEmpty ? fallback : 'Parent';
}
return '$fn $ln'.trim();
}
String? _coParentSubtitle() {
final name = _coParent?.fullName.trim() ?? '';
if (name.isEmpty) return null;
return 'Co-parent : $name';
}
String _displayStatus(String status) {
switch (status) {
case 'actif':
@@ -202,7 +227,10 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
}).toList();
if (!mounted) return;
setState(() => _children = kids);
setState(() {
_children = kids;
_coParent = refreshed.coParent;
});
} catch (_) {}
}
@@ -445,15 +473,35 @@ class _AdminParentEditModalState extends State<AdminParentEditModal> {
mainAxisSize: MainAxisSize.min,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Padding(
padding: EdgeInsets.fromLTRB(18, 16, 0, 10),
child: Text(
'Fiche parent',
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w700),
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(18, 16, 12, 10),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
_headerTitle(),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w700,
),
),
if (_coParentSubtitle() != null) ...[
const SizedBox(height: 4),
Text(
_coParentSubtitle()!,
style: const TextStyle(
fontSize: 13,
color: Colors.black54,
),
),
],
],
),
),
),
const Spacer(),
SizedBox(width: 160, child: _statusDropdown()),
const SizedBox(width: 4),
IconButton(