Initial commit: unionflow-mobile-apps
Application Flutter complète (sans build artifacts). Signed-off-by: lions dev Team
This commit is contained in:
146
lib/features/explore/data/repositories/network_repository.dart
Normal file
146
lib/features/explore/data/repositories/network_repository.dart
Normal file
@@ -0,0 +1,146 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
|
||||
import 'package:unionflow_mobile_apps/core/network/api_client.dart';
|
||||
import 'package:unionflow_mobile_apps/core/utils/logger.dart';
|
||||
import '../../domain/entities/network_item.dart';
|
||||
|
||||
/// Repository pour la recherche réseau (membres + organisations).
|
||||
/// Délègue la recherche au backend Quarkus.
|
||||
@lazySingleton
|
||||
class NetworkRepository {
|
||||
final ApiClient _apiClient;
|
||||
|
||||
NetworkRepository(this._apiClient);
|
||||
|
||||
List<dynamic> _parseListResponse(dynamic data) {
|
||||
if (data is List) return data;
|
||||
if (data is Map && data.containsKey('content')) {
|
||||
final content = data['content'];
|
||||
return content is List ? content : [];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
/// Recherche de membres (GET /api/membres/recherche?q=...)
|
||||
Future<List<NetworkItem>> searchMembers(String query, {int page = 0, int size = 20}) async {
|
||||
if (query.trim().isEmpty) return [];
|
||||
try {
|
||||
final response = await _apiClient.get(
|
||||
'/api/membres/recherche',
|
||||
queryParameters: {'q': query.trim(), 'page': page, 'size': size},
|
||||
);
|
||||
final data = _parseListResponse(response.data);
|
||||
return data.map((json) => _memberFromJson(json as Map<String, dynamic>)).toList();
|
||||
} on DioException catch (e) {
|
||||
if (e.response?.statusCode == 400) return [];
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Recherche d'organisations (GET /api/organisations/recherche?nom=...)
|
||||
Future<List<NetworkItem>> searchOrganizations(String query, {int page = 0, int size = 20}) async {
|
||||
if (query.trim().isEmpty) return [];
|
||||
try {
|
||||
final response = await _apiClient.get(
|
||||
'/api/organisations/recherche',
|
||||
queryParameters: {'nom': query.trim(), 'page': page, 'size': size},
|
||||
);
|
||||
final data = _parseListResponse(response.data);
|
||||
return data.map((json) => _organisationFromJson(json as Map<String, dynamic>)).toList();
|
||||
} on DioException catch (e) {
|
||||
if (e.response?.statusCode == 400) return [];
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Recherche globale : membres + organisations (deux appels parallèles).
|
||||
/// Si [followedIds] est fourni, les membres dont l'id est dans le set auront [isConnected: true].
|
||||
Future<List<NetworkItem>> search(String query, {int page = 0, int size = 10, Set<String>? followedIds}) async {
|
||||
if (query.trim().isEmpty) return [];
|
||||
try {
|
||||
final results = await Future.wait([
|
||||
searchMembers(query, page: page, size: size),
|
||||
searchOrganizations(query, page: page, size: size),
|
||||
]);
|
||||
final members = results[0].map((m) {
|
||||
if (followedIds != null && followedIds.contains(m.id)) return m.copyWith(isConnected: true);
|
||||
return m;
|
||||
}).toList();
|
||||
final orgs = results[1];
|
||||
return [...members, ...orgs];
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Liste des ids des membres suivis par l'utilisateur connecté (GET /api/membres/me/suivis).
|
||||
Future<List<String>> getFollowedIds() async {
|
||||
try {
|
||||
final response = await _apiClient.get('/api/membres/me/suivis');
|
||||
if (response.statusCode != 200) return [];
|
||||
final data = response.data;
|
||||
if (data is! List) return [];
|
||||
return data.map((e) => e.toString()).toList();
|
||||
} on DioException catch (e) {
|
||||
if (e.response?.statusCode == 401 || e.response?.statusCode == 403) return [];
|
||||
AppLogger.error('NetworkRepository: getFollowedIds échoué', error: e);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Suivre un membre (POST /api/membres/{id}/suivre). Retourne true si following après l'appel.
|
||||
Future<bool> follow(String memberId) async {
|
||||
try {
|
||||
final response = await _apiClient.post('/api/membres/$memberId/suivre');
|
||||
if (response.statusCode == 200 && response.data is Map) {
|
||||
return (response.data as Map)['following'] == true;
|
||||
}
|
||||
return false;
|
||||
} on DioException catch (e, st) {
|
||||
AppLogger.error('NetworkRepository: follow échoué', error: e, stackTrace: st);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
/// Ne plus suivre un membre (DELETE /api/membres/{id}/suivre). Retourne false (plus suivi).
|
||||
Future<bool> unfollow(String memberId) async {
|
||||
try {
|
||||
final response = await _apiClient.delete('/api/membres/$memberId/suivre');
|
||||
if (response.statusCode == 200 && response.data is Map) {
|
||||
return (response.data as Map)['following'] == true;
|
||||
}
|
||||
return false;
|
||||
} on DioException catch (e, st) {
|
||||
AppLogger.error('NetworkRepository: unfollow échoué', error: e, stackTrace: st);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
static NetworkItem _memberFromJson(Map<String, dynamic> json) {
|
||||
final id = json['id']?.toString() ?? '';
|
||||
final prenom = json['prenom']?.toString() ?? '';
|
||||
final nom = json['nom']?.toString() ?? '';
|
||||
final name = '$prenom $nom'.trim().isEmpty ? (json['numeroMembre']?.toString() ?? id) : '$prenom $nom'.trim();
|
||||
return NetworkItem(
|
||||
id: id,
|
||||
name: name,
|
||||
subtitle: json['profession']?.toString() ?? json['statutCompteLibelle']?.toString(),
|
||||
avatarUrl: null,
|
||||
type: 'Member',
|
||||
isConnected: false,
|
||||
);
|
||||
}
|
||||
|
||||
static NetworkItem _organisationFromJson(Map<String, dynamic> json) {
|
||||
final id = json['id']?.toString() ?? '';
|
||||
return NetworkItem(
|
||||
id: id,
|
||||
name: json['nom']?.toString() ?? json['nomCourt']?.toString() ?? 'Organisation',
|
||||
subtitle: json['typeOrganisationLibelle']?.toString() ?? json['statutLibelle']?.toString(),
|
||||
avatarUrl: null,
|
||||
type: 'Organization',
|
||||
isConnected: false,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user