import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import '../../../../core/config/api_endpoints.dart'; import '../../../../core/config/app_config.dart'; import '../models/auth_response.dart'; const _keyAccessToken = 'access_token'; const _keyRefreshToken = 'refresh_token'; final secureStorageProvider = Provider((ref) { return const FlutterSecureStorage(); }); final authStateProvider = StateNotifierProvider((ref) { return AuthNotifier(ref); }); final accessTokenProvider = FutureProvider((ref) async { final storage = ref.watch(secureStorageProvider); return storage.read(key: _keyAccessToken); }); class AuthState { final bool isAuthenticated; final bool isLoading; final String? error; final AuthUser? user; const AuthState({ this.isAuthenticated = false, this.isLoading = false, this.error, this.user, }); AuthState copyWith({ bool? isAuthenticated, bool? isLoading, String? error, AuthUser? user, }) { return AuthState( isAuthenticated: isAuthenticated ?? this.isAuthenticated, isLoading: isLoading ?? this.isLoading, error: error, user: user ?? this.user, ); } } class AuthNotifier extends StateNotifier { final Ref _ref; AuthNotifier(this._ref) : super(const AuthState()); Future login(String email, String password) async { state = state.copyWith(isLoading: true, error: null); try { final config = _ref.read(appConfigProvider); final dio = Dio(BaseOptions(baseUrl: config.apiBaseUrl)); final response = await dio.post( ApiEndpoints.login, data: {'email': email, 'password': password}, ); final authResponse = AuthResponse.fromJson(response.data as Map); final storage = _ref.read(secureStorageProvider); await storage.write(key: _keyAccessToken, value: authResponse.accessToken); await storage.write( key: _keyRefreshToken, value: authResponse.refreshToken); state = state.copyWith( isAuthenticated: true, isLoading: false, user: authResponse.user, ); _ref.invalidate(accessTokenProvider); return true; } on DioException catch (e) { final message = (e.response?.data is Map) ? e.response?.data['message'] : null; state = state.copyWith( isLoading: false, error: message?.toString() ?? 'Login failed', ); return false; } catch (e) { state = state.copyWith( isLoading: false, error: e.toString(), ); return false; } } Future logout() async { final storage = _ref.read(secureStorageProvider); await storage.delete(key: _keyAccessToken); await storage.delete(key: _keyRefreshToken); _ref.invalidate(accessTokenProvider); state = const AuthState(); } Future refreshToken() async { try { final storage = _ref.read(secureStorageProvider); final refreshToken = await storage.read(key: _keyRefreshToken); if (refreshToken == null) return false; final config = _ref.read(appConfigProvider); final dio = Dio(BaseOptions(baseUrl: config.apiBaseUrl)); final response = await dio.post( ApiEndpoints.refreshToken, data: {'refreshToken': refreshToken}, ); final data = response.data as Map; await storage.write( key: _keyAccessToken, value: data['accessToken'] as String); await storage.write( key: _keyRefreshToken, value: data['refreshToken'] as String); _ref.invalidate(accessTokenProvider); return true; } catch (_) { await logout(); return false; } } }