From 134b9781c8f6520e0585143fef537c90a55945c1 Mon Sep 17 00:00:00 2001 From: Julien Martin Date: Fri, 17 Jul 2026 16:19:12 +0200 Subject: [PATCH] feat(#149): clic sur case libre pour rattacher un enfant (fiche AM). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Les emplacements vides de la grille ouvrent le même flux que le lien footer, avec hover et respect de la capacité max. Co-authored-by: Cursor --- .../admin_am_children_capacity_grid.dart | 57 +++++++++++++++---- .../admin/common/admin_am_edit_modal.dart | 1 + 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/frontend/lib/widgets/admin/common/admin_am_children_capacity_grid.dart b/frontend/lib/widgets/admin/common/admin_am_children_capacity_grid.dart index b77871c..5b28e3c 100644 --- a/frontend/lib/widgets/admin/common/admin_am_children_capacity_grid.dart +++ b/frontend/lib/widgets/admin/common/admin_am_children_capacity_grid.dart @@ -20,6 +20,8 @@ class AdminAmChildrenCapacityGrid extends StatelessWidget { final int capacity; final void Function(ParentChildSummary child) onOpen; final void Function(ParentChildSummary child) onDetach; + /// Clic sur une case libre → même flux que « Rattacher un enfant » (#149). + final VoidCallback? onAttachEmpty; const AdminAmChildrenCapacityGrid({ super.key, @@ -27,6 +29,7 @@ class AdminAmChildrenCapacityGrid extends StatelessWidget { required this.capacity, required this.onOpen, required this.onDetach, + this.onAttachEmpty, }); @override @@ -78,7 +81,7 @@ class AdminAmChildrenCapacityGrid extends StatelessWidget { ); } if (index < maxSlots) { - return const _EmptySlot(); + return _EmptySlot(onTap: onAttachEmpty); } return const _UnavailableSlot(); } @@ -129,18 +132,52 @@ class _UnavailableSlot extends StatelessWidget { } } -class _EmptySlot extends StatelessWidget { - const _EmptySlot(); +class _EmptySlot extends StatefulWidget { + final VoidCallback? onTap; + + const _EmptySlot({this.onTap}); + + @override + State<_EmptySlot> createState() => _EmptySlotState(); +} + +class _EmptySlotState extends State<_EmptySlot> { + bool _hovered = false; @override Widget build(BuildContext context) { - return _SlotShell( - backgroundColor: Colors.grey.shade50, - borderColor: Colors.grey.shade300, - child: Center( - child: Text( - 'Place libre', - style: TextStyle(fontSize: 12, color: Colors.grey.shade500), + final clickable = widget.onTap != null; + return MouseRegion( + onEnter: clickable ? (_) => setState(() => _hovered = true) : null, + onExit: clickable ? (_) => setState(() => _hovered = false) : null, + cursor: clickable ? SystemMouseCursors.click : MouseCursor.defer, + child: Material( + color: Colors.transparent, + borderRadius: BorderRadius.circular(8), + child: InkWell( + onTap: widget.onTap, + borderRadius: BorderRadius.circular(8), + hoverColor: const Color(0x149CC5C0), + child: _SlotShell( + backgroundColor: _hovered + ? const Color(0xFFF3F0FA) + : Colors.grey.shade50, + borderColor: _hovered + ? const Color(0xFFB8A4D4) + : Colors.grey.shade300, + child: Center( + child: Text( + 'Place libre', + style: TextStyle( + fontSize: 12, + color: _hovered + ? const Color(0xFF6B3FA0) + : Colors.grey.shade500, + fontWeight: _hovered ? FontWeight.w600 : FontWeight.w400, + ), + ), + ), + ), ), ), ); diff --git a/frontend/lib/widgets/admin/common/admin_am_edit_modal.dart b/frontend/lib/widgets/admin/common/admin_am_edit_modal.dart index 706250e..6663be2 100644 --- a/frontend/lib/widgets/admin/common/admin_am_edit_modal.dart +++ b/frontend/lib/widgets/admin/common/admin_am_edit_modal.dart @@ -745,6 +745,7 @@ class _AdminAmEditModalState extends State capacity: capacity, onOpen: _openChild, onDetach: _detachChild, + onAttachEmpty: _capacityFull ? null : _attachChild, ), ], );