Merge branch 'login-fix' into 'master'

Refactor: refactor login functionality to accept credential (email or NISN)...

See merge request profile-image/kedaireka/polinema-adapative-learning/mobile-adaptive-learning!21
This commit is contained in:
Naresh Pratista 2024-12-02 03:21:45 +00:00
commit 7fcd5639ae
2 changed files with 56 additions and 28 deletions

View File

@ -68,14 +68,17 @@ class UserProvider with ChangeNotifier {
} }
} }
Future<bool> login({required String email, required String password}) async { // In the login method of UserProvider
Future<bool> login({
required String credential,
required String password,
}) async {
setLoading(true); setLoading(true);
_errorCode = null; _errorCode = null;
try { try {
final response = await _userRepository.loginUser({ final loginData = {'IDENTIFIER': credential, 'PASSWORD': password};
'EMAIL': email,
'PASSWORD': password, final response = await _userRepository.loginUser(loginData);
});
_errorCode = response.statusCode; _errorCode = response.statusCode;
@ -93,7 +96,6 @@ class UserProvider with ChangeNotifier {
await refreshUserData(); await refreshUserData();
return true; return true;
} else if (response.statusCode == 403) { } else if (response.statusCode == 403) {
// Khusus untuk error 403 (user belum divalidasi)
print('User is not validated: ${response.data['message']}'); print('User is not validated: ${response.data['message']}');
return false; return false;
} }

View File

@ -19,22 +19,29 @@ class SigninScreen extends StatefulWidget {
} }
class _SigninScreenState extends State<SigninScreen> { class _SigninScreenState extends State<SigninScreen> {
final TextEditingController _emailController = TextEditingController(); final TextEditingController _loginController = TextEditingController();
final TextEditingController _passwordController = TextEditingController(); final TextEditingController _passwordController = TextEditingController();
final FocusNode _emailFocus = FocusNode(); final FocusNode _loginFocus = FocusNode();
final FocusNode _passwordFocus = FocusNode(); final FocusNode _passwordFocus = FocusNode();
final _formKey = GlobalKey<FormState>(); final _formKey = GlobalKey<FormState>();
@override @override
void initState() { void initState() {
super.initState(); super.initState();
context.read<ValidatorProvider>().setController('login', _loginController);
context
.read<ValidatorProvider>()
.setController('password', _passwordController);
} }
@override @override
void dispose() { void dispose() {
_emailController.dispose(); context.read<ValidatorProvider>().removeController('login');
context.read<ValidatorProvider>().removeController('password');
_loginController.dispose();
_passwordController.dispose(); _passwordController.dispose();
_emailFocus.dispose(); _loginFocus.dispose();
_passwordFocus.dispose(); _passwordFocus.dispose();
super.dispose(); super.dispose();
} }
@ -46,9 +53,12 @@ class _SigninScreenState extends State<SigninScreen> {
final validatorProvider = context.read<ValidatorProvider>(); final validatorProvider = context.read<ValidatorProvider>();
try { try {
final loginCredential = _loginController.text.trim();
final password = _passwordController.text;
final isSuccess = await userProvider.login( final isSuccess = await userProvider.login(
email: _emailController.text.trim(), credential: loginCredential,
password: _passwordController.text, password: password,
); );
if (!mounted) return; if (!mounted) return;
@ -73,8 +83,6 @@ class _SigninScreenState extends State<SigninScreen> {
// Reset form // Reset form
validatorProvider.resetFields(); validatorProvider.resetFields();
_emailController.clear();
_passwordController.clear();
} else { } else {
_handleLoginError(context, userProvider.errorCode); _handleLoginError(context, userProvider.errorCode);
} }
@ -94,10 +102,10 @@ class _SigninScreenState extends State<SigninScreen> {
switch (errorCode) { switch (errorCode) {
case 403: case 403:
message = 'Please verify your email first to continue.'; message = 'Please verify your account first to continue.';
break; break;
case 401: case 401:
message = 'Invalid email or password. Please try again.'; message = 'Invalid credentials. Please try again.';
break; break;
case 429: case 429:
message = 'Too many attempts. Please try again later.'; message = 'Too many attempts. Please try again later.';
@ -107,6 +115,22 @@ class _SigninScreenState extends State<SigninScreen> {
CustomSnackBar.show(context, message: message, isError: true); CustomSnackBar.show(context, message: message, isError: true);
} }
String? _validateLogin(String? value) {
if (value == null || value.isEmpty) {
return 'Login credential cannot be empty';
}
value = value.trim();
if (value.contains('@')) {
return context.read<ValidatorProvider>().emailValidator(value);
} else if (RegExp(r'^\d{ 10}$').hasMatch(value)) {
return null; // Valid NISN
} else {
return 'Please enter a valid email or NISN (10 digits)';
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
@ -158,26 +182,28 @@ class _SigninScreenState extends State<SigninScreen> {
), ),
const SizedBox(height: 30), const SizedBox(height: 30),
CustomFieldWidget( CustomFieldWidget(
fieldName: 'email', fieldName: 'login',
controller: _emailController, controller: _loginController,
focusNode: _emailFocus, focusNode: _loginFocus,
isRequired: true, isRequired: true,
textInputAction: TextInputAction.next, textInputAction: TextInputAction.next,
labelText: 'Email Address', labelText: 'Email or NISN',
hintText: 'Enter Your Email Address', hintText: 'Enter Email or NISN Number',
keyboardType: TextInputType.emailAddress, keyboardType: TextInputType.emailAddress,
validator: validatorProvider.emailValidator, validator: _validateLogin,
onChanged: (value) => onChanged: (value) =>
validatorProvider.validateField( context.read<ValidatorProvider>().validateField(
'email', 'login',
value?.trim(), value?.trim(),
validator: validatorProvider.emailValidator, validator: _validateLogin,
), ),
onFieldSubmitted: (_) { onFieldSubmitted: (_) {
FocusScope.of(context) FocusScope.of(context)
.requestFocus(_passwordFocus); .requestFocus(_passwordFocus);
}, },
errorText: validatorProvider.getError('email'), errorText: context
.read<ValidatorProvider>()
.getError('login'),
), ),
const SizedBox(height: 14), const SizedBox(height: 14),
CustomFieldWidget( CustomFieldWidget(