diff --git a/eme-frontend/lib/screens/checklist_depart_screen.dart b/eme-frontend/lib/screens/checklist_depart_screen.dart index 0b5074e..fb33d62 100644 --- a/eme-frontend/lib/screens/checklist_depart_screen.dart +++ b/eme-frontend/lib/screens/checklist_depart_screen.dart @@ -4,6 +4,7 @@ import "../theme/ensup_colors.dart"; import "../models/materiel_item.dart"; import "../widgets/ensup_top_bar.dart"; import "../widgets/brand_corners.dart"; +import "confirmation_screen.dart"; enum _Etat { present, absent, deteriore } @@ -25,8 +26,20 @@ class _ChecklistDepartScreenState extends State { ); void _valider() { - ScaffoldMessenger.of(context).showSnackBar( - const SnackBar(content: Text("Confirmation de l'emprunt — écran à venir")), + final anomalies = []; + for (var i = 0; i < _etats.length; i++) { + if (_etats[i] == _Etat.absent) { + anomalies.add("${widget.item.accessoires[i]} absent au départ"); + } else if (_etats[i] == _Etat.deteriore) { + anomalies.add("${widget.item.accessoires[i]} détérioré au départ"); + } + } + final note = anomalies.isEmpty ? null : anomalies.join(", "); + + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => ConfirmationScreen(item: widget.item, note: note), + ), ); } diff --git a/eme-frontend/lib/screens/confirmation_screen.dart b/eme-frontend/lib/screens/confirmation_screen.dart new file mode 100644 index 0000000..14468d4 --- /dev/null +++ b/eme-frontend/lib/screens/confirmation_screen.dart @@ -0,0 +1,217 @@ +import "package:flutter/material.dart"; +import "package:google_fonts/google_fonts.dart"; +import "../theme/ensup_colors.dart"; +import "../models/materiel_item.dart"; +import "../widgets/ensup_top_bar.dart"; +import "../widgets/brand_corners.dart"; + +/// Écran de succès clôturant l'emprunt : confirmation + récapitulatif. +class ConfirmationScreen extends StatelessWidget { + const ConfirmationScreen({super.key, required this.item, this.note}); + + final MaterielItem item; + final String? note; + + static String _deuxChiffres(int valeur) => valeur.toString().padLeft(2, "0"); + + @override + Widget build(BuildContext context) { + final now = DateTime.now(); + final date = "${_deuxChiffres(now.day)}/${_deuxChiffres(now.month)}/${now.year}"; + final heure = "${_deuxChiffres(now.hour)}:${_deuxChiffres(now.minute)}"; + + return Scaffold( + backgroundColor: EnsupColors.soft, + body: Stack( + children: [ + Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 1280, maxHeight: 820), + child: Container( + margin: const EdgeInsets.all(24), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: EnsupColors.text.withValues(alpha: 0.14), + blurRadius: 60, + offset: const Offset(0, 18), + ), + ], + ), + clipBehavior: Clip.antiAlias, + child: Column( + children: [ + const EnsupTopBar( + brandText: "EME · Confirmation", + campusTag: "Paris · Ensitech", + ), + Expanded( + child: DecoratedBox( + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topLeft, + end: Alignment.bottomRight, + colors: [Color(0xFFF0FDF4), Color(0xFFF8FAFC)], + ), + ), + child: Center( + child: SingleChildScrollView( + padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 32), + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 560), + child: Column( + children: [ + _boiteSucces(), + const SizedBox(height: 16), + _recapitulatif(date, heure), + const SizedBox(height: 16), + SizedBox( + width: double.infinity, + child: FilledButton.icon( + onPressed: () => Navigator.of(context).popUntil( + (route) => route.settings.name == "home", + ), + icon: const Icon(Icons.home_outlined, size: 18), + label: Text( + "Retour à l'accueil", + style: GoogleFonts.darkerGrotesque( + fontWeight: FontWeight.w700, + fontSize: 16, + ), + ), + style: FilledButton.styleFrom( + backgroundColor: EnsupColors.cyan, + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + ), + ), + ], + ), + ), + ), + ), + ), + ), + ], + ), + ), + ), + ), + const Positioned.fill(child: BrandCorners()), + ], + ), + ); + } + + Widget _boiteSucces() { + return Container( + width: double.infinity, + padding: const EdgeInsets.all(36), + decoration: BoxDecoration( + gradient: const LinearGradient(colors: [Color(0xFFF0FDF4), Color(0xFFECFDF5)]), + borderRadius: BorderRadius.circular(16), + border: Border.all(color: const Color(0xFFBBF7D0), width: 2), + ), + child: Column( + children: [ + Container( + width: 72, + height: 72, + decoration: BoxDecoration( + shape: BoxShape.circle, + gradient: const LinearGradient(colors: [Color(0xFF16A34A), Color(0xFF22C55E)]), + boxShadow: [ + BoxShadow( + color: const Color(0xFF16A34A).withValues(alpha: 0.3), + blurRadius: 20, + offset: const Offset(0, 6), + ), + ], + ), + child: const Icon(Icons.check, color: Colors.white, size: 36), + ), + const SizedBox(height: 18), + Text( + "Emprunt enregistré !", + style: GoogleFonts.darkerGrotesque( + fontSize: 28, + fontWeight: FontWeight.w900, + color: const Color(0xFF15803D), + ), + ), + const SizedBox(height: 8), + Text( + "Votre emprunt a bien été enregistré. Vous pouvez récupérer le matériel.", + textAlign: TextAlign.center, + style: GoogleFonts.titilliumWeb(fontSize: 14, color: const Color(0xFF166534)), + ), + ], + ), + ); + } + + Widget _recapitulatif(String date, String heure) { + final note = this.note; + + return Container( + width: double.infinity, + padding: const EdgeInsets.all(18), + decoration: BoxDecoration( + color: Colors.white, + borderRadius: BorderRadius.circular(10), + border: Border.all(color: EnsupColors.line, width: 1.5), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + "RÉCAPITULATIF DE L'EMPRUNT", + style: GoogleFonts.darkerGrotesque( + fontSize: 12, + fontWeight: FontWeight.w700, + color: EnsupColors.muted, + letterSpacing: 0.6, + ), + ), + const SizedBox(height: 10), + _rrow("Matériel", item.nom), + _rrow("Référence", item.reference), + _rrow("Emprunteur", "Lucas Martin"), + _rrow("Date d'emprunt", date), + _rrow("Heure", heure), + _rrow("Campus", item.campus), + if (note != null) _rrow("Note", note, valueColor: const Color(0xFFD97706)), + ], + ), + ); + } + + Widget _rrow(String cle, String valeur, {Color? valueColor}) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 7), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(cle, style: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.muted)), + const SizedBox(width: 16), + Expanded( + child: Text( + valeur, + textAlign: TextAlign.right, + style: GoogleFonts.titilliumWeb( + fontSize: 13, + fontWeight: FontWeight.w600, + color: valueColor ?? EnsupColors.text, + ), + ), + ), + ], + ), + ); + } +} diff --git a/eme-frontend/lib/screens/login_screen.dart b/eme-frontend/lib/screens/login_screen.dart index 328ae84..699553a 100644 --- a/eme-frontend/lib/screens/login_screen.dart +++ b/eme-frontend/lib/screens/login_screen.dart @@ -12,7 +12,10 @@ class LoginScreen extends StatelessWidget { void _identifier(BuildContext context) { Navigator.of(context).push( - MaterialPageRoute(builder: (_) => const HomeScreen()), + MaterialPageRoute( + builder: (_) => const HomeScreen(), + settings: const RouteSettings(name: "home"), + ), ); } diff --git a/review.md b/review.md index 9efe2e9..b2bc759 100644 --- a/review.md +++ b/review.md @@ -207,4 +207,4 @@ En terminal interactif (VS Code), `migrate dev` fonctionne normalement (taper `y --- -*Dernière mise à jour : 2026-07-06 — Frontend : parcours emprunt jusqu'à la checklist de départ.* +*Dernière mise à jour : 2026-07-06 — Frontend : parcours emprunt complet (jusqu'à la confirmation).*