Compare commits

...
Author SHA1 Message Date
jmartinandCursor 8b1b9e7917 feat(front): implement AM dashboard shell with 3 columns (#169)
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-24 12:13:20 +02:00
2 changed files with 63 additions and 54 deletions
@@ -1,11 +1,12 @@
import 'package:flutter/material.dart'; 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/widgets/app_footer.dart'; import 'package:p_tits_pas/widgets/quotidien/quotidien_shell.dart';
import 'package:p_tits_pas/widgets/dashboard/dashboard_bandeau.dart'; import 'package:p_tits_pas/widgets/quotidien/quotidien_theme.dart';
/// Dashboard assistante maternelle page blanche avec bandeau générique. /// Dashboard assistante maternelle coquille 3 colonnes quotidien (#169).
/// Contenu détaillé à venir. /// Colonne gauche : sélecteur de couple enfantparent(s) (à venir #170).
/// Métier cartes / blog / messagerie : tickets C/D/E.
class AmDashboardScreen extends StatefulWidget { class AmDashboardScreen extends StatefulWidget {
const AmDashboardScreen({super.key}); const AmDashboardScreen({super.key});
@@ -14,7 +15,7 @@ class AmDashboardScreen extends StatefulWidget {
} }
class _AmDashboardScreenState extends State<AmDashboardScreen> { class _AmDashboardScreenState extends State<AmDashboardScreen> {
int selectedTabIndex = 0; QuotidienNavSection _section = QuotidienNavSection.liaison;
AppUser? _user; AppUser? _user;
@override @override
@@ -28,51 +29,58 @@ class _AmDashboardScreenState extends State<AmDashboardScreen> {
if (mounted) setState(() => _user = user); if (mounted) setState(() => _user = user);
} }
String get _displayName {
final n = _user?.fullName.trim() ?? '';
if (n.isNotEmpty) return n;
final email = _user?.email.trim() ?? '';
if (email.isNotEmpty) return email.split('@').first;
return 'Assistante maternelle';
}
void _soon(String label) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('$label — à venir')),
);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return QuotidienShell(
appBar: PreferredSize( selectedSection: _section,
preferredSize: const Size.fromHeight(60.0), onSectionSelected: (s) => setState(() => _section = s),
child: DashboardBandeau( userDisplayName: _displayName,
tabItems: const [ userEmail: _user?.email,
DashboardTabItem(label: 'Mon tableau de bord'), onProfileTap: () => _soon('Profil'),
DashboardTabItem(label: 'Paramètres'), onSettingsTap: () => _soon('Paramètres'),
], // L'AM n'a pas de bouton "Recherche AM" dans le bandeau
selectedTabIndex: selectedTabIndex, onSearchAmTap: null,
onTabSelected: (index) => setState(() => selectedTabIndex = index), leftColumn: const QuotidienColumnPlaceholder(
userDisplayName: _user?.fullName.isNotEmpty == true title: 'Cartes',
? _user!.fullName subtitle:
: 'Assistante maternelle', 'Couple enfantparent(s) et flux de cartes\n(à brancher — tickets #170 / #174).',
userEmail: _user?.email, icon: Icons.style_outlined,
userRole: _user?.role,
onProfileTap: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('Modification du profil à venir')),
);
},
onSettingsTap: () {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('Paramètres à venir')),
);
},
onLogout: () {},
showLogoutConfirmation: true,
),
), ),
body: Column( centerColumn: const QuotidienColumnPlaceholder(
children: [ title: 'Blog',
Expanded( subtitle:
child: Center( 'Fil du quotidien (affichage par défaut)\n(à brancher — ticket #179).',
child: Text( icon: Icons.auto_stories_outlined,
'Dashboard AM à venir', ),
style: Theme.of(context).textTheme.titleLarge, rightColumn: const QuotidienColumnPlaceholder(
), title: 'Messagerie',
), subtitle:
), 'Mess. Parents · Mess. RPE\n(à brancher — ticket #185).',
const AppFooter(), icon: Icons.chat_bubble_outline,
], ),
agendaBody: const QuotidienStubPage(
title: 'Agenda',
message: 'Agenda — contenu à venir (stub #187).',
),
contratBody: const QuotidienStubPage(
title: 'Contrat',
message: 'Contrat — contenu à venir (stub #187).',
), ),
); );
} }
} }
@@ -183,15 +183,16 @@ class _UserMenu extends StatelessWidget {
title: Text('Profil'), title: Text('Profil'),
), ),
), ),
const PopupMenuItem( if (onSearchAmTap != null)
value: 'search_am', const PopupMenuItem(
child: ListTile( value: 'search_am',
dense: true, child: ListTile(
contentPadding: EdgeInsets.zero, dense: true,
leading: Icon(Icons.search, size: 20), contentPadding: EdgeInsets.zero,
title: Text('Recherche AM'), leading: Icon(Icons.search, size: 20),
title: Text('Recherche AM'),
),
), ),
),
const PopupMenuItem( const PopupMenuItem(
value: 'settings', value: 'settings',
child: ListTile( child: ListTile(