/// API Service - Main HTTP client using Dio library; import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:pretty_dio_logger/pretty_dio_logger.dart'; import '../../../core/constants/api_constants.dart'; import '../../providers/auth_provider.dart'; /// API Service provider final apiServiceProvider = Provider((ref) { final authState = ref.watch(authProvider); final token = authState?.accessToken; final options = BaseOptions( baseUrl: ApiConstants.baseUrl, connectTimeout: const Duration(milliseconds: ApiConstants.connectionTimeoutMs), receiveTimeout: const Duration(milliseconds: ApiConstants.receiveTimeoutMs), sendTimeout: const Duration(milliseconds: ApiConstants.sendTimeoutMs), headers: { 'Content-Type': 'application/json', if (token != null) 'Authorization': 'Bearer $token', }, ); final dio = Dio(options); // Add logger in debug mode dio.interceptors.add( PrettyDioLogger( requestHeader: true, requestBody: true, responseBody: true, responseHeader: false, error: true, compact: true, ), ); // Add token refresh interceptor dio.interceptors.add( InterceptorsWrapper( onError: (error, handler) async { if (error.response?.statusCode == 401) { // Try to refresh token try { final newToken = await ref.read(authProvider.notifier).refreshToken(); if (newToken != null) { // Retry original request with new token final opts = options.copyWith( headers: { ...options.headers, 'Authorization': 'Bearer $newToken', }, ); final clonedReq = await dio.fetch(opts..path = error.requestOptions.path); return handler.resolve(clonedReq); } } catch (e) { // Refresh failed, logout user ref.read(authProvider.notifier).logout(); } } return handler.next(error); }, ), ); return dio; }); /// Get API client Dio getDio(Ref ref) { return ref.read(apiServiceProvider); }