From 64b0b39deb2a66410ca730c493771563b6664405 Mon Sep 17 00:00:00 2001 From: Naresh Pratista <2141720057@student.polinema.ac.id> Date: Wed, 13 Nov 2024 14:21:56 +0700 Subject: [PATCH] Updated theme colors, added error code handling in user provider, and modified signin and signup screens to handle specific errors and timeouts. --- lib/core/utils/styles/theme.dart | 6 +- lib/features/auth/provider/user_provider.dart | 10 +++ .../auth/screens/signin/signin_screen.dart | 22 ++++-- .../auth/screens/signup/signup_screen.dart | 73 ++++++++++++++----- 4 files changed, 85 insertions(+), 26 deletions(-) diff --git a/lib/core/utils/styles/theme.dart b/lib/core/utils/styles/theme.dart index 48ffd70..87eb27e 100644 --- a/lib/core/utils/styles/theme.dart +++ b/lib/core/utils/styles/theme.dart @@ -83,9 +83,9 @@ class AppTextStyles { ThemeData appTheme() { return ThemeData( textSelectionTheme: const TextSelectionThemeData( - cursorColor: AppColors.primaryColor, - selectionColor: AppColors.primaryColor, - selectionHandleColor: AppColors.primaryColor, + cursorColor: AppColors.blackColor, + selectionColor: AppColors.blueColor, + selectionHandleColor: AppColors.blueColor, ), textTheme: GoogleFonts.interTextTheme(), fontFamily: GoogleFonts.inter().fontFamily, diff --git a/lib/features/auth/provider/user_provider.dart b/lib/features/auth/provider/user_provider.dart index 8c23d52..2b22b5d 100644 --- a/lib/features/auth/provider/user_provider.dart +++ b/lib/features/auth/provider/user_provider.dart @@ -10,12 +10,14 @@ class UserProvider with ChangeNotifier { Map? _userData; File? _selectedImage; bool _isLoading = false; + int? _errorCode; bool get isLoading => _isLoading; bool get isLoggedIn => _isLoggedIn; String? get jwtToken => _jwtToken; Map? get userData => _userData; File? get selectedImage => _selectedImage; + int? get errorCode => _errorCode; UserProvider() { _loadLoginStatus(); @@ -68,12 +70,15 @@ class UserProvider with ChangeNotifier { Future login({required String email, required String password}) async { setLoading(true); + _errorCode = null; try { final response = await _userRepository.loginUser({ 'EMAIL': email, 'PASSWORD': password, }); + _errorCode = response.statusCode; + if (response.statusCode == 200 && response.data['payload']['TOKEN'] != null) { String token = response.data['payload']['TOKEN']; @@ -87,7 +92,12 @@ class UserProvider with ChangeNotifier { _isLoggedIn = true; await refreshUserData(); return true; + } else if (response.statusCode == 403) { + // Khusus untuk error 403 (user belum divalidasi) + print('User is not validated: ${response.data['message']}'); + return false; } + return false; } catch (e) { print('Login error: $e'); diff --git a/lib/features/auth/screens/signin/signin_screen.dart b/lib/features/auth/screens/signin/signin_screen.dart index 3a2e94a..73ee33a 100644 --- a/lib/features/auth/screens/signin/signin_screen.dart +++ b/lib/features/auth/screens/signin/signin_screen.dart @@ -170,12 +170,22 @@ class SigninScreen extends StatelessWidget { _passwordController.clear(); }); } else { - CustomSnackBar.show( - context, - message: - 'Login failed, please check your credentials', - isError: true, - ); + // Handle specific error for unverified user + if (userProvider.errorCode == 403) { + CustomSnackBar.show( + context, + message: + 'User is not validated! Please verify your email first.', + isError: true, + ); + } else { + CustomSnackBar.show( + context, + message: + 'Login failed, please check your credentials', + isError: true, + ); + } } } }, diff --git a/lib/features/auth/screens/signup/signup_screen.dart b/lib/features/auth/screens/signup/signup_screen.dart index d22b4f5..b279efa 100644 --- a/lib/features/auth/screens/signup/signup_screen.dart +++ b/lib/features/auth/screens/signup/signup_screen.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:english_learning/core/widgets/custom_snackbar.dart'; import 'package:english_learning/features/auth/provider/user_provider.dart'; import 'package:english_learning/features/auth/provider/validator_provider.dart'; @@ -38,46 +40,83 @@ class _SignupScreenState extends State { BuildContext context, ValidatorProvider validatorProvider, ) async { + if (isLoading) return; // Prevent multiple submissions + setState(() { isLoading = true; }); + try { - // Attempt registration first - final isSuccess = await userProvider.register( + // Attempt registration with timeout + final isSuccess = await userProvider + .register( name: _nameController.text, email: _emailController.text, nisn: _nisnController.text, password: _passwordController.text, confirmPassword: _passwordController.text, + ) + .timeout( + const Duration(seconds: 30), + onTimeout: () { + throw TimeoutException( + 'Registration request timed out. Please try again.'); + }, ); + // Remove loading dialog + Navigator.of(context).pop(); + if (isSuccess) { - // Show verification dialog - showDialog( + // Show success verification dialog + if (!context.mounted) return; + await showDialog( context: context, barrierDismissible: false, - builder: (BuildContext context) { - return SignupVerification( - onSubmit: () { - // Navigate to sign in screen - Navigator.pushReplacement( - context, - MaterialPageRoute( - builder: (context) => SigninScreen(), - ), - ); - }, + builder: (BuildContext dialogContext) { + return PopScope( + canPop: false, + child: SignupVerification( + onSubmit: () { + // Clear the form fields + _emailController.clear(); + _passwordController.clear(); + _nisnController.clear(); + _nameController.clear(); + validatorProvider.resetFields(); + + // Navigate to login screen + Navigator.of(dialogContext).pushAndRemoveUntil( + MaterialPageRoute( + builder: (context) => SigninScreen(), + ), + (Route route) => false, + ); + }, + ), ); }, ); } else { - // Show error message + if (!context.mounted) return; CustomSnackBar.show( context, - message: 'Registration failed', + message: 'Registration failed. Please try again.', isError: true, ); } + } catch (e) { + // Remove loading dialog if it's showing + if (Navigator.canPop(context)) { + Navigator.of(context).pop(); + } + + if (!context.mounted) return; + CustomSnackBar.show( + context, + message: 'An error occurred: ${e.toString()}', + isError: true, + ); } finally { setState(() { isLoading = false;