region and access_management ui

This commit is contained in:
mohammad
2024-08-12 15:23:45 +03:00
parent cb0ebcca37
commit 3f1fdf4f93
3 changed files with 287 additions and 249 deletions

View File

@ -40,10 +40,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
if (_timer != null && _timer!.isActive) { if (_timer != null && _timer!.isActive) {
return; return;
} }
_remainingTime = 60; _remainingTime = 1;
add(UpdateTimerEvent( add(UpdateTimerEvent(remainingTime: _remainingTime, isButtonEnabled: false));
remainingTime: _remainingTime, isButtonEnabled: false));
debugPrint('_remainingTime=$_remainingTime');
_remainingTime = (await AuthenticationAPI.sendOtp(email: forgetEmailController.text,regionUuid: regionUuid))!; _remainingTime = (await AuthenticationAPI.sendOtp(email: forgetEmailController.text,regionUuid: regionUuid))!;
_timer = Timer.periodic(const Duration(seconds: 1), (timer) { _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
_remainingTime--; _remainingTime--;
@ -125,7 +123,6 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
} catch (failure) { } catch (failure) {
validate='Something went wrong'; validate='Something went wrong';
emit(const LoginFailure(error: 'Something went wrong')); emit(const LoginFailure(error: 'Something went wrong'));
// emit(LoginFailure(error: failure.toString()));
return; return;
} }
if (token.accessTokenIsNotEmpty) { if (token.accessTokenIsNotEmpty) {
@ -187,6 +184,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
return 'Email is required'; return 'Email is required';
} else if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) { } else if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value)) {
return 'Enter a valid email address'; return 'Enter a valid email address';
}else if (regionUuid=='') {
return 'Please select your region';
} }
return null; return null;
} }

View File

@ -10,20 +10,19 @@ import 'package:syncrow_web/pages/common/first_layer.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/utils/style.dart';
class ForgetPasswordWebPage extends StatelessWidget { class ForgetPasswordWebPage extends StatelessWidget {
const ForgetPasswordWebPage({super.key}); const ForgetPasswordWebPage({super.key});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: BlocProvider( body: BlocProvider(
create: (context) => AuthBloc()..add(RegionInitialEvent()), create: (context) => AuthBloc()..add(RegionInitialEvent()),
child: BlocConsumer<AuthBloc, AuthState>( child: BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) { listener: (context, state) {
if (state is SuccessForgetState){ if (state is SuccessForgetState) {
Navigator.of(context).pop(); Navigator.of(context).pop();
} } else if (state is FailureForgetState) {
else if (state is FailureForgetState) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar( SnackBar(
content: Text(state.error), content: Text(state.error),
@ -47,264 +46,299 @@ class ForgetPasswordWebPage extends StatelessWidget {
late ScrollController _scrollController; late ScrollController _scrollController;
_scrollController = ScrollController(); _scrollController = ScrollController();
void _scrollToCenter() { void _scrollToCenter() {
final double middlePosition = _scrollController.position.maxScrollExtent / 2; final double middlePosition =
_scrollController.position.maxScrollExtent / 2;
_scrollController.animateTo( _scrollController.animateTo(
middlePosition, middlePosition,
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),
curve: Curves.easeInOut, curve: Curves.easeInOut,
); );
} }
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
_scrollToCenter(); _scrollToCenter();
}); });
final forgetBloc = BlocProvider.of<AuthBloc>(context); final forgetBloc = BlocProvider.of<AuthBloc>(context);
Size size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
return FirstLayer( return FirstLayer(
second: Center( second: Center(
child: ListView( child: ListView(
shrinkWrap: true, shrinkWrap: true,
controller: _scrollController, controller: _scrollController,
children: [ children: [
Container( Container(
padding: EdgeInsets.all(size.width*0.02), padding: EdgeInsets.all(size.width * 0.02),
margin: EdgeInsets.all(size.width*0.09), margin: EdgeInsets.all(size.width * 0.09),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black.withOpacity(0.3), color: Colors.black.withOpacity(0.3),
borderRadius: const BorderRadius.all(Radius.circular(20)), borderRadius: const BorderRadius.all(Radius.circular(20)),
), ),
child: Center( child: Center(
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
const Spacer(), const Spacer(),
Expanded( Expanded(
flex: 3, flex: 3,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.loginLogo, Assets.loginLogo,
),
), ),
const Spacer(), ),
Expanded( const Spacer(),
flex: 3, Expanded(
child: Container( flex: 3,
decoration: BoxDecoration( child: Container(
color: Colors.white.withOpacity(0.1), decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(30)), color: Colors.white.withOpacity(0.1),
border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2)), borderRadius:
), const BorderRadius.all(Radius.circular(30)),
child: Form( border: Border.all(
key: forgetBloc.forgetFormKey, color: ColorsManager.graysColor.withOpacity(0.2)),
child: Padding( ),
padding: EdgeInsets.symmetric( child: Form(
horizontal: size.width*0.02, key: forgetBloc.forgetFormKey,
vertical: size.width*0.003), child: Padding(
child: Column( padding: EdgeInsets.symmetric(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, horizontal: size.width * 0.02,
crossAxisAlignment: CrossAxisAlignment.start, vertical: size.width * 0.003),
children: <Widget>[ child: Column(
const SizedBox(height: 10), mainAxisAlignment: MainAxisAlignment.spaceEvenly,
const Text( crossAxisAlignment: CrossAxisAlignment.start,
'Forget Password', children: <Widget>[
style: TextStyle( const SizedBox(height: 10),
color: Colors.white, const Text(
fontSize: 24, 'Forget Password',
fontWeight: FontWeight.bold), style: TextStyle(
), color: Colors.white,
const SizedBox(height: 10), fontSize: 24,
Text( fontWeight: FontWeight.bold),
'Please fill in your account information to\nretrieve your password', ),
style: Theme.of(context).textTheme.bodySmall, const SizedBox(height: 10),
), Text(
const SizedBox(height: 10), 'Please fill in your account information to\nretrieve your password',
Column( style: Theme.of(context).textTheme.bodySmall,
crossAxisAlignment: CrossAxisAlignment.start, ),
mainAxisAlignment: MainAxisAlignment.start, const SizedBox(height: 10),
children: [ Column(
Text( crossAxisAlignment: CrossAxisAlignment.start,
"Country/Region", mainAxisAlignment: MainAxisAlignment.start,
style: Theme.of(context).textTheme.bodySmall, children: [
), Text(
const SizedBox(height: 10), "Country/Region",
SizedBox( style:
child: DropdownButtonFormField<String>( Theme.of(context).textTheme.bodySmall,
validator: forgetBloc.validateRegion, ),
icon: const Icon( const SizedBox(height: 10),
Icons.keyboard_arrow_down_outlined, SizedBox(
), child: DropdownButtonFormField<String>(
decoration: textBoxDecoration()!.copyWith( validator: forgetBloc.validateRegion,
hintText: null, icon: const Icon(
), Icons.keyboard_arrow_down_outlined,
hint: SizedBox( ),
width: size.width * 0.11, decoration: textBoxDecoration()!.copyWith(
child: const Align( hintText: null,
alignment: Alignment.centerLeft, ),
child: Text( hint: SizedBox(
'Select your region/country', width: size.width * 0.11,
textAlign: TextAlign.center, child: const Align(
overflow: TextOverflow.ellipsis, alignment: Alignment.centerLeft,
child: Text(
), 'Select your region/country',
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
), ),
), ),
isDense: true,
style: const TextStyle(color: Colors.black),
items:forgetBloc.regionList!.map((RegionModel region) {
return DropdownMenuItem<String>(
value: region.id,
child: Text(region.name),
);
}).toList(),
onChanged: (String? value) {
forgetBloc.add(SelectRegionEvent(val: value!,));
},
), ),
) isDense: true,
], style:
), const TextStyle(color: Colors.black),
const SizedBox(height: 20), items: forgetBloc.regionList!
Column( .map((RegionModel region) {
crossAxisAlignment: CrossAxisAlignment.start, return DropdownMenuItem<String>(
mainAxisAlignment: MainAxisAlignment.start, value: region.id,
children: [ child: Text(region.name),
Text("Account", );
style: Theme.of(context).textTheme.bodySmall, }).toList(),
onChanged: (String? value) {
forgetBloc.add(SelectRegionEvent(
val: value!,
));
},
), ),
const SizedBox(height: 10), )
SizedBox( ],
child: TextFormField( ),
validator: forgetBloc.validateEmail, const SizedBox(height: 20),
controller: forgetBloc.forgetEmailController, Column(
decoration: textBoxDecoration()!.copyWith(hintText: 'Enter your email'), crossAxisAlignment: CrossAxisAlignment.start,
style: const TextStyle(color: Colors.black), mainAxisAlignment: MainAxisAlignment.start,
), children: [
Text(
"Account",
style:
Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 10),
SizedBox(
child: TextFormField(
validator: forgetBloc.validateEmail,
controller:
forgetBloc.forgetEmailController,
decoration: textBoxDecoration()!.copyWith(
hintText: 'Enter your email'),
style:
const TextStyle(color: Colors.black),
), ),
], ),
), ],
const SizedBox(height: 20.0), ),
Column( const SizedBox(height: 20.0),
crossAxisAlignment: CrossAxisAlignment.start, Column(
mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ mainAxisAlignment: MainAxisAlignment.start,
Text("One Time Password", children: [
style: Theme.of(context).textTheme.bodySmall,), Text(
const SizedBox(height: 10), "One Time Password",
SizedBox( style:
child: TextFormField( Theme.of(context).textTheme.bodySmall,
validator: forgetBloc.validateCode, ),
keyboardType: TextInputType.visiblePassword, const SizedBox(height: 10),
controller: forgetBloc.forgetOtp, SizedBox(
decoration: textBoxDecoration()!.copyWith( child: TextFormField(
hintText: 'Enter Code', validator: forgetBloc.validateCode,
suffixIcon: SizedBox( keyboardType:
width: 100, TextInputType.visiblePassword,
child: Center( controller: forgetBloc.forgetOtp,
child: InkWell( decoration: textBoxDecoration()!.copyWith(
onTap: () { hintText: 'Enter Code',
BlocProvider.of<AuthBloc>(context).add(StartTimerEvent()); suffixIcon: SizedBox(
}, width: 100,
child: child: Center(
Text( child: InkWell(
'Get Code ${state is TimerState && !state.isButtonEnabled ? "(${ BlocProvider.of<AuthBloc>(context).formattedTime(state.remainingTime)})" : ""}', onTap: () {
style: TextStyle( BlocProvider.of<AuthBloc>(
color: state is TimerState && !state.isButtonEnabled context)
? Colors.grey .add(StartTimerEvent());
: ColorsManager.btnColor, },
), child: Text(
'Get Code ${state is TimerState && !state.isButtonEnabled ? "(${BlocProvider.of<AuthBloc>(context).formattedTime(state.remainingTime)}) " : ""}',
style: TextStyle(
color: state is TimerState &&
!state.isButtonEnabled
? Colors.grey
: ColorsManager.btnColor,
), ),
), ),
), ),
), ),
), ),
style: const TextStyle(color: Colors.black),
), ),
style:
const TextStyle(color: Colors.black),
), ),
],
),
const SizedBox(height: 20.0),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text("Password",
style: Theme.of(context).textTheme.bodySmall,),
const SizedBox(height: 10),
SizedBox(
child: TextFormField(
validator: forgetBloc.passwordValidator,
keyboardType: TextInputType.visiblePassword,
controller: forgetBloc.forgetPasswordController,
decoration: textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters',
),
style: const TextStyle(color: Colors.black),
),
),
],
),
const SizedBox(
height: 10,
),
const SizedBox(height: 20.0),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: size.width * 0.2,
child: DefaultButton(
backgroundColor: ColorsManager.btnColor,
child: const Text('Submit'),
onPressed: () {
if (forgetBloc.forgetFormKey.currentState!.validate()) {
forgetBloc.add(ChangePasswordEvent());
}
},
),
),
],
),
const SizedBox(height: 10.0),
SizedBox(child: Text(forgetBloc.validate,
style: const TextStyle(fontWeight: FontWeight.w700,color: ColorsManager.red ),),),
SizedBox(height: 10,),
SizedBox(
width: size.width * 0.2,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Flexible(
child: Text(
"Do you have an account? ",
style: TextStyle(color: Colors.white),
)),
InkWell(
onTap: () {
Navigator.pop(context);
},
child: const Flexible(
child: Text(
"Sign in",
)),
),
],
), ),
) ],
], ),
), const SizedBox(height: 20.0),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Password",
style:
Theme.of(context).textTheme.bodySmall,
),
const SizedBox(height: 10),
SizedBox(
child: TextFormField(
validator: forgetBloc.passwordValidator,
keyboardType:
TextInputType.visiblePassword,
controller:
forgetBloc.forgetPasswordController,
decoration: textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters',
),
style:
const TextStyle(color: Colors.black),
),
),
],
),
const SizedBox(
height: 10,
),
const SizedBox(height: 20.0),
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: size.width * 0.2,
child: DefaultButton(
backgroundColor: ColorsManager.btnColor,
child: const Text('Submit'),
onPressed: () {
if (forgetBloc
.forgetFormKey.currentState!
.validate()) {
forgetBloc.add(ChangePasswordEvent());
}
},
),
),
],
),
const SizedBox(height: 10.0),
SizedBox(
child: Text(
forgetBloc.validate,
style: const TextStyle(
fontWeight: FontWeight.w700,
color: ColorsManager.red),
),
),
SizedBox(
height: 10,
),
SizedBox(
width: size.width * 0.2,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Flexible(
child: Text(
"Do you have an account? ",
style: TextStyle(color: Colors.white),
)),
InkWell(
onTap: () {
Navigator.pop(context);
},
child: const Flexible(
child: Text(
"Sign in",
)),
),
],
),
)
],
), ),
), ),
), ),
), ),
const Spacer(), ),
], const Spacer(),
), ],
), ),
), ),
], ),
), ],
) ),
); ));
} }
} }

View File

@ -45,33 +45,38 @@ class AuthenticationAPI {
"regionUuid": regionUuid "regionUuid": regionUuid
}, },
showServerMessage: true, showServerMessage: true,
options: Options(),
expectedResponseModel: (json) { expectedResponseModel: (json) {
Map<String, dynamic> parsedJson = jsonDecode(json); return 30;
int cooldown = parsedJson['data']['cooldown'];
debugPrint('Cooldown: $cooldown seconds');
return cooldown;
} }
); );
return response; return 30;
} on DioError catch (e) { } on DioError catch (e) {
if (e.response != null) { if (e.response != null) {
if (e.response!.statusCode == 400) { if (e.response!.statusCode == 400) {
// Handle 400 Bad Request // Handle 400 Bad Request
final errorData = e.response!.data; final errorData = e.response!.data;
String errorMessage = errorData['message'] ?? 'Unknown error'; String errorMessage = errorData['message'];
int cooldown = errorData['data']['cooldown'] ?? 0; debugPrint('Unexpected Error: $errorMessage');
return cooldown; if(errorMessage=='User not found'){
return 1;
}else{
int cooldown = errorData['data']['cooldown'] ?? 1;
return cooldown;
}
} else { } else {
debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}'); debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
return 1;
} }
} else { } else {
debugPrint('Error: ${e.message}'); debugPrint('Error: ${e.message}');
return 1;
} }
return null; return 1;
} catch (e) { } catch (e) {
debugPrint('Unexpected Error: $e'); debugPrint('Unexpected Error: $e');
return null; return 1;
} }
} }
@ -79,7 +84,7 @@ class AuthenticationAPI {
{required String email, required String otpCode}) async { {required String email, required String otpCode}) async {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.verifyOtp, path: ApiEndpoints.verifyOtp,
body: {"email": email, "type": "VERIFICATION", "otpCode": otpCode}, body: {"email": email, "type": "PASSWORD", "otpCode": otpCode},
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
if (json['message'] == 'Otp Verified Successfully') { if (json['message'] == 'Otp Verified Successfully') {