Files
mobile-app/lib/features/messaging/data/messaging_repository.dart

168 lines
5.7 KiB
Dart

import 'package:dio/dio.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:logger/logger.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/messaging/data/models/messaging_models.dart';
final _log = Logger(printer: PrettyPrinter(methodCount: 0));
class MessagingRepository {
final Dio _dio = ApiClient.instance.dio;
/// GET /messages/conversations
Future<List<Conversation>> getConversations() async {
try {
final response = await _dio.get(ApiConstants.conversations);
final data = response.data['data'] as List<dynamic>;
return data
.map((e) => Conversation.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 conversations',
statusCode: e.response?.statusCode,
);
} catch (e, stack) {
_log.e('Conversation parsing error', error: e, stackTrace: stack);
throw ApiException(message: 'Failed to parse conversations: $e');
}
}
/// POST /messages/conversations
Future<Conversation> startConversation(String agentProfileId) async {
try {
final response = await _dio.post(
ApiConstants.conversations,
data: {'agentProfileId': agentProfileId},
);
return Conversation.fromJson(
response.data['data'] as Map<String, dynamic>);
} on DioException catch (e) {
if (e.error is ApiException) throw e.error as ApiException;
throw ApiException(
message: e.message ?? 'Failed to start conversation',
statusCode: e.response?.statusCode,
);
}
}
/// POST /messages/conversations (agent → user)
Future<Conversation> startConversationWithUser(String userId) async {
try {
final response = await _dio.post(
ApiConstants.conversations,
data: {'userId': userId},
);
return Conversation.fromJson(
response.data['data'] as Map<String, dynamic>);
} on DioException catch (e) {
if (e.error is ApiException) throw e.error as ApiException;
throw ApiException(
message: e.message ?? 'Failed to start conversation',
statusCode: e.response?.statusCode,
);
}
}
/// GET /messages/conversations/:id
Future<Conversation> getConversation(String id) async {
try {
final response = await _dio.get('${ApiConstants.conversations}/$id');
return Conversation.fromJson(
response.data['data'] as Map<String, dynamic>);
} on DioException catch (e) {
if (e.error is ApiException) throw e.error as ApiException;
throw ApiException(
message: e.message ?? 'Failed to fetch conversation',
statusCode: e.response?.statusCode,
);
}
}
/// GET /messages/conversations/:id/messages?page=&limit=
Future<({List<ChatMessage> messages, PaginationInfo pagination})> getMessages(
String conversationId, {
int page = 1,
int limit = 50,
}) async {
try {
final response = await _dio.get(
'${ApiConstants.conversations}/$conversationId/messages',
queryParameters: {'page': page, 'limit': limit},
);
final data = response.data['data'] as Map<String, dynamic>;
final messages = (data['messages'] as List<dynamic>)
.map((e) => ChatMessage.fromJson(e as Map<String, dynamic>))
.toList();
final pagination = PaginationInfo.fromJson(
data['pagination'] as Map<String, dynamic>);
return (messages: messages, pagination: pagination);
} on DioException catch (e) {
if (e.error is ApiException) throw e.error as ApiException;
throw ApiException(
message: e.message ?? 'Failed to fetch messages',
statusCode: e.response?.statusCode,
);
}
}
/// POST /messages/conversations/:id/messages
Future<ChatMessage> sendMessage(
String conversationId, {
required String content,
MessageType type = MessageType.text,
}) async {
try {
final response = await _dio.post(
'${ApiConstants.conversations}/$conversationId/messages',
data: {
'content': content,
'messageType': type.toApiString(),
},
);
return ChatMessage.fromJson(
response.data['data'] as Map<String, dynamic>);
} on DioException catch (e) {
if (e.error is ApiException) throw e.error as ApiException;
throw ApiException(
message: e.message ?? 'Failed to send message',
statusCode: e.response?.statusCode,
);
}
}
/// PATCH /messages/conversations/:id/read
Future<void> markAsRead(String conversationId) async {
try {
await _dio.patch('${ApiConstants.conversations}/$conversationId/read');
} on DioException catch (e) {
if (e.error is ApiException) throw e.error as ApiException;
throw ApiException(
message: e.message ?? 'Failed to mark as read',
statusCode: e.response?.statusCode,
);
}
}
/// GET /messages/unread-count
Future<int> getUnreadCount() async {
try {
final response = await _dio.get(ApiConstants.unreadCount);
return response.data['data']['unreadCount'] as int? ?? 0;
} on DioException catch (e) {
if (e.error is ApiException) throw e.error as ApiException;
throw ApiException(
message: e.message ?? 'Failed to fetch unread count',
statusCode: e.response?.statusCode,
);
}
}
}
final messagingRepositoryProvider = Provider<MessagingRepository>((ref) {
return MessagingRepository();
});