/// Auth API Service library; import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../core/constants/api_constants.dart'; import '../../../domain/entities/user.dart'; import 'api_service.dart'; /// Auth API response models class LoginResponse { final String accessToken; final String refreshToken; final int expiresIn; final User user; LoginResponse({ required this.accessToken, required this.refreshToken, required this.expiresIn, required this.user, }); factory LoginResponse.fromJson(Map json) { return LoginResponse( accessToken: json['access_token'] as String, refreshToken: json['refresh_token'] as String, expiresIn: json['expires_in'] as int, user: User.fromJson(json['user'] as Map), ); } } /// Extension on User for JSON serialization extension UserJson on User { static User fromJson(Map json) { return User( id: json['id'] as String, email: json['email'] as String, username: json['username'] as String, displayName: json['display_name'] as String?, avatarUrl: json['avatar_url'] as String?, isPremium: json['is_premium'] as bool? ?? false, createdAt: DateTime.parse(json['created_at'] as String), updatedAt: DateTime.parse(json['updated_at'] as String), ); } Map toJson() { return { 'id': id, 'email': email, 'username': username, if (displayName != null) 'display_name': displayName, if (avatarUrl != null) 'avatar_url': avatarUrl, 'is_premium': isPremium, 'created_at': createdAt.toIso8601String(), 'updated_at': updatedAt.toIso8601String(), }; } } /// Auth API Service class AuthApiService { AuthApiService(this._dio); final Dio _dio; /// Login with email and password Future login(String email, String password) async { try { final response = await _dio.post( ApiConstants.login, data: { 'email': email, 'password': password, }, ); return LoginResponse.fromJson(response.data); } on DioException catch (e) { throw _handleDioError(e); } } /// Register a new user Future register({ required String email, required String username, required String password, String? displayName, }) async { try { final response = await _dio.post( ApiConstants.register, data: { 'email': email, 'username': username, 'password': password, if (displayName != null) 'display_name': displayName, }, ); return LoginResponse.fromJson(response.data); } on DioException catch (e) { throw _handleDioError(e); } } /// Refresh access token Future> refreshToken(String refreshToken) async { try { final response = await _dio.post( ApiConstants.refresh, data: {'refresh_token': refreshToken}, ); return response.data; } on DioException catch (e) { throw _handleDioError(e); } } /// Get current user profile Future getCurrentUser() async { try { final response = await _dio.get(ApiConstants.me); return UserJson.fromJson(response.data); } on DioException catch (e) { throw _handleDioError(e); } } /// Update user profile Future updateProfile({ String? displayName, String? avatarUrl, }) async { try { final response = await _dio.put( ApiConstants.me, data: { if (displayName != null) 'display_name': displayName, if (avatarUrl != null) 'avatar_url': avatarUrl, }, ); return UserJson.fromJson(response.data); } on DioException catch (e) { throw _handleDioError(e); } } /// Logout Future logout() async { try { await _dio.post(ApiConstants.logout); } on DioException catch (e) { throw _handleDioError(e); } } Exception _handleDioError(DioException error) { if (error.response != null) { final statusCode = error.response!.statusCode; final message = error.response!.data['detail'] as String? ?? 'An error occurred'; return Exception('$statusCode: $message'); } else if (error.type == DioExceptionType.connectionTimeout) { return const Exception('Connection timeout'); } else if (error.type == DioExceptionType.receiveTimeout) { return const Exception('Receive timeout'); } else { return Exception('Network error: ${error.message}'); } } } /// Provider for Auth API Service final authApiServiceProvider = Provider((ref) { final dio = ref.watch(apiServiceProvider); return AuthApiService(dio); });