feat(frontend): Séparation des demandes d'amitié envoyées et reçues
- Ajout de deux endpoints distincts dans Urls: getSentFriendRequestsWithUserId et getReceivedFriendRequestsWithUserId - Ajout de méthodes dans FriendsRepository et FriendsRepositoryImpl pour récupérer séparément les demandes envoyées et reçues - Ajout de la méthode cancelFriendRequest pour annuler une demande envoyée - Modification de FriendsProvider pour gérer deux listes distinctes: sentRequests et receivedRequests - Mise à jour de FriendsScreen pour afficher deux sections: - Demandes reçues: avec boutons Accepter/Rejeter - Demandes envoyées: avec bouton Annuler uniquement - Correction du mapping JSON dans FriendRequest.fromJson (userNom/userPrenoms correctement mappés) - Amélioration de FriendRequestCard pour gérer les deux types de demandes - Correction de la validation d'URL d'image dans FriendDetailScreen - Support du champ uuid dans UserModel.fromJson pour compatibilité backend
This commit is contained in:
@@ -1,45 +1,223 @@
|
||||
import '../../core/constants/env_config.dart';
|
||||
import '../../domain/entities/user.dart';
|
||||
|
||||
/// Modèle représentant l'utilisateur dans l'application AfterWork.
|
||||
/// Ce modèle est utilisé pour la conversion JSON et l'interaction avec l'API.
|
||||
/// Modèle de données pour les utilisateurs (Data Transfer Object).
|
||||
///
|
||||
/// Cette classe est responsable de la sérialisation/désérialisation
|
||||
/// avec l'API backend et convertit vers/depuis l'entité de domaine [User].
|
||||
///
|
||||
/// **Usage:**
|
||||
/// ```dart
|
||||
/// // Depuis JSON
|
||||
/// final user = UserModel.fromJson(jsonData);
|
||||
///
|
||||
/// // Vers JSON
|
||||
/// final json = user.toJson();
|
||||
///
|
||||
/// // Vers entité de domaine
|
||||
/// final entity = user.toEntity();
|
||||
/// ```
|
||||
class UserModel extends User {
|
||||
UserModel({
|
||||
required String userId,
|
||||
required String userLastName,
|
||||
required String userFirstName,
|
||||
required String email,
|
||||
required String motDePasse,
|
||||
required String profileImageUrl,
|
||||
}) : super(
|
||||
userId: userId,
|
||||
userLastName: userLastName,
|
||||
userFirstName: userFirstName,
|
||||
email: email,
|
||||
motDePasse: motDePasse,
|
||||
profileImageUrl: profileImageUrl,
|
||||
);
|
||||
/// Crée une nouvelle instance de [UserModel].
|
||||
///
|
||||
/// [userId] L'identifiant unique de l'utilisateur
|
||||
/// [userLastName] Le nom de famille de l'utilisateur
|
||||
/// [userFirstName] Le prénom de l'utilisateur
|
||||
/// [email] L'adresse email de l'utilisateur
|
||||
/// [motDePasse] Le mot de passe (hashé côté serveur)
|
||||
/// [profileImageUrl] L'URL de l'image de profil
|
||||
/// [eventsCount] Le nombre d'événements créés (optionnel)
|
||||
/// [friendsCount] Le nombre d'amis (optionnel)
|
||||
/// [postsCount] Le nombre de posts (optionnel)
|
||||
/// [visitedPlacesCount] Le nombre de lieux visités (optionnel)
|
||||
const UserModel({
|
||||
required super.userId,
|
||||
required super.userLastName,
|
||||
required super.userFirstName,
|
||||
required super.email,
|
||||
required super.motDePasse,
|
||||
required super.profileImageUrl,
|
||||
super.eventsCount,
|
||||
super.friendsCount,
|
||||
super.postsCount,
|
||||
super.visitedPlacesCount,
|
||||
});
|
||||
|
||||
/// Factory pour créer un `UserModel` à partir d'un JSON reçu depuis l'API.
|
||||
/// Crée un [UserModel] à partir d'un JSON reçu depuis l'API.
|
||||
///
|
||||
/// [json] Les données JSON à parser
|
||||
///
|
||||
/// Returns un [UserModel] avec les données parsées
|
||||
///
|
||||
/// **Note:** Les valeurs par défaut sont utilisées si des champs sont manquants.
|
||||
///
|
||||
/// **Exemple:**
|
||||
/// ```dart
|
||||
/// final json = {
|
||||
/// 'userId': '123',
|
||||
/// 'nom': 'Doe',
|
||||
/// 'prenoms': 'John',
|
||||
/// 'email': 'john@example.com',
|
||||
/// };
|
||||
/// final user = UserModel.fromJson(json);
|
||||
/// ```
|
||||
factory UserModel.fromJson(Map<String, dynamic> json) {
|
||||
return UserModel(
|
||||
userId: json['userId'] ?? '',
|
||||
userLastName: json['nom'] ?? 'Inconnu',
|
||||
userFirstName: json['prenoms'] ?? 'Inconnu',
|
||||
email: json['email'] ?? 'inconnu@example.com',
|
||||
motDePasse: json['motDePasse'] ?? '',
|
||||
profileImageUrl: json['profileImageUrl'] ?? '',
|
||||
);
|
||||
try {
|
||||
// Le backend peut renvoyer 'uuid' ou 'userId', on accepte les deux
|
||||
final userId = _parseString(json, 'userId', '') != ''
|
||||
? _parseString(json, 'userId', '')
|
||||
: _parseString(json, 'uuid', '');
|
||||
|
||||
return UserModel(
|
||||
userId: userId.isNotEmpty ? userId : (json['uuid']?.toString() ?? json['userId']?.toString() ?? ''),
|
||||
userLastName: _parseString(json, 'nom', 'Inconnu'),
|
||||
userFirstName: _parseString(json, 'prenoms', 'Inconnu'),
|
||||
email: _parseString(json, 'email', ''),
|
||||
motDePasse: _parseString(json, 'motDePasse', ''),
|
||||
profileImageUrl: _parseString(json, 'profileImageUrl', ''),
|
||||
eventsCount: _parseInt(json, 'eventsCount') ?? 0,
|
||||
friendsCount: _parseInt(json, 'friendsCount') ?? 0,
|
||||
postsCount: _parseInt(json, 'postsCount') ?? 0,
|
||||
visitedPlacesCount: _parseInt(json, 'visitedPlacesCount') ?? 0,
|
||||
);
|
||||
} catch (e) {
|
||||
if (EnvConfig.enableDetailedLogs) {
|
||||
print('[UserModel] Erreur lors du parsing JSON: $e');
|
||||
}
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Convertit le `UserModel` en JSON pour l'envoi vers l'API.
|
||||
/// Parse une valeur string depuis le JSON avec valeur par défaut.
|
||||
static String _parseString(
|
||||
Map<String, dynamic> json,
|
||||
String key,
|
||||
String defaultValue,
|
||||
) {
|
||||
final value = json[key];
|
||||
if (value == null) return defaultValue;
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
/// Parse une valeur int depuis le JSON (optionnel).
|
||||
static int? _parseInt(Map<String, dynamic> json, String key) {
|
||||
final value = json[key];
|
||||
if (value == null) return null;
|
||||
if (value is int) return value;
|
||||
if (value is String) {
|
||||
return int.tryParse(value);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Convertit ce [UserModel] en JSON pour l'envoi vers l'API.
|
||||
///
|
||||
/// Returns une [Map] contenant les données de l'utilisateur
|
||||
///
|
||||
/// **Note:** Le mot de passe est envoyé en clair (hashé côté serveur).
|
||||
///
|
||||
/// **Exemple:**
|
||||
/// ```dart
|
||||
/// final user = UserModel(...);
|
||||
/// final json = user.toJson();
|
||||
/// // Envoyer json à l'API
|
||||
/// ```
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': userId,
|
||||
final json = <String, dynamic>{
|
||||
if (userId.isNotEmpty) 'id': userId,
|
||||
'nom': userLastName,
|
||||
'prenoms': userFirstName,
|
||||
'email': email,
|
||||
'motDePasse': motDePasse, // Mot de passe en clair (comme demandé temporairement)
|
||||
'profileImageUrl':profileImageUrl,
|
||||
if (motDePasse.isNotEmpty) 'motDePasse': motDePasse,
|
||||
if (profileImageUrl.isNotEmpty) 'profileImageUrl': profileImageUrl,
|
||||
};
|
||||
|
||||
// Ajouter les compteurs optionnels s'ils sont présents
|
||||
if (eventsCount != null) {
|
||||
json['eventsCount'] = eventsCount;
|
||||
}
|
||||
if (friendsCount != null) {
|
||||
json['friendsCount'] = friendsCount;
|
||||
}
|
||||
if (postsCount != null) {
|
||||
json['postsCount'] = postsCount;
|
||||
}
|
||||
if (visitedPlacesCount != null) {
|
||||
json['visitedPlacesCount'] = visitedPlacesCount;
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
/// Convertit ce modèle vers une entité de domaine [User].
|
||||
///
|
||||
/// Returns une instance de [User] avec les mêmes données
|
||||
///
|
||||
/// **Exemple:**
|
||||
/// ```dart
|
||||
/// final model = UserModel.fromJson(json);
|
||||
/// final entity = model.toEntity();
|
||||
/// ```
|
||||
User toEntity() {
|
||||
return User(
|
||||
userId: userId,
|
||||
userLastName: userLastName,
|
||||
userFirstName: userFirstName,
|
||||
email: email,
|
||||
motDePasse: motDePasse,
|
||||
profileImageUrl: profileImageUrl,
|
||||
eventsCount: eventsCount,
|
||||
friendsCount: friendsCount,
|
||||
postsCount: postsCount,
|
||||
visitedPlacesCount: visitedPlacesCount,
|
||||
);
|
||||
}
|
||||
|
||||
/// Crée une copie de ce [UserModel] avec des valeurs modifiées.
|
||||
///
|
||||
/// Tous les paramètres sont optionnels. Seuls les paramètres fournis
|
||||
/// seront modifiés dans la nouvelle instance.
|
||||
///
|
||||
/// **Exemple:**
|
||||
/// ```dart
|
||||
/// final updated = user.copyWith(
|
||||
/// userFirstName: 'Jane',
|
||||
/// profileImageUrl: 'https://example.com/new-image.jpg',
|
||||
/// );
|
||||
/// ```
|
||||
UserModel copyWith({
|
||||
String? userId,
|
||||
String? userLastName,
|
||||
String? userFirstName,
|
||||
String? email,
|
||||
String? motDePasse,
|
||||
String? profileImageUrl,
|
||||
int? eventsCount,
|
||||
int? friendsCount,
|
||||
int? postsCount,
|
||||
int? visitedPlacesCount,
|
||||
}) {
|
||||
return UserModel(
|
||||
userId: userId ?? this.userId,
|
||||
userLastName: userLastName ?? this.userLastName,
|
||||
userFirstName: userFirstName ?? this.userFirstName,
|
||||
email: email ?? this.email,
|
||||
motDePasse: motDePasse ?? this.motDePasse,
|
||||
profileImageUrl: profileImageUrl ?? this.profileImageUrl,
|
||||
eventsCount: eventsCount ?? this.eventsCount,
|
||||
friendsCount: friendsCount ?? this.friendsCount,
|
||||
postsCount: postsCount ?? this.postsCount,
|
||||
visitedPlacesCount: visitedPlacesCount ?? this.visitedPlacesCount,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'UserModel('
|
||||
'userId: $userId, '
|
||||
'name: $userFirstName $userLastName, '
|
||||
'email: $email'
|
||||
')';
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user