import 'package:dropdown_button2/dropdown_button2.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:go_router/go_router.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; import 'package:syncrow_web/pages/auth/model/region_model.dart'; import 'package:syncrow_web/pages/auth/view/forget_password_page.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/first_layer.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/routes_const.dart'; import 'package:syncrow_web/utils/helpers/responsice_layout_helper/responsive_layout_helper.dart'; import 'package:syncrow_web/utils/style.dart'; class LoginWebPage extends StatefulWidget { const LoginWebPage({super.key}); @override State createState() => _LoginWebPageState(); } class _LoginWebPageState extends State with HelperResponsiveLayout { @override Widget build(BuildContext context) { return Scaffold( body: BlocProvider( create: (BuildContext context) => AuthBloc()..add(RegionInitialEvent()), child: BlocConsumer( listener: (context, state) { if (state is LoginSuccess) { GoRouter.of(context).go(RoutesConst.home); } else if (state is LoginFailure) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.error), ), ); } }, builder: (context, state) { return _buildLoginForm(context, state); }, ), ), ); } Widget _buildLoginForm(BuildContext context, AuthState state) { final loginBloc = BlocProvider.of(context); final isSmallScreen = isSmallScreenSize(context); final isMediumScreen = isMediumScreenSize(context); Size size = MediaQuery.of(context).size; late ScrollController _scrollController; _scrollController = ScrollController(); void _scrollToCenter() { final double middlePosition = _scrollController.position.maxScrollExtent / 2; _scrollController.animateTo( middlePosition, duration: const Duration(seconds: 1), curve: Curves.easeInOut, ); } WidgetsBinding.instance.addPostFrameCallback((_) { _scrollToCenter(); }); return Stack( children: [ FirstLayer( second: Center( child: ListView( controller: _scrollController, shrinkWrap: true, children: [ Container( width: 400, padding: EdgeInsets.all(size.width * 0.02), margin: EdgeInsets.all(size.width * 0.05), decoration: BoxDecoration( color: Colors.black.withOpacity(0.3), borderRadius: const BorderRadius.all(Radius.circular(20)), ), child: Center( child: isSmallScreen || isMediumScreen ? SizedBox( width: 400, child: Column( // For small screens crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox( width: 300, child: SvgPicture.asset( Assets.loginLogo, ), ), const SizedBox(height: 20), _buildLoginFormFields(context, loginBloc, size), ], ), ) : Row( // For larger screens crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ const Spacer(), Expanded( flex: 2, child: SvgPicture.asset( Assets.loginLogo, ), ), const Spacer(), Expanded( flex: 2, child: _buildLoginFormFields( context, loginBloc, size), ), const Spacer(), ], ), ), ), ], ), ), ), if (state is AuthLoading) const Center(child: CircularProgressIndicator()) ], ); } Widget _buildLoginFormFields( BuildContext context, AuthBloc loginBloc, Size size) { return Container( decoration: BoxDecoration( color: Colors.white.withOpacity(0.1), borderRadius: const BorderRadius.all(Radius.circular(30)), border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2)), ), child: Form( key: loginBloc.loginFormKey, child: Padding( padding: EdgeInsets.symmetric( horizontal: size.width * 0.02, vertical: size.width * 0.003), child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 40), Text('Login', style: Theme.of(context).textTheme.headlineLarge), SizedBox(height: size.height * 0.03), _buildDropdownField(context, loginBloc, size), const SizedBox(height: 20.0), _buildEmailField(context, loginBloc), const SizedBox(height: 20.0), _buildPasswordField(context, loginBloc), const SizedBox(height: 20), _buildForgotPassword(context), const SizedBox(height: 20), _buildCheckbox(context, loginBloc, size), const SizedBox(height: 20.0), _buildSignInButton(context, loginBloc, size), const SizedBox(height: 15.0), _buildValidationMessage(loginBloc), ], ), ), ), ); } Widget _buildDropdownField( BuildContext context, AuthBloc loginBloc, Size size) { final TextEditingController textEditingController = TextEditingController(); return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Text( "Country/Region", style: Theme.of(context).textTheme.bodySmall!.copyWith( fontSize: 14, fontWeight: FontWeight.w400, ), ), const SizedBox(height: 10), Container( height: 50, decoration: const BoxDecoration( color: ColorsManager.boxColor, borderRadius: BorderRadius.all(Radius.circular(8)), ), width: size.width * 0.9, child: DropdownButtonHideUnderline( child: DropdownButton2( style: TextStyle(color: Colors.black), isExpanded: true, hint: Text( 'Select your region/country', style: Theme.of(context).textTheme.bodySmall!.copyWith( color: ColorsManager.grayColor, fontWeight: FontWeight.w400, ), overflow: TextOverflow.ellipsis, ), items: loginBloc.regionList!.map((RegionModel region) { return DropdownMenuItem( value: region.id, // Use region.id as the value child: Text( region.name, overflow: TextOverflow.ellipsis, maxLines: 1, ), ); }).toList(), value: loginBloc.regionList!.any( (region) => region.id == loginBloc.regionUuid,) ? loginBloc.regionUuid : null, onChanged: (String? value) { if (value != null) { loginBloc.add(CheckEnableEvent()); loginBloc.add(SelectRegionEvent(val: value)); } }, buttonStyleData: const ButtonStyleData( padding: EdgeInsets.symmetric(horizontal: 16), height: 40, width: double.infinity, ), dropdownStyleData: DropdownStyleData( maxHeight: size.height * 0.70, ), menuItemStyleData: const MenuItemStyleData( height: 40, ), dropdownSearchData: DropdownSearchData( searchController: textEditingController, searchInnerWidgetHeight: 50, searchInnerWidget: Container( height: 50, padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4), child: TextFormField( style: const TextStyle(color: Colors.black), controller: textEditingController, decoration: textBoxDecoration()!.copyWith( errorStyle: const TextStyle(height: 0), contentPadding: const EdgeInsets.symmetric( vertical: 12, horizontal: 10, ), ), ), ), searchMatchFn: (item, searchValue) { // Use the item's child text (region name) for searching. final regionName = (item.child as Text).data?.toLowerCase() ?? ''; final search = searchValue.toLowerCase().trim(); // Debugging print statement to ensure values are captured correctly. // Return true if the region name contains the search term. return regionName.contains(search); }, ), onMenuStateChange: (isOpen) { if (!isOpen) { textEditingController.clear(); } }, ), ), ), ], ); } Widget _buildEmailField(BuildContext context, AuthBloc loginBloc) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Text( "Email", style: Theme.of(context) .textTheme .bodySmall! .copyWith(fontSize: 14, fontWeight: FontWeight.w400), ), const SizedBox(height: 10), SizedBox( child: TextFormField( onChanged: (value) { loginBloc.add(CheckEnableEvent()); }, validator: loginBloc.loginValidateEmail, controller: loginBloc.loginEmailController, decoration: textBoxDecoration()!.copyWith( errorStyle: const TextStyle(height: 0), hintText: 'Enter your email address', hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( color: ColorsManager.grayColor, fontWeight: FontWeight.w400)), style: const TextStyle(color: Colors.black), ), ), ], ); } Widget _buildPasswordField(BuildContext context, AuthBloc loginBloc) { return Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, children: [ Text( "Password", style: Theme.of(context) .textTheme .bodySmall! .copyWith(fontSize: 14, fontWeight: FontWeight.w400), ), const SizedBox(height: 10), SizedBox( child: TextFormField( onChanged: (value) { loginBloc.add(CheckEnableEvent()); }, validator: loginBloc.validatePassword, obscureText: loginBloc.obscureText, keyboardType: TextInputType.visiblePassword, controller: loginBloc.loginPasswordController, decoration: textBoxDecoration()!.copyWith( hintText: 'At least 8 characters', hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( color: ColorsManager.grayColor, fontWeight: FontWeight.w400), suffixIcon: IconButton( onPressed: () { loginBloc.add( PasswordVisibleEvent(newValue: loginBloc.obscureText)); }, icon: SizedBox( child: SvgPicture.asset( loginBloc.obscureText ? Assets.visiblePassword : Assets.invisiblePassword, height: 15, width: 15, ), ), ), errorStyle: const TextStyle(height: 0), ), style: const TextStyle(color: Colors.black), ), ), ], ); } Widget _buildForgotPassword(BuildContext context) { return SizedBox( child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ InkWell( onTap: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => const ForgetPasswordPage(), )); }, child: Text( "Forgot Password?", style: Theme.of(context).textTheme.bodySmall!.copyWith( color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400), ), ), ], ), ); } Widget _buildCheckbox(BuildContext context, AuthBloc loginBloc, Size size) { return Row( children: [ Transform.scale( scale: 1.2, child: Checkbox( fillColor: MaterialStateProperty.all(Colors.white), activeColor: Colors.white, value: loginBloc.isChecked, checkColor: Colors.black, shape: const CircleBorder(), onChanged: (bool? newValue) { loginBloc.add(CheckBoxEvent(newValue: newValue)); }, ), ), SizedBox( width: 220, child: RichText( text: TextSpan( text: 'Agree to ', style: const TextStyle(color: Colors.white), children: [ TextSpan( text: '(Terms of Service)', style: const TextStyle(color: Colors.black), recognizer: TapGestureRecognizer() ..onTap = () { loginBloc.launchURL('https://example.com/terms'); }, ), TextSpan( text: ' (Legal Statement)', style: const TextStyle(color: Colors.black), recognizer: TapGestureRecognizer() ..onTap = () { loginBloc.launchURL('https://example.com/legal'); }, ), TextSpan( text: ' (Privacy Statement)', style: const TextStyle(color: Colors.black), recognizer: TapGestureRecognizer() ..onTap = () { loginBloc.launchURL('https://example.com/privacy'); }, ), ], ), ), ), ], ); } Widget _buildSignInButton( BuildContext context, AuthBloc loginBloc, Size size) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: size.width * 0.2, child: DefaultButton( enabled: loginBloc.checkValidate, child: Text('Sign in', style: Theme.of(context).textTheme.labelLarge!.copyWith( fontSize: 14, color: loginBloc.checkValidate ? ColorsManager.whiteColors : ColorsManager.whiteColors.withOpacity(0.2), )), onPressed: () { if (loginBloc.loginFormKey.currentState!.validate()) { loginBloc.add(LoginButtonPressed( regionUuid: loginBloc.regionUuid, username: loginBloc.loginEmailController.text, password: loginBloc.loginPasswordController.text, )); } else { loginBloc.add(ChangeValidateEvent()); } }, ), ), ], ); } Widget _buildValidationMessage(AuthBloc loginBloc) { return Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( child: Text( loginBloc.validate, style: const TextStyle( fontWeight: FontWeight.w700, color: ColorsManager.red), ), ) ], ); } }