This commit is contained in:
Phuoc Nguyen
2025-10-10 18:06:40 +07:00
parent 77440ac957
commit 63e397d7e6
12 changed files with 1060 additions and 16 deletions

View File

@@ -89,21 +89,31 @@ class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
@override
Future<UserModel> getProfile() async {
try {
print('📡 DataSource: Calling getProfile API...');
final response = await dioClient.get(ApiConstants.profile);
print('📡 DataSource: Profile status=${response.statusCode}');
print('📡 DataSource: Profile response keys=${response.data?.keys?.toList()}');
print('📡 DataSource: Profile response=$response.data}');
if (response.statusCode == ApiConstants.statusOk) {
// API might return nested structure: {success, data: user, message}
// Check if response has 'data' key
final userData = response.data['data'] != null
? response.data['data'] as Map<String, dynamic>
: response.data as Map<String, dynamic>;
return UserModel.fromJson(userData);
// API returns nested structure: {success, data: user, message}
// Extract the 'data' object
final userData = response.data['data'] as Map<String, dynamic>;
print('📡 DataSource: Extracted user data with keys=${userData.keys.toList()}');
final userModel = UserModel.fromJson(userData);
print('📡 DataSource: User parsed successfully: ${userModel.name}');
return userModel;
} else {
throw ServerException('Get profile failed with status: ${response.statusCode}');
}
} on DioException catch (e) {
print('❌ DataSource: Profile DioException - ${e.message}');
throw _handleDioError(e);
} catch (e) {
} catch (e, stackTrace) {
print('❌ DataSource: Profile unexpected error - $e');
print('Stack trace: $stackTrace');
throw ServerException('Unexpected error getting profile: $e');
}
}

View File

@@ -14,7 +14,11 @@ class UserModel extends User {
/// Create UserModel from JSON
factory UserModel.fromJson(Map<String, dynamic> json) {
final createdAt = DateTime.parse(json['createdAt'] as String);
// createdAt might not be in response, default to now
final createdAt = json['createdAt'] != null
? DateTime.parse(json['createdAt'] as String)
: DateTime.now();
return UserModel(
id: json['id'] as String,
name: json['name'] as String,

View File

@@ -26,19 +26,24 @@ class AuthRepositoryImpl implements AuthRepository {
Future<Either<Failure, AuthResponse>> login({
required String email,
required String password,
bool rememberMe = false,
}) async {
try {
print('🔐 Repository: Starting login...');
print('🔐 Repository: Starting login (rememberMe: $rememberMe)...');
final loginDto = LoginDto(email: email, password: password);
final authResponse = await remoteDataSource.login(loginDto);
print('🔐 Repository: Got response, token length=${authResponse.accessToken.length}');
// Save token to secure storage
await secureStorage.saveAccessToken(authResponse.accessToken);
print('🔐 Repository: Token saved to secure storage');
// Save token to secure storage only if rememberMe is true
if (rememberMe) {
await secureStorage.saveAccessToken(authResponse.accessToken);
print('🔐 Repository: Token saved to secure storage (persistent)');
} else {
print('🔐 Repository: Token NOT saved (session only - rememberMe is false)');
}
// Set token in Dio client for subsequent requests
// Set token in Dio client for subsequent requests (always for current session)
dioClient.setAuthToken(authResponse.accessToken);
print('🔐 Repository: Token set in DioClient');
@@ -162,16 +167,25 @@ class AuthRepositoryImpl implements AuthRepository {
@override
Future<bool> isAuthenticated() async {
try {
print('🔍 Checking authentication...');
final hasToken = await secureStorage.hasAccessToken();
print('🔍 Has token in storage: $hasToken');
if (hasToken) {
final token = await secureStorage.getAccessToken();
print('🔍 Token retrieved, length: ${token?.length ?? 0}');
if (token != null) {
dioClient.setAuthToken(token);
print('✅ Token loaded from storage and set in DioClient');
return true;
}
}
print('❌ No token found in storage');
return false;
} catch (e) {
print('❌ Error checking authentication: $e');
return false;
}
}

View File

@@ -9,6 +9,7 @@ abstract class AuthRepository {
Future<Either<Failure, AuthResponse>> login({
required String email,
required String password,
bool rememberMe = false,
});
/// Register new user

View File

@@ -39,6 +39,7 @@ class _LoginPageState extends ConsumerState<LoginPage> {
final success = await ref.read(authProvider.notifier).login(
email: _emailController.text.trim(),
password: _passwordController.text,
rememberMe: _rememberMe,
);
if (!mounted) return;

View File

@@ -86,29 +86,36 @@ class Auth extends _$Auth {
/// Initialize auth state - call this on app start
Future<void> initialize() async {
print('🚀 Initializing auth state...');
state = state.copyWith(isLoading: true);
final isAuthenticated = await _repository.isAuthenticated();
print('🚀 isAuthenticated result: $isAuthenticated');
if (isAuthenticated) {
print('🚀 Token found, fetching user profile...');
// Get user profile
final result = await _repository.getProfile();
result.fold(
(failure) {
print('❌ Failed to get profile: ${failure.message}');
state = const AuthState(
isAuthenticated: false,
isLoading: false,
);
},
(user) {
print('✅ Profile loaded: ${user.name}');
state = AuthState(
user: user,
isAuthenticated: true,
isLoading: false,
);
print('✅ Initialize complete: isAuthenticated=${state.isAuthenticated}');
},
);
} else {
print('❌ No token found, user needs to login');
state = const AuthState(
isAuthenticated: false,
isLoading: false,
@@ -120,10 +127,15 @@ class Auth extends _$Auth {
Future<bool> login({
required String email,
required String password,
bool rememberMe = false,
}) async {
state = state.copyWith(isLoading: true, clearError: true);
final result = await _repository.login(email: email, password: password);
final result = await _repository.login(
email: email,
password: password,
rememberMe: rememberMe,
);
return result.fold(
(failure) {