fix(chat): Correction race condition + Implémentation TODOs

## Corrections Critiques

### Race Condition - Statuts de Messages
- Fix : Les icônes de statut (✓, ✓✓, ✓✓ bleu) ne s'affichaient pas
- Cause : WebSocket delivery confirmations arrivaient avant messages locaux
- Solution : Pattern Optimistic UI dans chat_bloc.dart
  - Création message temporaire immédiate
  - Ajout à la liste AVANT requête HTTP
  - Remplacement par message serveur à la réponse
- Fichier : lib/presentation/state_management/chat_bloc.dart

## Implémentation TODOs (13/21)

### Social (social_header_widget.dart)
-  Copier lien du post dans presse-papiers
-  Partage natif via Share.share()
-  Dialogue de signalement avec 5 raisons

### Partage (share_post_dialog.dart)
-  Interface sélection d'amis avec checkboxes
-  Partage externe via Share API

### Média (media_upload_service.dart)
-  Parsing JSON réponse backend
-  Méthode deleteMedia() pour suppression
-  Génération miniature vidéo

### Posts (create_post_dialog.dart, edit_post_dialog.dart)
-  Extraction URL depuis uploads
-  Documentation chargement médias

### Chat (conversations_screen.dart)
-  Navigation vers notifications
-  ConversationSearchDelegate pour recherche

## Nouveaux Fichiers

### Configuration
- build-prod.ps1 : Script build production avec dart-define
- lib/core/constants/env_config.dart : Gestion environnements

### Documentation
- TODOS_IMPLEMENTED.md : Documentation complète TODOs

## Améliorations

### Architecture
- Refactoring injection de dépendances
- Amélioration routing et navigation
- Optimisation providers (UserProvider, FriendsProvider)

### UI/UX
- Amélioration thème et couleurs
- Optimisation animations
- Meilleure gestion erreurs

### Services
- Configuration API avec env_config
- Amélioration datasources (events, users)
- Optimisation modèles de données
This commit is contained in:
dahoud
2026-01-10 10:43:17 +00:00
parent 06031b01f2
commit 92612abbd7
321 changed files with 43137 additions and 4285 deletions

View File

@@ -0,0 +1,405 @@
import 'package:dartz/dartz.dart';
import '../../core/errors/exceptions.dart';
import '../../core/errors/failures.dart';
import '../../core/utils/app_logger.dart';
import '../../domain/entities/chat_message.dart';
import '../../domain/entities/conversation.dart';
import '../../domain/repositories/chat_repository.dart';
import '../datasources/chat_remote_data_source.dart';
/// Implémentation du repository de chat.
///
/// Cette classe fait le lien entre la couche domaine et la couche données,
/// en convertissant les exceptions en failures et en gérant la transformation
/// entre les modèles de données et les entités de domaine.
///
/// **Usage:**
/// ```dart
/// final repository = ChatRepositoryImpl(
/// remoteDataSource: chatRemoteDataSource,
/// );
/// final result = await repository.getConversations('userId');
/// result.fold(
/// (failure) => print('Erreur: $failure'),
/// (conversations) => print('${conversations.length} conversations'),
/// );
/// ```
class ChatRepositoryImpl implements ChatRepository {
/// Crée une nouvelle instance de [ChatRepositoryImpl].
///
/// [remoteDataSource] La source de données distante pour le chat
ChatRepositoryImpl({required this.remoteDataSource});
/// Source de données distante pour les opérations de chat
final ChatRemoteDataSource remoteDataSource;
/// Log un message si le mode debug est activé.
void _log(String message) {
AppLogger.d(message, tag: 'ChatRepositoryImpl');
}
@override
Future<Either<Failure, List<Conversation>>> getConversations(
String userId,
) async {
_log('Récupération des conversations pour $userId');
try {
if (userId.isEmpty) {
return const Left(ValidationFailure(message:
'L\'ID utilisateur ne peut pas être vide',
field: 'userId',
));
}
final conversationModels = await remoteDataSource.getConversations(userId);
final conversations = conversationModels.map((model) => model.toEntity()).toList();
_log('${conversations.length} conversations récupérées');
return Right(conversations);
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} on UnauthorizedException catch (e) {
_log('Non autorisé: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la récupération des conversations: $e',
));
}
}
@override
Future<Either<Failure, Conversation>> getOrCreateConversation(
String userId,
String participantId,
) async {
_log('Récupération/création conversation entre $userId et $participantId');
try {
if (userId.isEmpty || participantId.isEmpty) {
return const Left(ValidationFailure(message:
'Les IDs utilisateur et participant sont requis',
));
}
if (userId == participantId) {
return const Left(ValidationFailure(message:
'Impossible de créer une conversation avec soi-même',
));
}
final conversationModel = await remoteDataSource.getOrCreateConversation(
userId,
participantId,
);
_log('Conversation récupérée/créée avec succès');
return Right(conversationModel.toEntity());
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} on UnauthorizedException catch (e) {
_log('Non autorisé: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la récupération/création de la conversation: $e',
));
}
}
@override
Future<Either<Failure, List<ChatMessage>>> getMessages(
String conversationId, {
int page = 0,
int size = 50,
}) async {
_log('Récupération des messages de $conversationId (page: $page)');
try {
if (conversationId.isEmpty) {
return const Left(ValidationFailure(message:
'L\'ID de conversation ne peut pas être vide',
field: 'conversationId',
));
}
final messageModels = await remoteDataSource.getMessages(
conversationId,
page: page,
size: size,
);
final messages = messageModels.map((model) => model.toEntity()).toList();
_log('${messages.length} messages récupérés');
return Right(messages);
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} on UnauthorizedException catch (e) {
_log('Non autorisé: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la récupération des messages: $e',
));
}
}
@override
Future<Either<Failure, ChatMessage>> sendMessage({
required String senderId,
required String recipientId,
required String content,
String? messageType,
String? mediaUrl,
}) async {
_log('Envoi d\'un message de $senderId à $recipientId');
try {
if (senderId.isEmpty || recipientId.isEmpty) {
return const Left(ValidationFailure(message:
'Les IDs expéditeur et destinataire sont requis',
));
}
if (content.isEmpty) {
return const Left(ValidationFailure(message:
'Le contenu du message ne peut pas être vide',
field: 'content',
));
}
if (senderId == recipientId) {
return const Left(ValidationFailure(message:
'Impossible d\'envoyer un message à soi-même',
));
}
final messageModel = await remoteDataSource.sendMessage(
senderId: senderId,
recipientId: recipientId,
content: content,
messageType: messageType,
mediaUrl: mediaUrl,
);
_log('Message envoyé avec succès');
return Right(messageModel.toEntity());
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} on UnauthorizedException catch (e) {
_log('Non autorisé: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de l\'envoi du message: $e',
));
}
}
@override
Future<Either<Failure, void>> markMessageAsRead(String messageId) async {
_log('Marquage du message $messageId comme lu');
try {
if (messageId.isEmpty) {
return const Left(ValidationFailure(message:
'L\'ID du message ne peut pas être vide',
field: 'messageId',
));
}
await remoteDataSource.markMessageAsRead(messageId);
_log('Message marqué comme lu');
return const Right(null);
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} on UnauthorizedException catch (e) {
_log('Non autorisé: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors du marquage du message: $e',
));
}
}
@override
Future<Either<Failure, void>> markConversationAsRead(
String conversationId,
String userId,
) async {
_log('Marquage de tous les messages de $conversationId comme lus');
try {
if (conversationId.isEmpty || userId.isEmpty) {
return const Left(ValidationFailure(message:
'Les IDs conversation et utilisateur sont requis',
));
}
await remoteDataSource.markConversationAsRead(conversationId, userId);
_log('Conversation marquée comme lue');
return const Right(null);
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} on UnauthorizedException catch (e) {
_log('Non autorisé: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors du marquage de la conversation: $e',
));
}
}
@override
Future<Either<Failure, void>> deleteMessage(String messageId) async {
_log('Suppression du message $messageId');
try {
if (messageId.isEmpty) {
return const Left(ValidationFailure(message:
'L\'ID du message ne peut pas être vide',
field: 'messageId',
));
}
await remoteDataSource.deleteMessage(messageId);
_log('Message supprimé');
return const Right(null);
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} on UnauthorizedException catch (e) {
_log('Non autorisé: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la suppression du message: $e',
));
}
}
@override
Future<Either<Failure, void>> deleteConversation(String conversationId) async {
_log('Suppression de la conversation $conversationId');
try {
if (conversationId.isEmpty) {
return const Left(ValidationFailure(message:
'L\'ID de la conversation ne peut pas être vide',
field: 'conversationId',
));
}
await remoteDataSource.deleteConversation(conversationId);
_log('Conversation supprimée');
return const Right(null);
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} on UnauthorizedException catch (e) {
_log('Non autorisé: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la suppression de la conversation: $e',
));
}
}
@override
Future<Either<Failure, int>> getUnreadMessagesCount(String userId) async {
_log('Récupération du nombre de messages non lus pour $userId');
try {
if (userId.isEmpty) {
return const Left(ValidationFailure(message:
'L\'ID utilisateur ne peut pas être vide',
field: 'userId',
));
}
final count = await remoteDataSource.getUnreadMessagesCount(userId);
_log('$count messages non lus');
return Right(count);
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} on UnauthorizedException catch (e) {
_log('Non autorisé: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la récupération du nombre de messages non lus: $e',
));
}
}
}

View File

@@ -95,4 +95,13 @@ abstract class FriendsRepository {
///
/// Retourne un `Future<void>`. En cas d'erreur, l'implémentation peut lancer une exception.
Future<void> cancelFriendRequest(String friendshipId);
/// Récupère les suggestions d'amis pour un utilisateur.
///
/// [userId] : Identifiant unique de l'utilisateur.
/// [limit] : Nombre maximum de suggestions à retourner (par défaut 10).
///
/// Retourne une liste de suggestions d'amis basées sur les amis en commun
/// et d'autres critères de pertinence.
Future<List<dynamic>> getFriendSuggestions(String userId, {int limit = 10});
}

View File

@@ -6,6 +6,7 @@ import 'package:http/http.dart' as http;
import '../../core/constants/env_config.dart';
import '../../core/constants/urls.dart';
import '../../core/errors/exceptions.dart';
import '../../core/utils/app_logger.dart';
import '../../domain/entities/friend.dart';
import '../../domain/entities/friend_request.dart';
import 'friends_repository.dart';
@@ -221,9 +222,7 @@ class FriendsRepositoryImpl implements FriendsRepository {
/// Log un message si le mode debug est activé.
void _log(String message) {
if (EnvConfig.enableDetailedLogs) {
print('[FriendsRepositoryImpl] $message');
}
AppLogger.d(message, tag: 'FriendsRepositoryImpl');
}
// ============================================================================
@@ -683,4 +682,56 @@ class FriendsRepositoryImpl implements FriendsRepository {
rethrow;
}
}
/// Récupère les suggestions d'amis pour un utilisateur.
///
/// [userId] L'identifiant unique de l'utilisateur
/// [limit] Nombre maximum de suggestions (par défaut 10)
///
/// Returns une liste d'objets [FriendSuggestion]
///
/// Throws [ServerException] en cas d'erreur
///
/// **Exemple:**
/// ```dart
/// final suggestions = await repository.getFriendSuggestions('user123', limit: 5);
/// ```
@override
Future<List<dynamic>> getFriendSuggestions(String userId, {int limit = 10}) async {
_log('Récupération des suggestions d\'amis pour l\'utilisateur $userId (limit: $limit)');
if (userId.isEmpty) {
throw ValidationException('L\'ID utilisateur ne peut pas être vide');
}
if (limit <= 0) {
throw ValidationException('La limite doit être > 0');
}
try {
final uri = Uri.parse(Urls.getFriendSuggestionsWithUserId(userId, limit: limit));
final response = await _performRequest('GET', uri);
if (response.statusCode == 404) {
_log('Aucune suggestion trouvée (404) - retour d\'une liste vide');
return [];
}
final jsonResponse = _parseJsonResponse(response, [200]) as List<dynamic>?;
if (jsonResponse == null) {
return [];
}
final suggestions = jsonResponse
.map((json) => json as Map<String, dynamic>)
.toList();
_log('${suggestions.length} suggestions d\'amis récupérées avec succès');
return suggestions;
} catch (e) {
_log('Erreur lors de la récupération des suggestions d\'amis: $e');
rethrow;
}
}
}

View File

@@ -1,49 +1,308 @@
import 'dart:convert';
import 'package:afterwork/data/datasources/user_remote_data_source.dart';
import 'package:afterwork/data/models/user_model.dart';
import 'package:afterwork/domain/entities/user.dart';
import 'package:afterwork/domain/repositories/user_repository.dart';
import 'package:http/http.dart' as http;
import 'package:dartz/dartz.dart';
import '../../core/constants/urls.dart';
import '../../core/constants/env_config.dart';
import '../../core/errors/exceptions.dart';
import '../../core/errors/failures.dart';
import '../../core/utils/app_logger.dart';
import '../../domain/entities/user.dart';
import '../../domain/repositories/user_repository.dart';
import '../datasources/user_remote_data_source.dart';
import '../models/user_model.dart';
/// Implémentation du repository des utilisateurs.
/// Cette classe fait le lien entre les appels de l'application et les services distants pour les opérations sur les utilisateurs.
///
/// Cette classe fait le lien entre la couche domaine et la couche données,
/// en convertissant les exceptions en failures et en gérant la transformation
/// entre les modèles de données et les entités de domaine.
///
/// **Usage:**
/// ```dart
/// final repository = UserRepositoryImpl(
/// remoteDataSource: userRemoteDataSource,
/// );
/// final result = await repository.getUser('user123');
/// result.fold(
/// (failure) => print('Erreur: $failure'),
/// (user) => print('Utilisateur: $user'),
/// );
/// ```
class UserRepositoryImpl implements UserRepository {
final UserRemoteDataSource remoteDataSource;
/// Constructeur avec injection de la source de données distante.
/// Crée une nouvelle instance de [UserRepositoryImpl].
///
/// [remoteDataSource] La source de données distante pour les utilisateurs
UserRepositoryImpl({required this.remoteDataSource});
/// Récupère un utilisateur par son ID depuis la source de données distante.
@override
Future<User> getUser(String id) async {
UserModel userModel = await remoteDataSource.getUser(id);
return userModel; // Retourne un UserModel qui est un sous-type de User.
/// Source de données distante pour les opérations sur les utilisateurs
final UserRemoteDataSource remoteDataSource;
/// Log un message si le mode debug est activé.
void _log(String message) {
AppLogger.d(message, tag: 'UserRepositoryImpl');
}
/// Authentifie un utilisateur par email et mot de passe (en clair, temporairement).
Future<UserModel> authenticateUser(String email, String password) async {
print("Tentative d'authentification pour l'email : $email");
/// Récupère un utilisateur par son ID depuis la source de données distante.
///
/// [id] L'identifiant de l'utilisateur
///
/// Returns [Right] avec l'utilisateur si succès, [Left] avec une [Failure] si erreur
///
/// **Exemple:**
/// ```dart
/// final result = await repository.getUser('user123');
/// result.fold(
/// (failure) => handleError(failure),
/// (user) => displayUser(user),
/// );
/// ```
@override
Future<Either<Failure, User>> getUser(String id) async {
_log('Récupération de l\'utilisateur $id');
try {
// Requête POST avec les identifiants utilisateur pour l'authentification
final response = await http.post(
Uri.parse('${Urls.baseUrl}/users/authenticate'),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({'email': email, 'motDePasse': password}),
if (id.isEmpty) {
return const Left(ValidationFailure(message:
'L\'ID utilisateur ne peut pas être vide',
field: 'id',
));
}
final userModel = await remoteDataSource.getUser(id);
_log('Utilisateur $id récupéré avec succès');
return Right(userModel.toEntity());
} on UserNotFoundException catch (e) {
_log('Utilisateur $id non trouvé: ${e.message}');
return Left(ServerFailure(
message: e.message,
code: 'USER_NOT_FOUND',
statusCode: 404,
));
} on ValidationException catch (e) {
_log('Erreur de validation: ${e.message}');
return Left(ValidationFailure(message:
e.message,
field: e.field,
));
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la récupération de l\'utilisateur: $e',
));
}
}
/// Authentifie un utilisateur avec son email et mot de passe.
///
/// [email] L'adresse email de l'utilisateur
/// [password] Le mot de passe de l'utilisateur
///
/// Returns [Right] avec l'utilisateur authentifié si succès,
/// [Left] avec une [Failure] si erreur
///
/// **Exemple:**
/// ```dart
/// final result = await repository.authenticateUser(
/// 'user@example.com',
/// 'password123',
/// );
/// ```
Future<Either<Failure, User>> authenticateUser(
String email,
String password,
) async {
_log('Authentification pour: $email');
try {
if (email.isEmpty || password.isEmpty) {
return const Left(ValidationFailure(message:
'L\'email et le mot de passe sont requis',
));
}
final userModel = await remoteDataSource.authenticateUser(email, password);
_log('Authentification réussie pour: ${userModel.email}');
return Right(userModel.toEntity());
} on UnauthorizedException catch (e) {
_log('Authentification échouée: ${e.message}');
return Left(AuthenticationFailure(
message: e.message,
code: 'UNAUTHORIZED',
));
} on ValidationException catch (e) {
_log('Erreur de validation: ${e.message}');
return Left(ValidationFailure(message:
e.message,
field: e.field,
));
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de l\'authentification: $e',
));
}
}
/// Crée un nouvel utilisateur.
///
/// [user] L'entité utilisateur à créer
///
/// Returns [Right] avec l'utilisateur créé si succès,
/// [Left] avec une [Failure] si erreur
Future<Either<Failure, User>> createUser(User user) async {
_log('Création d\'un nouvel utilisateur: ${user.email}');
try {
final userModel = UserModel(
userId: user.userId,
userLastName: user.userLastName,
userFirstName: user.userFirstName,
email: user.email,
motDePasse: user.motDePasse,
profileImageUrl: user.profileImageUrl,
eventsCount: user.eventsCount,
friendsCount: user.friendsCount,
postsCount: user.postsCount,
visitedPlacesCount: user.visitedPlacesCount,
);
print("Réponse du serveur pour l'authentification : ${response.statusCode} - ${response.body}");
if (response.statusCode == 200) {
return UserModel.fromJson(jsonDecode(response.body));
} else {
throw Exception("Erreur lors de l'authentification : ${response.statusCode}");
}
final createdUser = await remoteDataSource.createUser(userModel);
_log('Utilisateur créé avec succès: ${createdUser.userId}');
return Right(createdUser.toEntity());
} on ConflictException catch (e) {
_log('Conflit lors de la création: ${e.message}');
return Left(ServerFailure(
message: e.message,
code: 'CONFLICT',
statusCode: 409,
));
} on ValidationException catch (e) {
_log('Erreur de validation: ${e.message}');
return Left(ValidationFailure(message:
e.message,
field: e.field,
));
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} catch (e) {
print("Erreur d'authentification : $e");
throw Exception("Erreur lors de l'authentification : $e");
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la création de l\'utilisateur: $e',
));
}
}
/// Met à jour un utilisateur existant.
///
/// [user] L'entité utilisateur avec les nouvelles données
///
/// Returns [Right] avec l'utilisateur mis à jour si succès,
/// [Left] avec une [Failure] si erreur
Future<Either<Failure, User>> updateUser(User user) async {
_log('Mise à jour de l\'utilisateur ${user.userId}');
try {
final userModel = UserModel(
userId: user.userId,
userLastName: user.userLastName,
userFirstName: user.userFirstName,
email: user.email,
motDePasse: user.motDePasse,
profileImageUrl: user.profileImageUrl,
eventsCount: user.eventsCount,
friendsCount: user.friendsCount,
postsCount: user.postsCount,
visitedPlacesCount: user.visitedPlacesCount,
);
final updatedUser = await remoteDataSource.updateUser(userModel);
_log('Utilisateur ${user.userId} mis à jour avec succès');
return Right(updatedUser.toEntity());
} on UserNotFoundException catch (e) {
_log('Utilisateur non trouvé: ${e.message}');
return Left(ServerFailure(
message: e.message,
code: 'USER_NOT_FOUND',
statusCode: 404,
));
} on ValidationException catch (e) {
_log('Erreur de validation: ${e.message}');
return Left(ValidationFailure(message:
e.message,
field: e.field,
));
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la mise à jour de l\'utilisateur: $e',
));
}
}
/// Supprime un utilisateur.
///
/// [id] L'identifiant de l'utilisateur à supprimer
///
/// Returns [Right] avec `null` si succès, [Left] avec une [Failure] si erreur
Future<Either<Failure, void>> deleteUser(String id) async {
_log('Suppression de l\'utilisateur $id');
try {
if (id.isEmpty) {
return const Left(ValidationFailure(message:
'L\'ID utilisateur ne peut pas être vide',
field: 'id',
));
}
await remoteDataSource.deleteUser(id);
_log('Utilisateur $id supprimé avec succès');
return const Right(null);
} on UserNotFoundException catch (e) {
_log('Utilisateur non trouvé: ${e.message}');
return Left(ServerFailure(
message: e.message,
code: 'USER_NOT_FOUND',
statusCode: 404,
));
} on ValidationException catch (e) {
_log('Erreur de validation: ${e.message}');
return Left(ValidationFailure(message:
e.message,
field: e.field,
));
} on ServerException catch (e) {
_log('Erreur serveur: ${e.message}');
return Left(ServerFailure(
message: e.message,
statusCode: e.statusCode,
));
} catch (e) {
_log('Erreur inattendue: $e');
return Left(ServerFailure(
message: 'Erreur lors de la suppression de l\'utilisateur: $e',
));
}
}
}