Files
afterwork/lib/data/repositories/user_repository_impl.dart
dahoud 92612abbd7 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
2026-01-10 10:43:17 +00:00

309 lines
9.6 KiB
Dart

import 'package:dartz/dartz.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 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 {
/// Crée une nouvelle instance de [UserRepositoryImpl].
///
/// [remoteDataSource] La source de données distante pour les utilisateurs
UserRepositoryImpl({required this.remoteDataSource});
/// 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');
}
/// 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 {
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,
);
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) {
_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',
));
}
}
}