import 'package:dio/dio.dart'; import 'package:real_estate_mobile/config/app_config.dart'; import 'package:real_estate_mobile/core/network/api_exceptions.dart'; import 'package:real_estate_mobile/core/storage/secure_storage.dart'; class ApiClient { static ApiClient? _instance; late final Dio _dio; ApiClient._() { _dio = Dio( BaseOptions( baseUrl: AppConfig.apiBaseUrl, connectTimeout: const Duration(seconds: 30), receiveTimeout: const Duration(seconds: 30), headers: { 'Content-Type': 'application/json', 'Accept': 'application/json', }, ), ); _dio.interceptors.addAll([ _authInterceptor(), _errorInterceptor(), ]); } static ApiClient get instance { _instance ??= ApiClient._(); return _instance!; } Dio get dio => _dio; InterceptorsWrapper _authInterceptor() { return InterceptorsWrapper( onRequest: (options, handler) async { final token = await SecureStorage.getAccessToken(); if (token != null) { options.headers['Authorization'] = 'Bearer $token'; } handler.next(options); }, ); } InterceptorsWrapper _errorInterceptor() { return InterceptorsWrapper( onError: (error, handler) { final response = error.response; if (response != null) { final data = response.data; if (data is Map) { final message = data['message'] is List ? (data['message'] as List).join(', ') : data['message']?.toString() ?? 'An error occurred'; final errors = (data['errors'] as List?) ?.map((e) => FieldError.fromJson(e as Map)) .toList() ?? []; handler.reject( DioException( requestOptions: error.requestOptions, response: error.response, error: ApiException( message: message, statusCode: response.statusCode, fieldErrors: errors, ), ), ); return; } } handler.reject( DioException( requestOptions: error.requestOptions, response: error.response, error: ApiException( message: error.message ?? 'Network error occurred', statusCode: response?.statusCode, ), ), ); }, ); } }