fix(mobile): URL changement mdp corrigée + v3.0 — multi-org, AppAuth, sécurité prod
Auth: - profile_repository.dart: /api/auth/change-password → /api/membres/auth/change-password Multi-org (Phase 3): - OrgSelectorPage, OrgSwitcherBloc, OrgSwitcherEntry - org_context_service.dart: headers X-Active-Organisation-Id + X-Active-Role Navigation: - MorePage: navigation conditionnelle par typeOrganisation - Suppression adaptive_navigation (remplacé par main_navigation_layout) Auth AppAuth: - keycloak_webview_auth_service: fixes AppAuth Android - AuthBloc: gestion REAUTH_REQUIS + premierLoginComplet Onboarding: - Nouveaux états: payment_method_page, onboarding_shared_widgets - SouscriptionStatusModel mis à jour StatutValidationSouscription Android: - build.gradle: ProGuard/R8, network_security_config - Gradle wrapper mis à jour
This commit is contained in:
@@ -15,7 +15,7 @@ import '../../bloc/membres_bloc.dart';
|
||||
import '../../bloc/membres_event.dart';
|
||||
import '../../bloc/membres_state.dart';
|
||||
import '../../data/models/membre_complete_model.dart';
|
||||
import '../widgets/add_member_dialog.dart';
|
||||
import '../widgets/add_member_dialog.dart' show showAddMemberSheet, showCredentialsDialog;
|
||||
import 'members_page_connected.dart';
|
||||
|
||||
final _getIt = GetIt.instance;
|
||||
@@ -55,55 +55,14 @@ class MembersPageConnected extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocListener<MembresBloc, MembresState>(
|
||||
listener: (context, state) {
|
||||
// Après création : afficher le mot de passe temporaire si disponible, puis recharger
|
||||
// Après création : recharger la liste (la dialog mot de passe est gérée dans AddMemberDialog)
|
||||
if (state is MembreCreated) {
|
||||
final motDePasse = state.membre.motDePasseTemporaire;
|
||||
if (motDePasse != null && motDePasse.isNotEmpty) {
|
||||
showDialog<void>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => AlertDialog(
|
||||
title: const Text('Compte créé avec succès'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Le membre ${state.membre.nomComplet} a été créé.'),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
'Mot de passe temporaire :',
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SelectableText(
|
||||
motDePasse,
|
||||
style: const TextStyle(
|
||||
fontSize: 18,
|
||||
fontFamily: 'monospace',
|
||||
letterSpacing: 2,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
const Text(
|
||||
'Communiquez ce mot de passe au membre. Il devra le changer à sa première connexion.',
|
||||
style: TextStyle(fontSize: 12, color: Colors.grey),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
ElevatedButton(
|
||||
onPressed: () => Navigator.of(_).pop(),
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
context.read<MembresBloc>().add(LoadMembres(refresh: true, organisationId: organisationId));
|
||||
}
|
||||
|
||||
// Gestion des erreurs avec SnackBar
|
||||
if (state is MembresError) {
|
||||
final bloc = context.read<MembresBloc>();
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(state.message),
|
||||
@@ -113,12 +72,67 @@ class MembersPageConnected extends StatelessWidget {
|
||||
label: 'Réessayer',
|
||||
textColor: Colors.white,
|
||||
onPressed: () {
|
||||
context.read<MembresBloc>().add(LoadMembres(organisationId: organisationId));
|
||||
bloc.add(LoadMembres(organisationId: organisationId));
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Après activation : succès + rechargement
|
||||
if (state is MembreActivated) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Membre activé avec succès'),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(seconds: 3),
|
||||
),
|
||||
);
|
||||
context.read<MembresBloc>().add(LoadMembres(refresh: true, organisationId: organisationId));
|
||||
}
|
||||
|
||||
// Après reset mot de passe : afficher le dialog credentials
|
||||
if (state is MotDePasseReinitialise) {
|
||||
showCredentialsDialog(context, state.membre);
|
||||
}
|
||||
|
||||
// Après affectation à une organisation : succès + rechargement
|
||||
if (state is MembreAffecte) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(
|
||||
content: Text('Membre affecté à l\'organisation avec succès'),
|
||||
backgroundColor: Colors.green,
|
||||
duration: Duration(seconds: 3),
|
||||
),
|
||||
);
|
||||
context.read<MembresBloc>().add(LoadMembres(refresh: true, organisationId: organisationId));
|
||||
}
|
||||
|
||||
// Lifecycle adhésion : succès + rechargement
|
||||
if (state is MembreInvite) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Invitation envoyée'), backgroundColor: Colors.blue, duration: Duration(seconds: 3)),
|
||||
);
|
||||
context.read<MembresBloc>().add(LoadMembres(refresh: true, organisationId: organisationId));
|
||||
}
|
||||
if (state is AdhesionActivee) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Adhésion activée'), backgroundColor: Colors.green, duration: Duration(seconds: 3)),
|
||||
);
|
||||
context.read<MembresBloc>().add(LoadMembres(refresh: true, organisationId: organisationId));
|
||||
}
|
||||
if (state is AdhesionSuspendue) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Adhésion suspendue'), backgroundColor: Colors.orange, duration: Duration(seconds: 3)),
|
||||
);
|
||||
context.read<MembresBloc>().add(LoadMembres(refresh: true, organisationId: organisationId));
|
||||
}
|
||||
if (state is MembreRadie) {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
const SnackBar(content: Text('Membre radié de l\'organisation'), backgroundColor: Colors.red, duration: Duration(seconds: 3)),
|
||||
);
|
||||
context.read<MembresBloc>().add(LoadMembres(refresh: true, organisationId: organisationId));
|
||||
}
|
||||
},
|
||||
child: BlocBuilder<MembresBloc, MembresState>(
|
||||
builder: (context, state) {
|
||||
@@ -178,6 +192,7 @@ class MembersPageConnected extends StatelessWidget {
|
||||
totalCount: state.totalElements,
|
||||
currentPage: state.currentPage,
|
||||
totalPages: state.totalPages,
|
||||
organisationId: organisationId,
|
||||
onPageChanged: (newPage, recherche) {
|
||||
AppLogger.userAction('Load page', data: {'page': newPage});
|
||||
context.read<MembresBloc>().add(LoadMembres(page: newPage, recherche: recherche, organisationId: organisationId));
|
||||
@@ -189,16 +204,37 @@ class MembersPageConnected extends StatelessWidget {
|
||||
onSearch: (query) {
|
||||
context.read<MembresBloc>().add(LoadMembres(page: 0, recherche: query, organisationId: organisationId));
|
||||
},
|
||||
onAddMember: () async {
|
||||
final bloc = context.read<MembresBloc>();
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (_) => BlocProvider.value(
|
||||
value: bloc,
|
||||
child: const AddMemberDialog(),
|
||||
),
|
||||
);
|
||||
onAddMember: () => showAddMemberSheet(context),
|
||||
onActivateMember: (memberId) {
|
||||
context.read<MembresBloc>().add(ActivateMembre(memberId));
|
||||
},
|
||||
onResetPassword: (memberId) {
|
||||
context.read<MembresBloc>().add(ResetMotDePasse(memberId));
|
||||
},
|
||||
onAffecterOrganisation: organisationId == null
|
||||
? (memberId, orgId) {
|
||||
context.read<MembresBloc>().add(AffecterOrganisation(memberId, orgId));
|
||||
}
|
||||
: null,
|
||||
onLifecycleAction: organisationId != null
|
||||
? (memberId, action, motif) {
|
||||
final bloc = context.read<MembresBloc>();
|
||||
switch (action) {
|
||||
case 'inviter':
|
||||
bloc.add(InviterMembre(membreId: memberId, organisationId: organisationId!));
|
||||
break;
|
||||
case 'activer':
|
||||
bloc.add(ActiverAdhesion(membreId: memberId, organisationId: organisationId!, motif: motif));
|
||||
break;
|
||||
case 'suspendre':
|
||||
bloc.add(SuspendrAdhesion(membreId: memberId, organisationId: organisationId!, motif: motif));
|
||||
break;
|
||||
case 'radier':
|
||||
bloc.add(RadierAdhesion(membreId: memberId, organisationId: organisationId!, motif: motif));
|
||||
break;
|
||||
}
|
||||
}
|
||||
: null,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user