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:
parent
8a2aa421e8
commit
64b0b39deb
|
|
@ -83,9 +83,9 @@ class AppTextStyles {
|
||||||
ThemeData appTheme() {
|
ThemeData appTheme() {
|
||||||
return ThemeData(
|
return ThemeData(
|
||||||
textSelectionTheme: const TextSelectionThemeData(
|
textSelectionTheme: const TextSelectionThemeData(
|
||||||
cursorColor: AppColors.primaryColor,
|
cursorColor: AppColors.blackColor,
|
||||||
selectionColor: AppColors.primaryColor,
|
selectionColor: AppColors.blueColor,
|
||||||
selectionHandleColor: AppColors.primaryColor,
|
selectionHandleColor: AppColors.blueColor,
|
||||||
),
|
),
|
||||||
textTheme: GoogleFonts.interTextTheme(),
|
textTheme: GoogleFonts.interTextTheme(),
|
||||||
fontFamily: GoogleFonts.inter().fontFamily,
|
fontFamily: GoogleFonts.inter().fontFamily,
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,14 @@ class UserProvider with ChangeNotifier {
|
||||||
Map<String, dynamic>? _userData;
|
Map<String, dynamic>? _userData;
|
||||||
File? _selectedImage;
|
File? _selectedImage;
|
||||||
bool _isLoading = false;
|
bool _isLoading = false;
|
||||||
|
int? _errorCode;
|
||||||
|
|
||||||
bool get isLoading => _isLoading;
|
bool get isLoading => _isLoading;
|
||||||
bool get isLoggedIn => _isLoggedIn;
|
bool get isLoggedIn => _isLoggedIn;
|
||||||
String? get jwtToken => _jwtToken;
|
String? get jwtToken => _jwtToken;
|
||||||
Map<String, dynamic>? get userData => _userData;
|
Map<String, dynamic>? get userData => _userData;
|
||||||
File? get selectedImage => _selectedImage;
|
File? get selectedImage => _selectedImage;
|
||||||
|
int? get errorCode => _errorCode;
|
||||||
|
|
||||||
UserProvider() {
|
UserProvider() {
|
||||||
_loadLoginStatus();
|
_loadLoginStatus();
|
||||||
|
|
@ -68,12 +70,15 @@ class UserProvider with ChangeNotifier {
|
||||||
|
|
||||||
Future<bool> login({required String email, required String password}) async {
|
Future<bool> login({required String email, required String password}) async {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
_errorCode = null;
|
||||||
try {
|
try {
|
||||||
final response = await _userRepository.loginUser({
|
final response = await _userRepository.loginUser({
|
||||||
'EMAIL': email,
|
'EMAIL': email,
|
||||||
'PASSWORD': password,
|
'PASSWORD': password,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
_errorCode = response.statusCode;
|
||||||
|
|
||||||
if (response.statusCode == 200 &&
|
if (response.statusCode == 200 &&
|
||||||
response.data['payload']['TOKEN'] != null) {
|
response.data['payload']['TOKEN'] != null) {
|
||||||
String token = response.data['payload']['TOKEN'];
|
String token = response.data['payload']['TOKEN'];
|
||||||
|
|
@ -87,7 +92,12 @@ class UserProvider with ChangeNotifier {
|
||||||
_isLoggedIn = true;
|
_isLoggedIn = true;
|
||||||
await refreshUserData();
|
await refreshUserData();
|
||||||
return true;
|
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;
|
return false;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Login error: $e');
|
print('Login error: $e');
|
||||||
|
|
|
||||||
|
|
@ -169,6 +169,15 @@ class SigninScreen extends StatelessWidget {
|
||||||
_emailController.clear();
|
_emailController.clear();
|
||||||
_passwordController.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 {
|
} else {
|
||||||
CustomSnackBar.show(
|
CustomSnackBar.show(
|
||||||
context,
|
context,
|
||||||
|
|
@ -178,6 +187,7 @@ class SigninScreen extends StatelessWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 8),
|
const SizedBox(height: 8),
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:english_learning/core/widgets/custom_snackbar.dart';
|
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/user_provider.dart';
|
||||||
import 'package:english_learning/features/auth/provider/validator_provider.dart';
|
import 'package:english_learning/features/auth/provider/validator_provider.dart';
|
||||||
|
|
@ -38,46 +40,83 @@ class _SignupScreenState extends State<SignupScreen> {
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
ValidatorProvider validatorProvider,
|
ValidatorProvider validatorProvider,
|
||||||
) async {
|
) async {
|
||||||
|
if (isLoading) return; // Prevent multiple submissions
|
||||||
|
|
||||||
setState(() {
|
setState(() {
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Attempt registration first
|
// Attempt registration with timeout
|
||||||
final isSuccess = await userProvider.register(
|
final isSuccess = await userProvider
|
||||||
|
.register(
|
||||||
name: _nameController.text,
|
name: _nameController.text,
|
||||||
email: _emailController.text,
|
email: _emailController.text,
|
||||||
nisn: _nisnController.text,
|
nisn: _nisnController.text,
|
||||||
password: _passwordController.text,
|
password: _passwordController.text,
|
||||||
confirmPassword: _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) {
|
if (isSuccess) {
|
||||||
// Show verification dialog
|
// Show success verification dialog
|
||||||
showDialog(
|
if (!context.mounted) return;
|
||||||
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext dialogContext) {
|
||||||
return SignupVerification(
|
return PopScope(
|
||||||
|
canPop: false,
|
||||||
|
child: SignupVerification(
|
||||||
onSubmit: () {
|
onSubmit: () {
|
||||||
// Navigate to sign in screen
|
// Clear the form fields
|
||||||
Navigator.pushReplacement(
|
_emailController.clear();
|
||||||
context,
|
_passwordController.clear();
|
||||||
|
_nisnController.clear();
|
||||||
|
_nameController.clear();
|
||||||
|
validatorProvider.resetFields();
|
||||||
|
|
||||||
|
// Navigate to login screen
|
||||||
|
Navigator.of(dialogContext).pushAndRemoveUntil(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => SigninScreen(),
|
builder: (context) => SigninScreen(),
|
||||||
),
|
),
|
||||||
|
(Route<dynamic> route) => false,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
// Show error message
|
if (!context.mounted) return;
|
||||||
CustomSnackBar.show(
|
CustomSnackBar.show(
|
||||||
context,
|
context,
|
||||||
message: 'Registration failed',
|
message: 'Registration failed. Please try again.',
|
||||||
isError: true,
|
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 {
|
} finally {
|
||||||
setState(() {
|
setState(() {
|
||||||
isLoading = false;
|
isLoading = false;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user