Updated theme colors, added error code handling in user provider, and modified signin and signup screens to handle specific errors and timeouts.

This commit is contained in:
Naresh Pratista 2024-11-13 14:21:56 +07:00
parent 8a2aa421e8
commit 64b0b39deb
4 changed files with 85 additions and 26 deletions

View File

@ -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,

View File

@ -10,12 +10,14 @@ class UserProvider with ChangeNotifier {
Map<String, dynamic>? _userData;
File? _selectedImage;
bool _isLoading = false;
int? _errorCode;
bool get isLoading => _isLoading;
bool get isLoggedIn => _isLoggedIn;
String? get jwtToken => _jwtToken;
Map<String, dynamic>? get userData => _userData;
File? get selectedImage => _selectedImage;
int? get errorCode => _errorCode;
UserProvider() {
_loadLoginStatus();
@ -68,12 +70,15 @@ class UserProvider with ChangeNotifier {
Future<bool> 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');

View File

@ -169,6 +169,15 @@ class SigninScreen extends StatelessWidget {
_emailController.clear();
_passwordController.clear();
});
} else {
// 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,
@ -178,6 +187,7 @@ class SigninScreen extends StatelessWidget {
);
}
}
}
},
),
const SizedBox(height: 8),

View File

@ -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<SignupScreen> {
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(
builder: (BuildContext dialogContext) {
return PopScope(
canPop: false,
child: SignupVerification(
onSubmit: () {
// Navigate to sign in screen
Navigator.pushReplacement(
context,
// 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<dynamic> 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;