refactoring

This commit is contained in:
dahoud
2026-03-31 09:14:47 +00:00
parent 9bfffeeebe
commit 5383df6dcb
200 changed files with 11192 additions and 7063 deletions

View File

@@ -29,20 +29,74 @@ class ProfileRepositoryImpl implements IProfileRepository {
}
return null;
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) rethrow;
if (e.response?.statusCode == 404) return null;
rethrow;
}
}
/// Adapte les clés backend (MembreResponse) vers le modèle mobile si besoin
/// Adapte les clés backend (MembreResponse) vers le modèle mobile
void _normalizeMembreResponse(Map<String, dynamic> data) {
// photoUrl → photo
if (data.containsKey('photoUrl') && !data.containsKey('photo')) {
data['photo'] = data['photoUrl'];
}
// associationNom → organisationNom
if (data.containsKey('associationNom') && !data.containsKey('organisationNom')) {
data['organisationNom'] = data['associationNom'];
}
if (data['id'] is String == false && data['id'] != null) {
// statutCompte → statut (avec mapping des valeurs)
if (data.containsKey('statutCompte') && !data.containsKey('statut')) {
final sc = (data['statutCompte'] as String? ?? '').toUpperCase();
if (sc == 'ACTIF') {
data['statut'] = 'ACTIF';
} else if (sc == 'INACTIF') {
data['statut'] = 'INACTIF';
} else if (sc == 'SUSPENDU') {
data['statut'] = 'SUSPENDU';
} else {
// EN_ATTENTE_VALIDATION, EN_ATTENTE, etc.
data['statut'] = 'EN_ATTENTE';
}
}
// roles (List<String>) → role (premier rôle)
if (data.containsKey('roles') && !data.containsKey('role')) {
final roles = data['roles'];
if (roles is List && roles.isNotEmpty) {
data['role'] = roles.first?.toString();
}
}
// Dates LocalDate [year, month, day] → ISO string "YYYY-MM-DD"
for (final field in ['dateNaissance', 'dateAdhesion', 'dateFinAdhesion', 'dateVerificationIdentite']) {
final val = data[field];
if (val is List && val.length >= 3) {
final y = val[0].toString().padLeft(4, '0');
final m = val[1].toString().padLeft(2, '0');
final d = val[2].toString().padLeft(2, '0');
data[field] = '$y-$m-$d';
}
}
// Dates LocalDateTime [year, month, day, h, min, s, ns] → ISO string
for (final field in ['dateCreation', 'dateModification', 'derniereActivite']) {
final val = data[field];
if (val is List && val.length >= 3) {
final y = val[0].toString().padLeft(4, '0');
final m = val[1].toString().padLeft(2, '0');
final d = val[2].toString().padLeft(2, '0');
final h = val.length > 3 ? val[3].toString().padLeft(2, '0') : '00';
final min = val.length > 4 ? val[4].toString().padLeft(2, '0') : '00';
final s = val.length > 5 ? val[5].toString().padLeft(2, '0') : '00';
data[field] = '$y-$m-${d}T$h:$min:$s';
}
}
// id UUID → String
if (data['id'] != null && data['id'] is! String) {
data['id'] = data['id'].toString();
}
}
@@ -77,6 +131,7 @@ class ProfileRepositoryImpl implements IProfileRepository {
}
return null;
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) rethrow;
if (e.response?.statusCode == 404) return null;
rethrow;
}
@@ -110,6 +165,7 @@ class ProfileRepositoryImpl implements IProfileRepository {
final updated = membre.copyWith(photo: photoUrl);
return updateProfile(id, updated);
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) rethrow;
throw Exception('Erreur réseau lors de la mise à jour de la photo: ${e.message}');
} catch (e) {
throw Exception('Erreur lors de la mise à jour de la photo: $e');
@@ -135,6 +191,7 @@ class ProfileRepositoryImpl implements IProfileRepository {
throw Exception(errorMsg);
}
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) rethrow;
if (e.response?.statusCode == 400) {
throw Exception('Ancien mot de passe incorrect');
} else if (e.response?.statusCode == 401) {
@@ -161,6 +218,7 @@ class ProfileRepositoryImpl implements IProfileRepository {
throw Exception('Erreur lors de la mise à jour des préférences: ${response.statusCode}');
}
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) rethrow;
// Si l'endpoint n'existe pas (404), on sauvegarde localement via SharedPreferences
if (e.response?.statusCode == 404) {
// Fallback: stockage local uniquement
@@ -182,6 +240,7 @@ class ProfileRepositoryImpl implements IProfileRepository {
throw Exception('Erreur lors de la suppression du compte: ${response.statusCode}');
}
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) rethrow;
if (e.response?.statusCode == 403) {
throw Exception('Vous n\'avez pas les permissions pour supprimer ce compte');
} else if (e.response?.statusCode == 404) {

View File

@@ -28,6 +28,8 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
on<LoadMe>(_onLoadMe);
on<LoadMyProfile>(_onLoadMyProfile);
on<UpdateMyProfile>(_onUpdateMyProfile);
on<ChangePassword>(_onChangePassword);
on<DeleteAccount>(_onDeleteAccount);
}
/// Charge le profil du membre connecté
@@ -44,8 +46,10 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
emit(const ProfileNotFound());
}
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) return;
emit(ProfileError(_networkErrorMessage(e)));
} catch (e) {
if (e is DioException && e.type == DioExceptionType.cancel) return;
emit(ProfileError('Erreur lors du chargement du profil : $e'));
}
}
@@ -65,8 +69,10 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
emit(const ProfileNotFound());
}
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) return;
emit(ProfileError(_networkErrorMessage(e)));
} catch (e) {
if (e is DioException && e.type == DioExceptionType.cancel) return;
emit(ProfileError('Erreur lors du chargement du profil : $e'));
}
}
@@ -84,15 +90,57 @@ class ProfileBloc extends Bloc<ProfileEvent, ProfileState> {
final updated = await _updateProfile(event.membreId, event.membre);
emit(ProfileUpdated(updated));
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) return;
if (currentState is ProfileLoaded) {
emit(ProfileLoaded(currentState.membre));
}
emit(ProfileError(_networkErrorMessage(e)));
} catch (e) {
if (e is DioException && e.type == DioExceptionType.cancel) return;
emit(ProfileError('Erreur lors de la mise à jour du profil : $e'));
}
}
/// Change le mot de passe via Keycloak
Future<void> _onChangePassword(
ChangePassword event,
Emitter<ProfileState> emit,
) async {
final previousState = state;
try {
emit(const PasswordChanging());
await _repository.changePassword(event.membreId, event.oldPassword, event.newPassword);
emit(const PasswordChanged());
if (previousState is ProfileLoaded) emit(previousState);
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) return;
emit(ProfileError(_networkErrorMessage(e)));
if (previousState is ProfileLoaded) emit(previousState);
} catch (e) {
if (e is DioException && e.type == DioExceptionType.cancel) return;
emit(ProfileError(e.toString().replaceFirst('Exception: ', '')));
if (previousState is ProfileLoaded) emit(previousState);
}
}
/// Supprime le compte (soft delete)
Future<void> _onDeleteAccount(
DeleteAccount event,
Emitter<ProfileState> emit,
) async {
try {
emit(const AccountDeleting());
await _repository.deleteAccount(event.membreId);
emit(const AccountDeleted());
} on DioException catch (e) {
if (e.type == DioExceptionType.cancel) return;
emit(ProfileError(_networkErrorMessage(e)));
} catch (e) {
if (e is DioException && e.type == DioExceptionType.cancel) return;
emit(ProfileError(e.toString().replaceFirst('Exception: ', '')));
}
}
String _networkErrorMessage(DioException e) {
switch (e.type) {
case DioExceptionType.connectionTimeout:

View File

@@ -30,3 +30,27 @@ class UpdateMyProfile extends ProfileEvent {
@override
List<Object?> get props => [membreId, membre];
}
/// Change le mot de passe via Keycloak
class ChangePassword extends ProfileEvent {
final String membreId;
final String oldPassword;
final String newPassword;
const ChangePassword({
required this.membreId,
required this.oldPassword,
required this.newPassword,
});
@override
List<Object?> get props => [membreId, oldPassword, newPassword];
}
/// Supprime le compte (soft delete backend)
class DeleteAccount extends ProfileEvent {
final String membreId;
const DeleteAccount(this.membreId);
@override
List<Object?> get props => [membreId];
}

View File

@@ -50,3 +50,19 @@ class ProfileError extends ProfileState {
class ProfileNotFound extends ProfileState {
const ProfileNotFound();
}
class PasswordChanging extends ProfileState {
const PasswordChanging();
}
class PasswordChanged extends ProfileState {
const PasswordChanged();
}
class AccountDeleting extends ProfileState {
const AccountDeleting();
}
class AccountDeleted extends ProfileState {
const AccountDeleted();
}

File diff suppressed because it is too large Load Diff