Files
mobile-app/lib/features/agents/presentation/providers/agent_network_provider.dart

140 lines
4.0 KiB
Dart

import 'dart:async';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:real_estate_mobile/features/agents/data/agents_repository.dart';
import 'package:real_estate_mobile/features/messaging/data/socket_service.dart';
class AgentNetworkState {
final List<Map<String, dynamic>> pendingRequests;
final List<Map<String, dynamic>> connections;
final bool isLoading;
final String? error;
final Set<String> processingIds;
const AgentNetworkState({
this.pendingRequests = const [],
this.connections = const [],
this.isLoading = true,
this.error,
this.processingIds = const {},
});
AgentNetworkState copyWith({
List<Map<String, dynamic>>? pendingRequests,
List<Map<String, dynamic>>? connections,
bool? isLoading,
String? error,
Set<String>? processingIds,
bool clearError = false,
}) {
return AgentNetworkState(
pendingRequests: pendingRequests ?? this.pendingRequests,
connections: connections ?? this.connections,
isLoading: isLoading ?? this.isLoading,
error: clearError ? null : (error ?? this.error),
processingIds: processingIds ?? this.processingIds,
);
}
}
class AgentNetworkNotifier extends StateNotifier<AgentNetworkState> {
final AgentsRepository _repo;
StreamSubscription? _connectionRequestSub;
AgentNetworkNotifier(this._repo) : super(const AgentNetworkState()) {
loadData();
// Listen for real-time connection request events
_connectionRequestSub =
SocketService().onConnectionRequest.listen((_) {
if (mounted) loadData();
});
}
@override
void dispose() {
_connectionRequestSub?.cancel();
super.dispose();
}
Future<void> loadData() async {
state = state.copyWith(isLoading: true, clearError: true);
try {
final results = await Future.wait([
_repo.getReceivedRequests('PENDING'),
_repo.getReceivedRequests('ACCEPTED'),
]);
state = state.copyWith(
pendingRequests: results[0],
connections: results[1],
isLoading: false,
);
} catch (e) {
state = state.copyWith(
isLoading: false,
error: 'Failed to load network data',
);
}
}
Future<void> acceptRequest(String requestId) async {
if (state.processingIds.contains(requestId)) return;
state = state.copyWith(
processingIds: {...state.processingIds, requestId},
);
final success = await _repo.respondToRequest(requestId, 'ACCEPTED');
if (success) {
// Move from pending to connections
final request = state.pendingRequests.firstWhere(
(r) => r['id'] == requestId,
orElse: () => <String, dynamic>{},
);
state = state.copyWith(
pendingRequests:
state.pendingRequests.where((r) => r['id'] != requestId).toList(),
connections: request.isNotEmpty
? [request, ...state.connections]
: state.connections,
processingIds: state.processingIds
.where((id) => id != requestId)
.toSet(),
);
} else {
state = state.copyWith(
processingIds: state.processingIds
.where((id) => id != requestId)
.toSet(),
);
}
}
Future<void> rejectRequest(String requestId) async {
if (state.processingIds.contains(requestId)) return;
state = state.copyWith(
processingIds: {...state.processingIds, requestId},
);
final success = await _repo.respondToRequest(requestId, 'REJECTED');
if (success) {
state = state.copyWith(
pendingRequests:
state.pendingRequests.where((r) => r['id'] != requestId).toList(),
processingIds: state.processingIds
.where((id) => id != requestId)
.toSet(),
);
} else {
state = state.copyWith(
processingIds: state.processingIds
.where((id) => id != requestId)
.toSet(),
);
}
}
}
final agentNetworkProvider =
StateNotifierProvider.autoDispose<AgentNetworkNotifier, AgentNetworkState>(
(ref) => AgentNetworkNotifier(AgentsRepository()),
);