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

174 lines
5.0 KiB
Dart

import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:real_estate_mobile/features/agents/data/agents_repository.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';
import 'package:real_estate_mobile/features/agents/data/models/filterable_field.dart';
import 'package:real_estate_mobile/features/agents/presentation/providers/agents_provider.dart';
class SearchAgentsState {
final List<AgentProfile> agents;
final List<AgentType> agentTypes;
final List<FilterableField> filterFields;
final bool isLoading;
final bool isLoadingMore;
final String? error;
final String searchQuery;
final String? selectedAgentTypeId;
final int currentPage;
final int totalPages;
final Map<String, List<String>> activeFilters;
const SearchAgentsState({
this.agents = const [],
this.agentTypes = const [],
this.filterFields = const [],
this.isLoading = false,
this.isLoadingMore = false,
this.error,
this.searchQuery = '',
this.selectedAgentTypeId,
this.currentPage = 1,
this.totalPages = 1,
this.activeFilters = const {},
});
bool get hasMore => currentPage < totalPages;
SearchAgentsState copyWith({
List<AgentProfile>? agents,
List<AgentType>? agentTypes,
List<FilterableField>? filterFields,
bool? isLoading,
bool? isLoadingMore,
String? error,
String? searchQuery,
String? selectedAgentTypeId,
bool clearAgentTypeId = false,
int? currentPage,
int? totalPages,
Map<String, List<String>>? activeFilters,
}) {
return SearchAgentsState(
agents: agents ?? this.agents,
agentTypes: agentTypes ?? this.agentTypes,
filterFields: filterFields ?? this.filterFields,
isLoading: isLoading ?? this.isLoading,
isLoadingMore: isLoadingMore ?? this.isLoadingMore,
error: error,
searchQuery: searchQuery ?? this.searchQuery,
selectedAgentTypeId: clearAgentTypeId
? null
: (selectedAgentTypeId ?? this.selectedAgentTypeId),
currentPage: currentPage ?? this.currentPage,
totalPages: totalPages ?? this.totalPages,
activeFilters: activeFilters ?? this.activeFilters,
);
}
}
class SearchAgentsNotifier extends StateNotifier<SearchAgentsState> {
final AgentsRepository _repository;
SearchAgentsNotifier(this._repository)
: super(const SearchAgentsState(isLoading: true)) {
_init();
}
Future<void> _init() async {
try {
final results = await Future.wait([
_repository.getAgentTypes(),
_repository.getFilterableFields(),
]);
state = state.copyWith(
agentTypes: results[0] as List<AgentType>,
filterFields: results[1] as List<FilterableField>,
);
await _fetchAgents(page: 1);
} catch (e) {
state = state.copyWith(isLoading: false, error: e.toString());
}
}
Future<void> _fetchAgents({required int page, bool append = false}) async {
try {
final response = await _repository.searchAgents(
search: state.searchQuery.isNotEmpty ? state.searchQuery : null,
agentTypeId: state.selectedAgentTypeId,
page: page,
limit: 10,
filters: state.activeFilters.isNotEmpty ? state.activeFilters : null,
);
state = state.copyWith(
agents: append ? [...state.agents, ...response.data] : response.data,
currentPage: response.page,
totalPages: response.totalPages,
isLoading: false,
isLoadingMore: false,
);
} catch (e) {
state = state.copyWith(
isLoading: false,
isLoadingMore: false,
error: e.toString(),
);
}
}
void search(String query) {
state = state.copyWith(
searchQuery: query,
isLoading: true,
currentPage: 1,
);
_fetchAgents(page: 1);
}
void filterByAgentType(String? agentTypeId) {
state = state.copyWith(
selectedAgentTypeId: agentTypeId,
clearAgentTypeId: agentTypeId == null,
isLoading: true,
currentPage: 1,
);
_fetchAgents(page: 1);
}
void applyFilters(Map<String, List<String>> filters) {
state = state.copyWith(
activeFilters: filters,
isLoading: true,
currentPage: 1,
);
_fetchAgents(page: 1);
}
void clearFilters() {
state = state.copyWith(
activeFilters: const {},
isLoading: true,
currentPage: 1,
);
_fetchAgents(page: 1);
}
void loadMore() {
if (state.isLoadingMore || !state.hasMore) return;
state = state.copyWith(isLoadingMore: true);
_fetchAgents(page: state.currentPage + 1, append: true);
}
Future<void> refresh() async {
state = state.copyWith(isLoading: true, currentPage: 1);
await _fetchAgents(page: 1);
}
}
final searchAgentsProvider =
StateNotifierProvider.autoDispose<SearchAgentsNotifier, SearchAgentsState>(
(ref) {
final repository = ref.watch(agentsRepositoryProvider);
return SearchAgentsNotifier(repository);
});