2026-03-07 22:33:09 +05:30
|
|
|
import 'dart:convert';
|
|
|
|
|
|
2026-02-24 03:28:13 +05:30
|
|
|
import 'package:dio/dio.dart';
|
|
|
|
|
import 'package:real_estate_mobile/core/constants/api_constants.dart';
|
|
|
|
|
import 'package:real_estate_mobile/core/network/api_client.dart';
|
|
|
|
|
import 'package:real_estate_mobile/core/network/api_exceptions.dart';
|
|
|
|
|
import 'package:real_estate_mobile/features/agents/data/models/agent_profile.dart';
|
|
|
|
|
import 'package:real_estate_mobile/features/agents/data/models/agent_type.dart';
|
2026-03-07 22:33:09 +05:30
|
|
|
import 'package:real_estate_mobile/features/agents/data/models/filterable_field.dart';
|
2026-02-24 03:28:13 +05:30
|
|
|
|
|
|
|
|
class SearchAgentsResponse {
|
|
|
|
|
final List<AgentProfile> data;
|
|
|
|
|
final int total;
|
|
|
|
|
final int page;
|
|
|
|
|
final int limit;
|
|
|
|
|
final int totalPages;
|
|
|
|
|
|
|
|
|
|
const SearchAgentsResponse({
|
|
|
|
|
required this.data,
|
|
|
|
|
required this.total,
|
|
|
|
|
required this.page,
|
|
|
|
|
required this.limit,
|
|
|
|
|
required this.totalPages,
|
|
|
|
|
});
|
|
|
|
|
|
2026-02-24 22:35:16 +05:30
|
|
|
/// Parses: { data: [...], meta: { total, page, limit, totalPages } }
|
2026-02-24 03:28:13 +05:30
|
|
|
factory SearchAgentsResponse.fromJson(Map<String, dynamic> json) {
|
2026-02-24 22:35:16 +05:30
|
|
|
final meta = json['meta'] as Map<String, dynamic>? ?? {};
|
2026-02-24 03:28:13 +05:30
|
|
|
return SearchAgentsResponse(
|
2026-02-24 22:35:16 +05:30
|
|
|
data: (json['data'] as List<dynamic>?)
|
|
|
|
|
?.map(
|
|
|
|
|
(e) => AgentProfile.fromJson(e as Map<String, dynamic>))
|
|
|
|
|
.toList() ??
|
|
|
|
|
[],
|
|
|
|
|
total: meta['total'] as int? ?? 0,
|
|
|
|
|
page: meta['page'] as int? ?? 1,
|
|
|
|
|
limit: meta['limit'] as int? ?? 10,
|
|
|
|
|
totalPages: meta['totalPages'] as int? ?? 1,
|
2026-02-24 03:28:13 +05:30
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
class AgentsRepository {
|
|
|
|
|
final Dio _dio = ApiClient.instance.dio;
|
|
|
|
|
|
2026-02-24 22:35:16 +05:30
|
|
|
/// Search agents: GET /agents
|
|
|
|
|
/// Response: { success, data: { data: [...], meta: {...} } }
|
2026-02-24 03:28:13 +05:30
|
|
|
Future<SearchAgentsResponse> searchAgents({
|
|
|
|
|
String? agentTypeId,
|
2026-03-07 10:25:53 +05:30
|
|
|
String? search,
|
2026-02-24 03:28:13 +05:30
|
|
|
int page = 1,
|
|
|
|
|
int limit = 10,
|
|
|
|
|
String? sortBy,
|
|
|
|
|
String? sortOrder,
|
2026-03-07 22:33:09 +05:30
|
|
|
Map<String, List<String>>? filters,
|
2026-02-24 03:28:13 +05:30
|
|
|
}) async {
|
|
|
|
|
try {
|
|
|
|
|
final queryParams = <String, dynamic>{
|
|
|
|
|
'page': page,
|
|
|
|
|
'limit': limit,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if (agentTypeId != null) queryParams['agentTypeId'] = agentTypeId;
|
2026-03-07 10:25:53 +05:30
|
|
|
if (search != null && search.isNotEmpty) queryParams['search'] = search;
|
2026-02-24 03:28:13 +05:30
|
|
|
if (sortBy != null) queryParams['sortBy'] = sortBy;
|
|
|
|
|
if (sortOrder != null) queryParams['sortOrder'] = sortOrder;
|
2026-03-07 22:33:09 +05:30
|
|
|
if (filters != null && filters.isNotEmpty) {
|
|
|
|
|
queryParams['filters'] = jsonEncode(filters);
|
|
|
|
|
}
|
2026-02-24 03:28:13 +05:30
|
|
|
|
|
|
|
|
final response = await _dio.get(
|
|
|
|
|
ApiConstants.agents,
|
|
|
|
|
queryParameters: queryParams,
|
|
|
|
|
);
|
|
|
|
|
|
2026-02-24 22:35:16 +05:30
|
|
|
// Backend wraps: { success: true, data: { data: [...], meta: {...} } }
|
|
|
|
|
final responseData = response.data;
|
|
|
|
|
final payload = responseData['data'] as Map<String, dynamic>;
|
|
|
|
|
return SearchAgentsResponse.fromJson(payload);
|
2026-02-24 03:28:13 +05:30
|
|
|
} on DioException catch (e) {
|
|
|
|
|
if (e.error is ApiException) {
|
|
|
|
|
throw e.error as ApiException;
|
|
|
|
|
}
|
|
|
|
|
throw ApiException(
|
|
|
|
|
message: e.message ?? 'Failed to fetch agents',
|
|
|
|
|
statusCode: e.response?.statusCode,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-07 22:33:09 +05:30
|
|
|
/// Get filterable profile fields: GET /profile-fields/filterable
|
|
|
|
|
/// Response: { success, data: [...] }
|
|
|
|
|
Future<List<FilterableField>> getFilterableFields() async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _dio.get(ApiConstants.filterableFields);
|
|
|
|
|
final data = response.data['data'] as List<dynamic>;
|
|
|
|
|
return data
|
|
|
|
|
.map((e) => FilterableField.fromJson(e as Map<String, dynamic>))
|
|
|
|
|
.toList();
|
|
|
|
|
} on DioException catch (e) {
|
|
|
|
|
if (e.error is ApiException) {
|
|
|
|
|
throw e.error as ApiException;
|
|
|
|
|
}
|
|
|
|
|
throw ApiException(
|
|
|
|
|
message: e.message ?? 'Failed to fetch filterable fields',
|
|
|
|
|
statusCode: e.response?.statusCode,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-08 00:41:44 +05:30
|
|
|
/// Get agent by ID: GET /agents/{id}
|
|
|
|
|
/// Response: { success, data: AgentProfile }
|
|
|
|
|
Future<AgentProfile> getAgentById(String id) async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _dio.get('${ApiConstants.agents}/$id');
|
|
|
|
|
final data = response.data['data'] as Map<String, dynamic>;
|
|
|
|
|
return AgentProfile.fromJson(data);
|
|
|
|
|
} on DioException catch (e) {
|
|
|
|
|
if (e.error is ApiException) throw e.error as ApiException;
|
|
|
|
|
throw ApiException(
|
|
|
|
|
message: e.message ?? 'Failed to fetch agent',
|
|
|
|
|
statusCode: e.response?.statusCode,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get field values for agent: GET /agents/{id}/field-values
|
|
|
|
|
/// Response: { success, data: { agentProfileId, fieldValues: [...] } }
|
|
|
|
|
Future<List<AgentFieldValue>> getFieldValues(String agentId) async {
|
|
|
|
|
try {
|
|
|
|
|
final response =
|
|
|
|
|
await _dio.get('${ApiConstants.agents}/$agentId/field-values');
|
|
|
|
|
final data = response.data['data'] as Map<String, dynamic>;
|
|
|
|
|
final fieldValues = data['fieldValues'] as List<dynamic>? ?? [];
|
|
|
|
|
return fieldValues
|
|
|
|
|
.map((e) => AgentFieldValue.fromFieldValueResponse(
|
|
|
|
|
e as Map<String, dynamic>))
|
|
|
|
|
.toList();
|
|
|
|
|
} on DioException catch (e) {
|
|
|
|
|
if (e.error is ApiException) throw e.error as ApiException;
|
|
|
|
|
throw ApiException(
|
|
|
|
|
message: e.message ?? 'Failed to fetch field values',
|
|
|
|
|
statusCode: e.response?.statusCode,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get testimonials for agent: GET /testimonials/agent/{agentProfileId}
|
|
|
|
|
Future<List<Map<String, dynamic>>> getTestimonials(String agentId,
|
|
|
|
|
{int limit = 10}) async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _dio.get(
|
|
|
|
|
'${ApiConstants.testimonials}/agent/$agentId',
|
|
|
|
|
queryParameters: {'limit': limit},
|
|
|
|
|
);
|
|
|
|
|
final data = response.data['data'] as List<dynamic>? ?? [];
|
|
|
|
|
return data.cast<Map<String, dynamic>>();
|
|
|
|
|
} on DioException catch (_) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Get connection status: GET /connection-requests/status/{agentProfileId}
|
|
|
|
|
Future<Map<String, dynamic>?> getConnectionStatus(String agentId) async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _dio
|
|
|
|
|
.get('${ApiConstants.connectionRequests}/status/$agentId');
|
|
|
|
|
return response.data['data'] as Map<String, dynamic>?;
|
|
|
|
|
} on DioException catch (_) {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Create connection request: POST /connection-requests
|
|
|
|
|
Future<bool> createConnectionRequest(String agentId,
|
|
|
|
|
{String? message}) async {
|
|
|
|
|
try {
|
|
|
|
|
await _dio.post(ApiConstants.connectionRequests, data: {
|
|
|
|
|
'agentProfileId': agentId,
|
|
|
|
|
if (message != null && message.isNotEmpty) 'message': message,
|
|
|
|
|
});
|
|
|
|
|
return true;
|
|
|
|
|
} on DioException catch (_) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Cancel connection request: DELETE /connection-requests/{requestId}
|
|
|
|
|
Future<bool> cancelConnectionRequest(String requestId) async {
|
|
|
|
|
try {
|
|
|
|
|
await _dio.delete('${ApiConstants.connectionRequests}/$requestId');
|
|
|
|
|
return true;
|
|
|
|
|
} on DioException catch (_) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-08 16:05:08 +05:30
|
|
|
/// Get received connection requests: GET /connection-requests/received?status=...
|
|
|
|
|
Future<List<Map<String, dynamic>>> getReceivedRequests(String status) async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _dio.get(
|
|
|
|
|
'${ApiConstants.connectionRequests}/received',
|
|
|
|
|
queryParameters: {'status': status},
|
|
|
|
|
);
|
|
|
|
|
final data = response.data['data'] as List<dynamic>? ?? [];
|
|
|
|
|
return data.cast<Map<String, dynamic>>();
|
|
|
|
|
} on DioException catch (_) {
|
|
|
|
|
return [];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Respond to connection request: PATCH /connection-requests/{id}/respond
|
|
|
|
|
Future<bool> respondToRequest(String requestId, String status) async {
|
|
|
|
|
try {
|
|
|
|
|
await _dio.patch(
|
|
|
|
|
'${ApiConstants.connectionRequests}/$requestId/respond',
|
|
|
|
|
data: {'status': status},
|
|
|
|
|
);
|
|
|
|
|
return true;
|
|
|
|
|
} on DioException catch (_) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-24 22:35:16 +05:30
|
|
|
/// Get agent types: GET /agent-types
|
|
|
|
|
/// Response: { success, data: [...] }
|
2026-02-24 03:28:13 +05:30
|
|
|
Future<List<AgentType>> getAgentTypes() async {
|
|
|
|
|
try {
|
|
|
|
|
final response = await _dio.get(ApiConstants.agentTypes);
|
2026-02-24 22:35:16 +05:30
|
|
|
|
|
|
|
|
// Backend wraps: { success: true, data: [...] }
|
2026-02-24 03:28:13 +05:30
|
|
|
final data = response.data['data'] as List<dynamic>;
|
|
|
|
|
return data
|
|
|
|
|
.map((e) => AgentType.fromJson(e as Map<String, dynamic>))
|
|
|
|
|
.toList();
|
|
|
|
|
} on DioException catch (e) {
|
|
|
|
|
if (e.error is ApiException) {
|
|
|
|
|
throw e.error as ApiException;
|
|
|
|
|
}
|
|
|
|
|
throw ApiException(
|
|
|
|
|
message: e.message ?? 'Failed to fetch agent types',
|
|
|
|
|
statusCode: e.response?.statusCode,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|