Files
syncrow-app/lib/features/menu/view/widgets/securty/bloc/security_bloc.dart
2025-07-15 09:02:42 +03:00

211 lines
6.5 KiB
Dart

import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_app/features/app_layout/bloc/home_cubit.dart';
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_event.dart';
import 'package:syncrow_app/features/menu/view/widgets/securty/bloc/security_state.dart';
import 'package:syncrow_app/services/api/authentication_api.dart';
class SecurityBloc extends Bloc<SecurityEvent, SecurityState> {
bool _isPasswordVisible = false;
String otpCode = '';
String validate = '';
SecurityBloc() : super(PasswordVisibilityState(false)) {
on<SetPassword>(_onSetPassword);
on<TogglePasswordVisibility>(_onTogglePasswordVisibility);
on<StartTimerEvent>(_onStartTimer);
on<StopTimerEvent>(_onStopTimer);
on<UpdateTimerEvent>(_onUpdateTimer);
on<VerifyPassCodeEvent>(verifyCode);
on<ChangePasswordEvent>(changePassword);
on<DeleteAccountEvent>(onDeleteAccountEvent);
}
void _onSetPassword(SetPassword event, Emitter<SecurityState> emit) {
if (event.password.length < 6) {
emit(PasswordErrorState('Password must be at least 6 characters long.'));
} else {
emit(PasswordSetState('Password successfully set.'));
}
}
void _onTogglePasswordVisibility(
TogglePasswordVisibility event, Emitter<SecurityState> emit) {
_isPasswordVisible = !_isPasswordVisible;
emit(PasswordVisibilityState(_isPasswordVisible));
}
String? passwordValidator(String? value) {
if (value == null || value.isEmpty) {
return 'Please enter your password';
}
List<String> validationErrors = [];
if (!RegExp(r'^(?=.*[a-z])').hasMatch(value)) {
validationErrors.add(' - one lowercase letter');
}
if (!RegExp(r'^(?=.*[A-Z])').hasMatch(value)) {
validationErrors.add(' - one uppercase letter');
}
if (!RegExp(r'^(?=.*\d)').hasMatch(value)) {
validationErrors.add(' - one number');
}
if (!RegExp(r'^(?=.*[@$!%*?&])').hasMatch(value)) {
validationErrors.add(' - one special character');
}
if (value.length < 8) {
validationErrors.add(' - minimum 8 characters');
}
if (validationErrors.isNotEmpty) {
return 'Password must contain at least:\n${validationErrors.join('\n')}';
}
return null;
}
TextEditingController newPassword = TextEditingController();
Timer? _timer;
int _remainingTime = 0;
Future _onStartTimer(
StartTimerEvent event, Emitter<SecurityState> emit) async {
if (_timer != null && _timer!.isActive) {
return;
}
_remainingTime = 1;
add(UpdateTimerEvent(
remainingTime: _remainingTime, isButtonEnabled: false));
try {
_remainingTime = 30;
var res = (await AuthenticationAPI.sendOtp(body: {
'email': HomeCubit.user!.email,
'type': 'PASSWORD',
if (HomeCubit.user!.regionUuid != null)
'regionUuid': HomeCubit.user!.regionUuid
}));
_remainingTime = res['cooldown'];
} on DioException catch (e) {
if (e.response!.statusCode == 400) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
if (errorMessage == 'User not found') {
validate = 'Invalid Credential';
emit(AuthInitialState());
return 1;
} else {
validate = '';
_remainingTime = errorData['data']['cooldown'] ?? 1;
emit(AuthInitialState());
}
} else {
emit(AuthInitialState());
return 1;
}
emit(AuthInitialState());
} catch (e) {
emit(AuthInitialState());
return 1;
}
_timer = Timer.periodic(const Duration(seconds: 1), (timer) {
_remainingTime--;
if (_remainingTime <= 0) {
_timer?.cancel();
add(UpdateTimerEvent(remainingTime: 0, isButtonEnabled: true));
} else {
add(UpdateTimerEvent(
remainingTime: _remainingTime, isButtonEnabled: false));
}
});
}
void _onStopTimer(StopTimerEvent event, Emitter<SecurityState> emit) {
_timer?.cancel();
emit(TimerState(isButtonEnabled: true, remainingTime: 0));
}
void _onUpdateTimer(UpdateTimerEvent event, Emitter<SecurityState> emit) {
emit(TimerState(
isButtonEnabled: event.isButtonEnabled,
remainingTime: event.remainingTime));
}
String formattedTime(int time) {
final int days = (time / 86400).floor(); // 86400 seconds in a day
final int hours = ((time % 86400) / 3600).floor();
final int minutes = (((time % 86400) % 3600) / 60).floor();
final int seconds = (((time % 86400) % 3600) % 60).floor();
final String formattedTime = [
if (days > 0) '${days}d', // Append 'd' for days
if (days > 0 || hours > 0)
hours
.toString()
.padLeft(2, '0'), // Show hours if there are days or hours
minutes.toString().padLeft(2, '0'),
seconds.toString().padLeft(2, '0'),
].join(':');
return formattedTime;
}
Future<void> verifyCode(
VerifyPassCodeEvent event, Emitter<SecurityState> emit) async {
emit(LoadingForgetState());
try {
final response = await AuthenticationAPI.verifyPassCode(body: {
'email': HomeCubit.user!.email!,
'type': 'PASSWORD',
'otpCode': otpCode
});
if (response['statusCode'] == 200) {
_timer?.cancel();
emit(SuccessForgetState());
}
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage =
errorData['error']['message'] ?? 'something went wrong';
validate = errorMessage;
emit(AuthInitialState());
}
}
Future<void> changePassword(
ChangePasswordEvent event, Emitter<SecurityState> emit) async {
emit(LoadingForgetState());
try {
final response = await AuthenticationAPI.forgetPassword(
email: HomeCubit.user!.email!,
otpCode: event.otpCode,
password: newPassword.text,
);
emit(ChangedPassState());
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage =
errorData['error']['message'] ?? 'something went wrong';
validate = errorMessage;
emit(AuthInitialState());
}
}
Future<void> onDeleteAccountEvent(
DeleteAccountEvent event, Emitter<SecurityState> emit) async {
emit(LoadingForgetState());
try {
await AuthenticationAPI.deleteAccount();
emit(ChangedPassState());
} catch (e) {
validate = e.toString();
emit(AuthInitialState());
}
}
}