diff --git a/eme-frontend/lib/screens/home_screen.dart b/eme-frontend/lib/screens/home_screen.dart index 801f56c..7cda671 100644 --- a/eme-frontend/lib/screens/home_screen.dart +++ b/eme-frontend/lib/screens/home_screen.dart @@ -14,9 +14,18 @@ import "restitution_select_screen.dart"; class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); - void _quitter(BuildContext context) { - AuthService.clearSession(); - Navigator.of(context).pop(); + Future _quitter(BuildContext context) async { + try { + await AuthService.signOut(); + if (context.mounted) { + Navigator.of(context).pop(); + } + } catch (error) { + if (!context.mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(error.toString()))); + } } @override @@ -48,7 +57,7 @@ class HomeScreen extends StatelessWidget { campusTag: DemoIdentity.campusTag, userName: DemoIdentity.userName, userInitials: DemoIdentity.userInitials, - onBack: () => _quitter(context), + onBack: () async => _quitter(context), ), Expanded( child: SingleChildScrollView( diff --git a/eme-frontend/lib/screens/login_screen.dart b/eme-frontend/lib/screens/login_screen.dart index 9da2a52..b4b8395 100644 --- a/eme-frontend/lib/screens/login_screen.dart +++ b/eme-frontend/lib/screens/login_screen.dart @@ -1,6 +1,7 @@ import "package:flutter/material.dart"; import "package:google_fonts/google_fonts.dart"; import "../demo_identity.dart"; +import "../services/api_client.dart"; import "../services/auth_service.dart"; import "../theme/ensup_colors.dart"; import "../widgets/ensup_top_bar.dart"; @@ -10,11 +11,17 @@ import "home_screen.dart"; import "responsable_screen.dart"; /// Écran de démarrage : identification de l'étudiant (RG01/RG02). -class LoginScreen extends StatelessWidget { +class LoginScreen extends StatefulWidget { const LoginScreen({super.key}); - void _identifier(BuildContext context) { - AuthService.selectDemoStudent(); + @override + State createState() => _LoginScreenState(); +} + +class _LoginScreenState extends State { + bool _connexionEnCours = false; + + void _ouvrirEtudiant() { Navigator.of(context).push( MaterialPageRoute( builder: (_) => const HomeScreen(), @@ -23,8 +30,7 @@ class LoginScreen extends StatelessWidget { ); } - void _identifierResponsable(BuildContext context) { - AuthService.selectDemoResponsable(); + void _ouvrirResponsable() { Navigator.of(context).push( MaterialPageRoute( builder: (_) => const ResponsableScreen(), @@ -33,6 +39,83 @@ class LoginScreen extends StatelessWidget { ); } + void _identifierParQr() { + if (_connexionEnCours) return; + if (AuthService.mode == AuthenticationMode.azure) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text( + "L'identification QR securisee n'est pas encore configuree.", + ), + ), + ); + return; + } + + AuthService.selectDemoStudent(); + _ouvrirEtudiant(); + } + + Future _connecterMicrosoft({required bool responsableDemo}) async { + if (_connexionEnCours) return; + + setState(() => _connexionEnCours = true); + try { + if (AuthService.mode == AuthenticationMode.demo) { + if (responsableDemo) { + AuthService.selectDemoResponsable(); + _ouvrirResponsable(); + } else { + AuthService.selectDemoStudent(); + _ouvrirEtudiant(); + } + return; + } + + await AuthService.signInWithMicrosoft(); + final reponse = await ApiClient.get("/auth/me"); + final roleCode = _roleCode(reponse); + if (!mounted) return; + + switch (roleCode) { + case "ETUDIANT": + _ouvrirEtudiant(); + case "RESPONSABLE": + _ouvrirResponsable(); + default: + throw StateError("Role utilisateur non autorise."); + } + } catch (error) { + if (!mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(error.toString()))); + } finally { + if (mounted) { + setState(() => _connexionEnCours = false); + } + } + } + + String _roleCode(dynamic reponse) { + if (reponse is! Map || reponse["data"] is! Map) { + throw StateError("Profil utilisateur invalide."); + } + + final data = reponse["data"] as Map; + if (data["role"] is! Map) { + throw StateError("Role utilisateur absent."); + } + + final role = data["role"] as Map; + final code = role["code"]; + if (code is! String) { + throw StateError("Role utilisateur invalide."); + } + + return code; + } + @override Widget build(BuildContext context) { return Scaffold( @@ -134,7 +217,9 @@ class LoginScreen extends StatelessWidget { label: "Scanner ma carte étudiante", description: "Présentez votre carte étudiante dématérialisée à la douchette ou à la tablette", - onTap: () => _identifier(context), + onTap: _connexionEnCours + ? null + : _identifierParQr, ), const SizedBox(height: 12), IdentificationOption( @@ -144,7 +229,11 @@ class LoginScreen extends StatelessWidget { "Connexion compte professionnel ENSUP", description: "Utiliser mon adresse e-mail Microsoft 365", - onTap: () => _identifier(context), + onTap: _connexionEnCours + ? null + : () => _connecterMicrosoft( + responsableDemo: false, + ), ), const SizedBox(height: 20), Row( @@ -173,8 +262,11 @@ class LoginScreen extends StatelessWidget { SizedBox( width: double.infinity, child: OutlinedButton.icon( - onPressed: () => - _identifierResponsable(context), + onPressed: _connexionEnCours + ? null + : () => _connecterMicrosoft( + responsableDemo: true, + ), icon: const Icon( Icons.person_outline, size: 16, diff --git a/eme-frontend/lib/screens/responsable_screen.dart b/eme-frontend/lib/screens/responsable_screen.dart index a0aa06f..1e8617a 100644 --- a/eme-frontend/lib/screens/responsable_screen.dart +++ b/eme-frontend/lib/screens/responsable_screen.dart @@ -45,9 +45,18 @@ class _ResponsableScreenState extends State { setState(() => _future = _charger()); } - void _quitter() { - AuthService.clearSession(); - Navigator.of(context).pop(); + Future _quitter() async { + try { + await AuthService.signOut(); + if (mounted) { + Navigator.of(context).pop(); + } + } catch (error) { + if (!mounted) return; + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(error.toString()))); + } } Future _changerStatut(Map anomalie) async {