feat: Implement agent filtering by integrating a new API endpoint for filterable fields, introducing filter data models, and adding a dedicated filter sheet UI, alongside an updated profile icon.
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
import 'dart:convert';
|
||||
|
||||
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';
|
||||
import 'package:real_estate_mobile/features/agents/data/models/filterable_field.dart';
|
||||
|
||||
class SearchAgentsResponse {
|
||||
final List<AgentProfile> data;
|
||||
@@ -49,6 +52,7 @@ class AgentsRepository {
|
||||
int limit = 10,
|
||||
String? sortBy,
|
||||
String? sortOrder,
|
||||
Map<String, List<String>>? filters,
|
||||
}) async {
|
||||
try {
|
||||
final queryParams = <String, dynamic>{
|
||||
@@ -60,6 +64,9 @@ class AgentsRepository {
|
||||
if (search != null && search.isNotEmpty) queryParams['search'] = search;
|
||||
if (sortBy != null) queryParams['sortBy'] = sortBy;
|
||||
if (sortOrder != null) queryParams['sortOrder'] = sortOrder;
|
||||
if (filters != null && filters.isNotEmpty) {
|
||||
queryParams['filters'] = jsonEncode(filters);
|
||||
}
|
||||
|
||||
final response = await _dio.get(
|
||||
ApiConstants.agents,
|
||||
@@ -81,6 +88,26 @@ class AgentsRepository {
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get agent types: GET /agent-types
|
||||
/// Response: { success, data: [...] }
|
||||
Future<List<AgentType>> getAgentTypes() async {
|
||||
|
||||
39
lib/features/agents/data/models/filterable_field.dart
Normal file
39
lib/features/agents/data/models/filterable_field.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
class FilterOption {
|
||||
final String value;
|
||||
final String label;
|
||||
|
||||
const FilterOption({required this.value, required this.label});
|
||||
|
||||
factory FilterOption.fromJson(Map<String, dynamic> json) {
|
||||
return FilterOption(
|
||||
value: json['value'] as String? ?? '',
|
||||
label: json['label'] as String? ?? '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FilterableField {
|
||||
final String slug;
|
||||
final String name;
|
||||
final String fieldType;
|
||||
final List<FilterOption> options;
|
||||
|
||||
const FilterableField({
|
||||
required this.slug,
|
||||
required this.name,
|
||||
required this.fieldType,
|
||||
this.options = const [],
|
||||
});
|
||||
|
||||
factory FilterableField.fromJson(Map<String, dynamic> json) {
|
||||
return FilterableField(
|
||||
slug: json['slug'] as String? ?? '',
|
||||
name: json['name'] as String? ?? '',
|
||||
fieldType: json['fieldType'] as String? ?? '',
|
||||
options: (json['options'] as List<dynamic>?)
|
||||
?.map((e) => FilterOption.fromJson(e as Map<String, dynamic>))
|
||||
.toList() ??
|
||||
const [],
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user