mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
auth UI and Api
This commit is contained in:
@ -9,6 +9,8 @@ import 'package:syncrow_web/pages/auth/model/login_with_email_model.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/token.dart';
|
||||
import 'package:syncrow_web/pages/auth/model/user_model.dart';
|
||||
import 'package:syncrow_web/services/auth_api.dart';
|
||||
import 'package:syncrow_web/utils/constants/strings_manager.dart';
|
||||
import 'package:syncrow_web/utils/helpers/shared_preferences_helper.dart';
|
||||
import 'package:syncrow_web/utils/snack_bar.dart';
|
||||
|
||||
class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
@ -20,16 +22,16 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
on<StopTimerEvent>(_onStopTimer);
|
||||
on<UpdateTimerEvent>(_onUpdateTimer);
|
||||
on<PasswordVisibleEvent>(_passwordVisible);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////// forget password //////////////////////////////////
|
||||
final TextEditingController forgetEmailController = TextEditingController();
|
||||
final TextEditingController forgetPasswordController = TextEditingController();
|
||||
final TextEditingController forgetOtp = TextEditingController();
|
||||
final forgetFormKey = GlobalKey<FormState>();
|
||||
|
||||
Timer? _timer;
|
||||
int _remainingTime = 0;
|
||||
|
||||
@ -53,7 +55,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
add(const UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
|
||||
print("Timer finished"); // Debug print
|
||||
} else {
|
||||
add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
add(UpdateTimerEvent(
|
||||
remainingTime: _remainingTime, isButtonEnabled: false));
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -67,40 +70,49 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
ChangePasswordEvent event, Emitter<AuthState> emit) async {
|
||||
try {
|
||||
emit(LoadingForgetState());
|
||||
await AuthenticationAPI.forgetPassword(
|
||||
password: forgetPasswordController.text, email: forgetEmailController.text);
|
||||
bool response = await AuthenticationAPI.verifyOtp(
|
||||
email: forgetEmailController.text, otpCode: forgetOtp.text);
|
||||
if (response == true) {
|
||||
await AuthenticationAPI.forgetPassword(
|
||||
password: forgetPasswordController.text,
|
||||
email: forgetEmailController.text);
|
||||
_timer?.cancel();
|
||||
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
|
||||
}
|
||||
emit(SuccessForgetState());
|
||||
} catch (failure) {
|
||||
print(failure);
|
||||
emit(FailureForgetState(error: failure.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void _onUpdateTimer(UpdateTimerEvent event, Emitter<AuthState> emit) {
|
||||
emit(TimerState(
|
||||
isButtonEnabled: event.isButtonEnabled,
|
||||
remainingTime: event.remainingTime));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////// login /////////////////////////////////////
|
||||
final TextEditingController loginEmailController = TextEditingController();
|
||||
final TextEditingController loginPasswordController = TextEditingController();
|
||||
final loginFormKey = GlobalKey<FormState>();
|
||||
bool isChecked = false;
|
||||
bool obscureText = false;
|
||||
|
||||
bool obscureText = true;
|
||||
String newPassword = '';
|
||||
String maskedEmail = '';
|
||||
String otpCode = '';
|
||||
|
||||
static Token token = Token.emptyConstructor();
|
||||
static UserModel? user;
|
||||
bool showValidationMessage = false;
|
||||
|
||||
void _login(LoginButtonPressed event, Emitter<AuthState> emit) async {
|
||||
void _login(LoginButtonPressed event, Emitter<AuthState> emit) async {
|
||||
emit(LoginLoading());
|
||||
if(isChecked) {
|
||||
if (isChecked) {
|
||||
try {
|
||||
if (event.username.isEmpty || event.password.isEmpty) {
|
||||
CustomSnackBar.displaySnackBar('Please enter your credentials');
|
||||
@ -113,8 +125,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
password: event.password,
|
||||
),
|
||||
);
|
||||
}
|
||||
catch (failure) {
|
||||
} catch (failure) {
|
||||
emit(const LoginFailure(error: 'Something went wrong'));
|
||||
// emit(LoginFailure(error: failure.toString()));
|
||||
return;
|
||||
@ -124,11 +135,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
FlutterSecureStorage storage = const FlutterSecureStorage();
|
||||
await storage.write(
|
||||
key: Token.loginAccessTokenKey, value: token.accessToken);
|
||||
|
||||
const FlutterSecureStorage().write(
|
||||
key: UserModel.userUuidKey,
|
||||
value: Token.decodeToken(token.accessToken)['uuid'].toString()
|
||||
);
|
||||
value: Token.decodeToken(token.accessToken)['uuid'].toString());
|
||||
user = UserModel.fromToken(token);
|
||||
loginEmailController.clear();
|
||||
loginPasswordController.clear();
|
||||
@ -136,18 +145,24 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
} else {
|
||||
emit(const LoginFailure(error: 'Something went wrong'));
|
||||
}
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
emit(const LoginFailure(error: 'Accept terms and condition'));
|
||||
}
|
||||
}
|
||||
|
||||
checkBoxToggle(CheckBoxEvent event, Emitter<AuthState> emit,){
|
||||
checkBoxToggle(CheckBoxEvent event, Emitter<AuthState> emit,) {
|
||||
emit(LoginLoading());
|
||||
isChecked = event.newValue!;
|
||||
emit(LoginInitial());
|
||||
}
|
||||
|
||||
checkOtpCode(ChangePasswordEvent event, Emitter<AuthState> emit,) async {
|
||||
emit(LoadingForgetState());
|
||||
await AuthenticationAPI.verifyOtp(
|
||||
email: forgetEmailController.text, otpCode: forgetOtp.text);
|
||||
emit(SuccessForgetState());
|
||||
}
|
||||
|
||||
void _passwordVisible(PasswordVisibleEvent event, Emitter<AuthState> emit) {
|
||||
emit(LoginLoading());
|
||||
obscureText = !event.newValue!;
|
||||
@ -161,8 +176,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////VALIDATORS/////////////////////////////////////
|
||||
|
||||
/////////////////////////////////////VALIDATORS/////////////////////////////////////
|
||||
String? validatePassword(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Password is required';
|
||||
@ -192,25 +207,23 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
emit(LoadingForgetState());
|
||||
final nameError = validateEmail(forgetEmailController.text);
|
||||
if (nameError != null) {
|
||||
emit(FailureForgetState(error:nameError )) ;
|
||||
// CustomSnackBar.displaySnackBar(nameError);
|
||||
emit(FailureForgetState(error: nameError));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String? validateRegion(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please select a region';
|
||||
}
|
||||
return null;
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please select a region';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
String? passwordValidator(String? value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter your password';
|
||||
}
|
||||
|
||||
List<String> validationErrors = [];
|
||||
|
||||
if (!RegExp(r'^(?=.*[a-z])').hasMatch(value)) {
|
||||
@ -230,73 +243,30 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
}
|
||||
|
||||
if (validationErrors.isNotEmpty) {
|
||||
return 'Password must contain at least:\n' + validationErrors.join('\n');
|
||||
return 'Password must contain at least:\n${validationErrors.join('\n')}';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
String? fullNameValidator(String? value) {
|
||||
if (value == null) return 'Full name is required';
|
||||
|
||||
final withoutExtraSpaces = value.replaceAll(RegExp(r"\s+"), ' ').trim();
|
||||
|
||||
if (withoutExtraSpaces.length < 2 || withoutExtraSpaces.length > 30) {
|
||||
return 'Full name must be between 2 and 30 characters long';
|
||||
}
|
||||
|
||||
// Test if it contains anything but alphanumeric spaces and single quote
|
||||
|
||||
if (RegExp(r"/[^ a-zA-Z0-9-\']/").hasMatch(withoutExtraSpaces)) {
|
||||
return 'Only alphanumeric characters, space, dash and single quote are allowed';
|
||||
}
|
||||
|
||||
final parts = withoutExtraSpaces.split(' ');
|
||||
|
||||
if (parts.length < 2) return 'Full name must contain first and last names';
|
||||
|
||||
if (parts.length > 3) return 'Full name can at most contain 3 parts';
|
||||
|
||||
if (parts.any((part) => part.length < 2 || part.length > 30)) {
|
||||
return 'Full name parts must be between 2 and 30 characters long';
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
String? reEnterPasswordCheckForgetPass(String? value) {
|
||||
passwordValidator(value);
|
||||
if (newPassword == value) {
|
||||
return null;
|
||||
} else {
|
||||
return 'Passwords do not match';
|
||||
}
|
||||
}
|
||||
|
||||
String? emailAddressValidator(String? value) {
|
||||
if (value != null && value.isNotEmpty && value != "") {
|
||||
if (checkValidityOfEmail(value)) {
|
||||
return null;
|
||||
} else {
|
||||
return 'Please enter a valid email';
|
||||
}
|
||||
} else {
|
||||
return 'Email address is required';
|
||||
}
|
||||
}
|
||||
|
||||
bool checkValidityOfEmail(String? email) {
|
||||
if (email != null) {
|
||||
return RegExp(
|
||||
r"^[a-zA-Z0-9]+([.!#$%&'*+/=?^_`{|}~-]?[a-zA-Z0-9]+)*@[a-zA-Z0-9]+([.-]?[a-zA-Z0-9]+)*\.[a-zA-Z0-9]{2,}$")
|
||||
.hasMatch(email);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
String maskEmail(String email) {
|
||||
final emailParts = email.split('@');
|
||||
if (emailParts.length != 2) return email;
|
||||
@ -324,4 +294,36 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
|
||||
];
|
||||
|
||||
|
||||
static Future<String> getTokenAndValidate() async {
|
||||
try {
|
||||
const storage = FlutterSecureStorage();
|
||||
final firstLaunch = await SharedPreferencesHelper.readBoolFromSP(StringsManager.firstLaunch) ?? true;
|
||||
if (firstLaunch) {
|
||||
storage.deleteAll();
|
||||
}
|
||||
await SharedPreferencesHelper.saveBoolToSP(StringsManager.firstLaunch, false);
|
||||
final value = await storage.read(key: Token.loginAccessTokenKey) ?? '';
|
||||
if (value.isEmpty) {
|
||||
return 'Token not found';
|
||||
}
|
||||
final tokenData = Token.decodeToken(value);
|
||||
if (tokenData.containsKey('exp')) {
|
||||
final exp = tokenData['exp'] ?? 0;
|
||||
final currentTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;
|
||||
if (currentTime < exp) {
|
||||
return 'Success';
|
||||
} else {
|
||||
return 'expired';
|
||||
}
|
||||
} else {
|
||||
return 'Something went wrong';
|
||||
}
|
||||
} catch (_) {
|
||||
return 'Something went wrong';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user