feat(auth): restore authenticated user profile

This commit is contained in:
SaidSoighiri94
2026-07-23 14:39:35 +02:00
parent dc208fa13a
commit 36224f30ee
8 changed files with 276 additions and 76 deletions
+13 -5
View File
@@ -1,10 +1,18 @@
/// Identité simulée utilisée tant que l'authentification Azure AD n'est pas branchée. import "services/auth_service.dart";
/// Identité de secours utilisée lorsque aucun profil de session n'est chargé.
class DemoIdentity { class DemoIdentity {
DemoIdentity._(); DemoIdentity._();
static const userName = "Lucas Martin"; static String get userName =>
static const userInitials = "LM"; AuthService.currentProfile?.fullName ?? "Lucas Martin";
static const userSubtitle = "Étudiant · B2 Informatique · Ensitech Cergy"; static String get userInitials =>
static const campusTag = "Saint-Christophe · Cergy"; AuthService.currentProfile?.initials ?? "LM";
static String get userSubtitle =>
AuthService.currentProfile?.subtitle ??
"Étudiant · B2 Informatique · Ensitech Cergy";
static String get campusTag =>
AuthService.currentProfile?.campusTag ?? "Saint-Christophe · Cergy";
static const loginCampusTag = "Ensitech · Cergy"; static const loginCampusTag = "Ensitech · Cergy";
} }
@@ -0,0 +1,90 @@
class AuthenticatedProfile {
const AuthenticatedProfile({
required this.id,
required this.nom,
required this.prenom,
required this.email,
required this.classe,
required this.roleCode,
required this.roleLabel,
required this.campusId,
required this.campusNom,
required this.campusVille,
});
final int id;
final String nom;
final String prenom;
final String email;
final String? classe;
final String roleCode;
final String roleLabel;
final int campusId;
final String campusNom;
final String campusVille;
factory AuthenticatedProfile.fromApi(dynamic reponse) {
if (reponse is! Map || reponse["data"] is! Map) {
throw const FormatException("Profil utilisateur invalide.");
}
final data = reponse["data"] as Map;
final role = data["role"];
final campus = data["campus"];
if (role is! Map || campus is! Map) {
throw const FormatException("Role ou campus utilisateur invalide.");
}
final id = data["id"];
final campusId = campus["id"];
if (id is! int || campusId is! int) {
throw const FormatException("Identifiant utilisateur invalide.");
}
final classe = data["classe"];
if (classe != null && classe is! String) {
throw const FormatException("Classe utilisateur invalide.");
}
return AuthenticatedProfile(
id: id,
nom: _requiredString(data, "nom"),
prenom: _requiredString(data, "prenom"),
email: _requiredString(data, "email"),
classe: classe as String?,
roleCode: _requiredString(role, "code"),
roleLabel: _requiredString(role, "libelle"),
campusId: campusId,
campusNom: _requiredString(campus, "nom"),
campusVille: _requiredString(campus, "ville"),
);
}
String get fullName => "$prenom $nom";
String get initials {
final first = prenom.trim().isEmpty ? "" : prenom.trim()[0];
final last = nom.trim().isEmpty ? "" : nom.trim()[0];
return "$first$last".toUpperCase();
}
String get campusTag => "$campusNom · $campusVille";
String get subtitle {
final details = <String>[roleLabel];
final studentClass = classe?.trim();
if (studentClass != null && studentClass.isNotEmpty) {
details.add(studentClass);
}
details.add(campusTag);
return details.join(" · ");
}
static String _requiredString(Map source, String key) {
final value = source[key];
if (value is! String || value.trim().isEmpty) {
throw FormatException("Champ utilisateur invalide : $key.");
}
return value.trim();
}
}
@@ -23,7 +23,8 @@ class ConfirmationScreen extends StatelessWidget {
final dateEmprunt = emprunt.dateEmprunt; final dateEmprunt = emprunt.dateEmprunt;
final date = final date =
"${_deuxChiffres(dateEmprunt.day)}/${_deuxChiffres(dateEmprunt.month)}/${dateEmprunt.year}"; "${_deuxChiffres(dateEmprunt.day)}/${_deuxChiffres(dateEmprunt.month)}/${dateEmprunt.year}";
final heure = "${_deuxChiffres(dateEmprunt.hour)}:${_deuxChiffres(dateEmprunt.minute)}"; final heure =
"${_deuxChiffres(dateEmprunt.hour)}:${_deuxChiffres(dateEmprunt.minute)}";
return Scaffold( return Scaffold(
backgroundColor: EnsupColors.soft, backgroundColor: EnsupColors.soft,
@@ -48,7 +49,7 @@ class ConfirmationScreen extends StatelessWidget {
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: Column( child: Column(
children: [ children: [
const EnsupTopBar( EnsupTopBar(
brandText: "EME · Confirmation", brandText: "EME · Confirmation",
campusTag: DemoIdentity.campusTag, campusTag: DemoIdentity.campusTag,
), ),
@@ -63,7 +64,10 @@ class ConfirmationScreen extends StatelessWidget {
), ),
child: Center( child: Center(
child: SingleChildScrollView( child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 32), padding: const EdgeInsets.symmetric(
horizontal: 28,
vertical: 32,
),
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 560), constraints: const BoxConstraints(maxWidth: 560),
child: Column( child: Column(
@@ -75,10 +79,15 @@ class ConfirmationScreen extends StatelessWidget {
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: FilledButton.icon( child: FilledButton.icon(
onPressed: () => Navigator.of(context).popUntil( onPressed: () =>
(route) => route.settings.name == "home", Navigator.of(context).popUntil(
(route) =>
route.settings.name == "home",
),
icon: const Icon(
Icons.home_outlined,
size: 18,
), ),
icon: const Icon(Icons.home_outlined, size: 18),
label: Text( label: Text(
"Retour à l'accueil", "Retour à l'accueil",
style: GoogleFonts.darkerGrotesque( style: GoogleFonts.darkerGrotesque(
@@ -88,9 +97,13 @@ class ConfirmationScreen extends StatelessWidget {
), ),
style: FilledButton.styleFrom( style: FilledButton.styleFrom(
backgroundColor: EnsupColors.cyan, backgroundColor: EnsupColors.cyan,
padding: const EdgeInsets.symmetric(vertical: 16), padding: const EdgeInsets.symmetric(
vertical: 16,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(
10,
),
), ),
), ),
), ),
@@ -118,7 +131,9 @@ class ConfirmationScreen extends StatelessWidget {
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.all(36), padding: const EdgeInsets.all(36),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: const LinearGradient(colors: [Color(0xFFF0FDF4), Color(0xFFECFDF5)]), gradient: const LinearGradient(
colors: [Color(0xFFF0FDF4), Color(0xFFECFDF5)],
),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
border: Border.all(color: const Color(0xFFBBF7D0), width: 2), border: Border.all(color: const Color(0xFFBBF7D0), width: 2),
), ),
@@ -129,7 +144,9 @@ class ConfirmationScreen extends StatelessWidget {
height: 72, height: 72,
decoration: BoxDecoration( decoration: BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
gradient: const LinearGradient(colors: [Color(0xFF16A34A), Color(0xFF22C55E)]), gradient: const LinearGradient(
colors: [Color(0xFF16A34A), Color(0xFF22C55E)],
),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: const Color(0xFF16A34A).withValues(alpha: 0.3), color: const Color(0xFF16A34A).withValues(alpha: 0.3),
@@ -153,7 +170,10 @@ class ConfirmationScreen extends StatelessWidget {
Text( Text(
"Votre emprunt a bien été enregistré. Vous pouvez récupérer le matériel.", "Votre emprunt a bien été enregistré. Vous pouvez récupérer le matériel.",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.titilliumWeb(fontSize: 14, color: const Color(0xFF166534)), style: GoogleFonts.titilliumWeb(
fontSize: 14,
color: const Color(0xFF166534),
),
), ),
], ],
), ),
@@ -191,7 +211,8 @@ class ConfirmationScreen extends StatelessWidget {
_rrow("Date d'emprunt", date), _rrow("Date d'emprunt", date),
_rrow("Heure", heure), _rrow("Heure", heure),
_rrow("Campus", item.campus), _rrow("Campus", item.campus),
if (note != null) _rrow("Note", note, valueColor: const Color(0xFFD97706)), if (note != null)
_rrow("Note", note, valueColor: const Color(0xFFD97706)),
], ],
), ),
); );
@@ -203,7 +224,13 @@ class ConfirmationScreen extends StatelessWidget {
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(cle, style: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.muted)), Text(
cle,
style: GoogleFonts.titilliumWeb(
fontSize: 13,
color: EnsupColors.muted,
),
),
const SizedBox(width: 16), const SizedBox(width: 16),
Expanded( Expanded(
child: Text( child: Text(
+1 -1
View File
@@ -71,7 +71,7 @@ class HomeScreen extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const ProfileCard( ProfileCard(
name: DemoIdentity.userName, name: DemoIdentity.userName,
subtitle: DemoIdentity.userSubtitle, subtitle: DemoIdentity.userSubtitle,
initials: DemoIdentity.userInitials, initials: DemoIdentity.userInitials,
+53 -38
View File
@@ -21,6 +21,14 @@ class LoginScreen extends StatefulWidget {
class _LoginScreenState extends State<LoginScreen> { class _LoginScreenState extends State<LoginScreen> {
bool _connexionEnCours = false; bool _connexionEnCours = false;
@override
void initState() {
super.initState();
if (AuthService.mode == AuthenticationMode.azure) {
WidgetsBinding.instance.addPostFrameCallback((_) => _restaurerSession());
}
}
void _ouvrirEtudiant() { void _ouvrirEtudiant() {
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
@@ -39,7 +47,44 @@ class _LoginScreenState extends State<LoginScreen> {
); );
} }
void _identifierParQr() { void _ouvrirPourRole(String roleCode) {
switch (roleCode) {
case "ETUDIANT":
_ouvrirEtudiant();
case "RESPONSABLE":
_ouvrirResponsable();
default:
throw StateError("Role utilisateur non autorise.");
}
}
Future<void> _restaurerSession() async {
setState(() => _connexionEnCours = true);
try {
if (!await AuthService.hasMicrosoftAccount()) {
return;
}
final reponse = await ApiClient.get("/auth/me");
final profile = AuthService.setProfileFromApi(reponse);
if (mounted) {
_ouvrirPourRole(profile.roleCode);
}
} catch (_) {
if (!mounted) return;
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text("La session Microsoft doit etre renouvelee."),
),
);
} finally {
if (mounted) {
setState(() => _connexionEnCours = false);
}
}
}
Future<void> _identifierParQr() async {
if (_connexionEnCours) return; if (_connexionEnCours) return;
if (AuthService.mode == AuthenticationMode.azure) { if (AuthService.mode == AuthenticationMode.azure) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
@@ -52,8 +97,7 @@ class _LoginScreenState extends State<LoginScreen> {
return; return;
} }
AuthService.selectDemoStudent(); await _connecterMicrosoft(responsableDemo: false);
_ouvrirEtudiant();
} }
Future<void> _connecterMicrosoft({required bool responsableDemo}) async { Future<void> _connecterMicrosoft({required bool responsableDemo}) async {
@@ -64,27 +108,17 @@ class _LoginScreenState extends State<LoginScreen> {
if (AuthService.mode == AuthenticationMode.demo) { if (AuthService.mode == AuthenticationMode.demo) {
if (responsableDemo) { if (responsableDemo) {
AuthService.selectDemoResponsable(); AuthService.selectDemoResponsable();
_ouvrirResponsable();
} else { } else {
AuthService.selectDemoStudent(); AuthService.selectDemoStudent();
_ouvrirEtudiant();
} }
return; } else {
}
await AuthService.signInWithMicrosoft(); 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.");
} }
final reponse = await ApiClient.get("/auth/me");
final profile = AuthService.setProfileFromApi(reponse);
if (!mounted) return;
_ouvrirPourRole(profile.roleCode);
} catch (error) { } catch (error) {
if (!mounted) return; if (!mounted) return;
ScaffoldMessenger.of( ScaffoldMessenger.of(
@@ -97,25 +131,6 @@ class _LoginScreenState extends State<LoginScreen> {
} }
} }
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 @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@@ -1,7 +1,6 @@
import "package:flutter/material.dart"; import "package:flutter/material.dart";
import "package:google_fonts/google_fonts.dart"; import "package:google_fonts/google_fonts.dart";
import "../demo_identity.dart";
import "../services/auth_service.dart"; import "../services/auth_service.dart";
import "../services/responsable_service.dart"; import "../services/responsable_service.dart";
import "../theme/ensup_colors.dart"; import "../theme/ensup_colors.dart";
@@ -463,6 +462,12 @@ class _ResponsableTopBar extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final profile = AuthService.currentProfile;
final campusTag = profile?.campusTag ?? "Ensitech · Cergy";
final initials = profile?.initials ?? "KB";
final userName = profile?.fullName ?? "Karim Benali";
final roleLabel = profile?.roleLabel ?? "Responsable matériel";
return Container( return Container(
height: 68, height: 68,
padding: const EdgeInsets.symmetric(horizontal: 20), padding: const EdgeInsets.symmetric(horizontal: 20),
@@ -533,7 +538,7 @@ class _ResponsableTopBar extends StatelessWidget {
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Text(
DemoIdentity.loginCampusTag, campusTag,
style: GoogleFonts.titilliumWeb( style: GoogleFonts.titilliumWeb(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
@@ -565,7 +570,7 @@ class _ResponsableTopBar extends StatelessWidget {
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: Text( child: Text(
"KB", initials,
style: GoogleFonts.darkerGrotesque( style: GoogleFonts.darkerGrotesque(
color: Colors.white, color: Colors.white,
fontSize: 13, fontSize: 13,
@@ -580,7 +585,7 @@ class _ResponsableTopBar extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Text(
"Karim Benali", userName,
style: GoogleFonts.titilliumWeb( style: GoogleFonts.titilliumWeb(
fontSize: 13, fontSize: 13,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
@@ -588,7 +593,7 @@ class _ResponsableTopBar extends StatelessWidget {
), ),
), ),
Text( Text(
"Responsable matériel", roleLabel,
style: GoogleFonts.titilliumWeb( style: GoogleFonts.titilliumWeb(
fontSize: 11, fontSize: 11,
color: EnsupColors.muted, color: EnsupColors.muted,
@@ -10,7 +10,11 @@ import "../widgets/brand_corners.dart";
/// Résultat de la restitution (RG17-RG20) : conforme (succès) ou non conforme /// Résultat de la restitution (RG17-RG20) : conforme (succès) ou non conforme
/// (anomalie détectée + notification au responsable). /// (anomalie détectée + notification au responsable).
class ResultatRetourScreen extends StatelessWidget { class ResultatRetourScreen extends StatelessWidget {
const ResultatRetourScreen({super.key, required this.emprunt, required this.anomalies}); const ResultatRetourScreen({
super.key,
required this.emprunt,
required this.anomalies,
});
final EmpruntItem emprunt; final EmpruntItem emprunt;
final List<AnomalieRetour> anomalies; final List<AnomalieRetour> anomalies;
@@ -48,7 +52,7 @@ class ResultatRetourScreen extends StatelessWidget {
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: Column( child: Column(
children: [ children: [
const EnsupTopBar( EnsupTopBar(
brandText: "EME · Résultat du contrôle", brandText: "EME · Résultat du contrôle",
campusTag: DemoIdentity.campusTag, campusTag: DemoIdentity.campusTag,
), ),
@@ -63,7 +67,10 @@ class ResultatRetourScreen extends StatelessWidget {
), ),
child: Center( child: Center(
child: SingleChildScrollView( child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 32), padding: const EdgeInsets.symmetric(
horizontal: 28,
vertical: 32,
),
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 560), constraints: const BoxConstraints(maxWidth: 560),
child: Column( child: Column(
@@ -73,10 +80,15 @@ class ResultatRetourScreen extends StatelessWidget {
SizedBox( SizedBox(
width: double.infinity, width: double.infinity,
child: FilledButton.icon( child: FilledButton.icon(
onPressed: () => Navigator.of(context).popUntil( onPressed: () =>
(route) => route.settings.name == "home", Navigator.of(context).popUntil(
(route) =>
route.settings.name == "home",
),
icon: const Icon(
Icons.home_outlined,
size: 18,
), ),
icon: const Icon(Icons.home_outlined, size: 18),
label: Text( label: Text(
"Retour à l'accueil", "Retour à l'accueil",
style: GoogleFonts.darkerGrotesque( style: GoogleFonts.darkerGrotesque(
@@ -86,9 +98,13 @@ class ResultatRetourScreen extends StatelessWidget {
), ),
style: FilledButton.styleFrom( style: FilledButton.styleFrom(
backgroundColor: EnsupColors.cyan, backgroundColor: EnsupColors.cyan,
padding: const EdgeInsets.symmetric(vertical: 16), padding: const EdgeInsets.symmetric(
vertical: 16,
),
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(
10,
),
), ),
), ),
), ),
@@ -116,7 +132,9 @@ class ResultatRetourScreen extends StatelessWidget {
width: double.infinity, width: double.infinity,
padding: const EdgeInsets.all(36), padding: const EdgeInsets.all(36),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: const LinearGradient(colors: [Color(0xFFF0FDF4), Color(0xFFECFDF5)]), gradient: const LinearGradient(
colors: [Color(0xFFF0FDF4), Color(0xFFECFDF5)],
),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
border: Border.all(color: const Color(0xFFBBF7D0), width: 2), border: Border.all(color: const Color(0xFFBBF7D0), width: 2),
), ),
@@ -127,7 +145,9 @@ class ResultatRetourScreen extends StatelessWidget {
height: 72, height: 72,
decoration: const BoxDecoration( decoration: const BoxDecoration(
shape: BoxShape.circle, shape: BoxShape.circle,
gradient: LinearGradient(colors: [Color(0xFF16A34A), Color(0xFF22C55E)]), gradient: LinearGradient(
colors: [Color(0xFF16A34A), Color(0xFF22C55E)],
),
), ),
child: const Icon(Icons.check, color: Colors.white, size: 36), child: const Icon(Icons.check, color: Colors.white, size: 36),
), ),
@@ -144,7 +164,10 @@ class ResultatRetourScreen extends StatelessWidget {
Text( Text(
"L'emprunt a été clôturé et le matériel est de nouveau disponible.", "L'emprunt a été clôturé et le matériel est de nouveau disponible.",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.titilliumWeb(fontSize: 14, color: const Color(0xFF166534)), style: GoogleFonts.titilliumWeb(
fontSize: 14,
color: const Color(0xFF166534),
),
), ),
], ],
), ),
@@ -164,12 +187,19 @@ class ResultatRetourScreen extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
color: EnsupColors.red.withValues(alpha: 0.06), color: EnsupColors.red.withValues(alpha: 0.06),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
border: Border.all(color: EnsupColors.red.withValues(alpha: 0.2), width: 1.5), border: Border.all(
color: EnsupColors.red.withValues(alpha: 0.2),
width: 1.5,
),
), ),
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
const Icon(Icons.warning_amber_rounded, color: EnsupColors.red, size: 24), const Icon(
Icons.warning_amber_rounded,
color: EnsupColors.red,
size: 24,
),
const SizedBox(width: 12), const SizedBox(width: 12),
Expanded( Expanded(
child: Column( child: Column(
@@ -227,7 +257,10 @@ class ResultatRetourScreen extends StatelessWidget {
anomalie.etatRetour, anomalie.etatRetour,
valeurCouleur: EnsupColors.red, valeurCouleur: EnsupColors.red,
), ),
_drow("Matériel", "${emprunt.materiel.nom} · ${emprunt.materiel.reference}"), _drow(
"Matériel",
"${emprunt.materiel.nom} · ${emprunt.materiel.reference}",
),
_drow("Emprunteur", DemoIdentity.userName), _drow("Emprunteur", DemoIdentity.userName),
_drow("Date détection", date), _drow("Date détection", date),
], ],
@@ -237,7 +270,11 @@ class ResultatRetourScreen extends StatelessWidget {
Text( Text(
"Le responsable matériel traitera cette anomalie. Vous pouvez retourner à l'accueil.", "Le responsable matériel traitera cette anomalie. Vous pouvez retourner à l'accueil.",
textAlign: TextAlign.center, textAlign: TextAlign.center,
style: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.muted, height: 1.6), style: GoogleFonts.titilliumWeb(
fontSize: 13,
color: EnsupColors.muted,
height: 1.6,
),
), ),
], ],
); );
@@ -249,7 +286,13 @@ class ResultatRetourScreen extends StatelessWidget {
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(cle, style: GoogleFonts.titilliumWeb(fontSize: 13, color: EnsupColors.muted)), Text(
cle,
style: GoogleFonts.titilliumWeb(
fontSize: 13,
color: EnsupColors.muted,
),
),
const SizedBox(width: 16), const SizedBox(width: 16),
Expanded( Expanded(
child: Text( child: Text(
@@ -1,3 +1,4 @@
import "../models/authenticated_profile.dart";
import "msal_bridge.dart"; import "msal_bridge.dart";
enum AuthenticationMode { demo, azure } enum AuthenticationMode { demo, azure }
@@ -19,8 +20,11 @@ class AuthService {
static const String demoResponsableEmail = "karim.benali@ensup.eu"; static const String demoResponsableEmail = "karim.benali@ensup.eu";
static String? _demoEmail; static String? _demoEmail;
static AuthenticatedProfile? _currentProfile;
static bool _azureInitialized = false; static bool _azureInitialized = false;
static AuthenticatedProfile? get currentProfile => _currentProfile;
static AuthenticationMode get mode { static AuthenticationMode get mode {
return switch (_configuredMode) { return switch (_configuredMode) {
"demo" => AuthenticationMode.demo, "demo" => AuthenticationMode.demo,
@@ -41,6 +45,13 @@ class AuthService {
static void clearSession() { static void clearSession() {
_demoEmail = null; _demoEmail = null;
_currentProfile = null;
}
static AuthenticatedProfile setProfileFromApi(dynamic reponse) {
final profile = AuthenticatedProfile.fromApi(reponse);
_currentProfile = profile;
return profile;
} }
static Future<void> signInWithMicrosoft() async { static Future<void> signInWithMicrosoft() async {
@@ -57,6 +68,7 @@ class AuthService {
if (mode == AuthenticationMode.azure) { if (mode == AuthenticationMode.azure) {
await _initializeAzure(); await _initializeAzure();
await MsalBridge.signOut(); await MsalBridge.signOut();
_currentProfile = null;
return; return;
} }