Merge pull request #38 from SyncrowIOT/access_bug_fixes

access_bug_fixes
This commit is contained in:
Abdullah
2024-10-09 21:30:58 +03:00
committed by GitHub
10 changed files with 460 additions and 223 deletions

View File

@ -5,7 +5,6 @@ import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
import 'package:syncrow_web/pages/access_management/model/password_model.dart'; import 'package:syncrow_web/pages/access_management/model/password_model.dart';
import 'package:syncrow_web/pages/common/hour_picker_dialog.dart'; import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
import 'package:syncrow_web/services/access_mang_api.dart'; import 'package:syncrow_web/services/access_mang_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart'; import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/snack_bar.dart'; import 'package:syncrow_web/utils/snack_bar.dart';

View File

@ -24,7 +24,6 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isLargeScreen = isLargeScreenSize(context); final isLargeScreen = isLargeScreenSize(context);
final isSmallScreen = isSmallScreenSize(context); final isSmallScreen = isSmallScreenSize(context);
final isHalfMediumScreen = isHafMediumScreenSize(context); final isHalfMediumScreen = isHafMediumScreenSize(context);
@ -169,7 +168,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
} }
Row _buildNormalSearchWidgets(BuildContext context, AccessBloc accessBloc) { Row _buildNormalSearchWidgets(BuildContext context, AccessBloc accessBloc) {
TimeOfDay _selectedTime = TimeOfDay.now(); // TimeOfDay _selectedTime = TimeOfDay.now();
return Row( return Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@ -268,8 +267,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex, selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(), passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp, startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp endTime: accessBloc.expirationTimeTimeStamp));
));
}, },
onReset: () { onReset: () {
accessBloc.add(ResetSearch()); accessBloc.add(ResetSearch());
@ -278,6 +276,4 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
], ],
); );
} }
} }

View File

@ -108,20 +108,9 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
} }
} on DioException catch (e) { } on DioException catch (e) {
final errorData = e.response!.data; final errorData = e.response!.data;
String errorMessage = errorData['message']; String errorMessage = errorData['error']['message'] ?? 'something went wrong';
if (errorMessage == 'this email is not registered') { validate = errorMessage;
validate = 'Invalid Credentials!';
emit(AuthInitialState()); emit(AuthInitialState());
} else if (errorMessage == "You entered wrong otp") {
forgetValidate = 'Wrong one time password.';
emit(AuthInitialState());
} else if (errorMessage == "OTP expired") {
forgetValidate = 'One time password has been expired.';
emit(AuthInitialState());
} else {
validate = '';
emit(AuthInitialState());
}
} }
} }

View File

@ -48,8 +48,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
late ScrollController _scrollController; late ScrollController _scrollController;
_scrollController = ScrollController(); _scrollController = ScrollController();
void _scrollToCenter() { void _scrollToCenter() {
final double middlePosition = final double middlePosition = _scrollController.position.maxScrollExtent / 2;
_scrollController.position.maxScrollExtent / 2;
_scrollController.animateTo( _scrollController.animateTo(
middlePosition, middlePosition,
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),
@ -66,8 +65,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
second: Center( second: Center(
child: Stack( child: Stack(
children: [ children: [
if (state is AuthLoading) if (state is AuthLoading) const Center(child: CircularProgressIndicator()),
const Center(child: CircularProgressIndicator()),
ListView( ListView(
shrinkWrap: true, shrinkWrap: true,
controller: _scrollController, controller: _scrollController,
@ -97,21 +95,16 @@ class ForgetPasswordWebPage extends StatelessWidget {
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1), color: Colors.white.withOpacity(0.1),
borderRadius: borderRadius: const BorderRadius.all(Radius.circular(30)),
const BorderRadius.all(Radius.circular(30)), border: Border.all(color: ColorsManager.graysColor.withOpacity(0.2)),
border: Border.all(
color:
ColorsManager.graysColor.withOpacity(0.2)),
), ),
child: Form( child: Form(
key: forgetBloc.forgetFormKey, key: forgetBloc.forgetFormKey,
child: Padding( child: Padding(
padding: EdgeInsets.symmetric( padding: EdgeInsets.symmetric(
horizontal: size.width * 0.02, horizontal: size.width * 0.02, vertical: size.width * 0.003),
vertical: size.width * 0.003),
child: Column( child: Column(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceEvenly,
MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[ children: <Widget>[
const SizedBox(height: 10), const SizedBox(height: 10),
@ -128,66 +121,55 @@ class ForgetPasswordWebPage extends StatelessWidget {
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith( .copyWith(fontSize: 14, fontWeight: FontWeight.w400),
fontSize: 14,
fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Column( Column(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
const SizedBox(height: 10), const SizedBox(height: 10),
Form( Form(
key: forgetBloc.forgetRegionKey, key: forgetBloc.forgetRegionKey,
child: SizedBox( child: SizedBox(
child: _buildDropdownField( child:
context, forgetBloc, size))) _buildDropdownField(context, forgetBloc, size)))
], ],
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Form( Form(
key: forgetBloc.forgetEmailKey, key: forgetBloc.forgetEmailKey,
child: Column( child: Column(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
children: [ children: [
Text( Text(
"Account", "Account",
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme fontSize: 14, fontWeight: FontWeight.w400),
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
child: TextFormField( child: TextFormField(
controller: forgetBloc.forgetEmailController, controller: forgetBloc.forgetEmailController,
validator: forgetBloc.validateEmail, validator: forgetBloc.validateEmail,
decoration: decoration: textBoxDecoration()!.copyWith(
textBoxDecoration()!.copyWith(
hintText: 'Enter your email', hintText: 'Enter your email',
hintStyle: Theme.of(context) hintStyle: Theme.of(context)
.textTheme.bodySmall!.copyWith( .textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
fontWeight: FontWeight.w400), fontWeight: FontWeight.w400),
), ),
style: const TextStyle( style: const TextStyle(color: Colors.black),
color: Colors.black),
), ),
), ),
], ],
)), )),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Column( Column(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
@ -195,22 +177,20 @@ class ForgetPasswordWebPage extends StatelessWidget {
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith( .copyWith(fontSize: 14, fontWeight: FontWeight.w400),
fontSize: 14,
fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
child: TextFormField( child: TextFormField(
validator: forgetBloc.validateCode, validator: forgetBloc.validateCode,
keyboardType: keyboardType: TextInputType.visiblePassword,
TextInputType.visiblePassword,
controller: forgetBloc.forgetOtp, controller: forgetBloc.forgetOtp,
decoration: decoration: textBoxDecoration()!.copyWith(
textBoxDecoration()!.copyWith(
hintText: 'Enter Code', hintText: 'Enter Code',
hintStyle: Theme.of(context).textTheme hintStyle: Theme.of(context)
.bodySmall!.copyWith( .textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor, color: ColorsManager.grayColor,
fontWeight: FontWeight.w400), fontWeight: FontWeight.w400),
suffixIcon: SizedBox( suffixIcon: SizedBox(
@ -222,8 +202,15 @@ class ForgetPasswordWebPage extends StatelessWidget {
state.remainingTime != 1 state.remainingTime != 1
? null ? null
: () { : () {
if (forgetBloc.forgetEmailKey.currentState!.validate()||forgetBloc.forgetRegionKey.currentState!.validate()) { if (forgetBloc
if(forgetBloc.forgetRegionKey.currentState!.validate()){ .forgetEmailKey.currentState!
.validate() ||
forgetBloc
.forgetRegionKey.currentState!
.validate()) {
if (forgetBloc
.forgetRegionKey.currentState!
.validate()) {
forgetBloc.add(StartTimerEvent()); forgetBloc.add(StartTimerEvent());
} }
} }
@ -231,28 +218,23 @@ class ForgetPasswordWebPage extends StatelessWidget {
child: Text( child: Text(
'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}', 'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}',
style: TextStyle( style: TextStyle(
color: state color: state is TimerState &&
is TimerState && !state.isButtonEnabled
!state
.isButtonEnabled
? Colors.grey ? Colors.grey
: ColorsManager : ColorsManager.btnColor,
.btnColor,
), ),
), ),
), ),
), ),
), ),
), ),
style: const TextStyle( style: const TextStyle(color: Colors.black),
color: Colors.black),
), ),
), ),
if (forgetBloc.forgetValidate != if (forgetBloc.forgetValidate !=
'') // Check if there is a validation message '') // Check if there is a validation message
Padding( Padding(
padding: padding: const EdgeInsets.only(top: 8.0),
const EdgeInsets.only(top: 8.0),
child: Text( child: Text(
forgetBloc.forgetValidate, forgetBloc.forgetValidate,
style: const TextStyle( style: const TextStyle(
@ -265,8 +247,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Column( Column(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start,
children: [ children: [
Text( Text(
@ -274,35 +255,26 @@ class ForgetPasswordWebPage extends StatelessWidget {
style: Theme.of(context) style: Theme.of(context)
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith( .copyWith(fontSize: 14, fontWeight: FontWeight.w400),
fontSize: 14,
fontWeight: FontWeight.w400),
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
SizedBox( SizedBox(
child: TextFormField( child: TextFormField(
obscureText: forgetBloc.obscureText, obscureText: forgetBloc.obscureText,
keyboardType: keyboardType: TextInputType.visiblePassword,
TextInputType.visiblePassword, validator: forgetBloc.passwordValidator,
validator: controller: forgetBloc.forgetPasswordController,
forgetBloc.passwordValidator, decoration: textBoxDecoration()!.copyWith(
controller: forgetBloc
.forgetPasswordController,
decoration:
textBoxDecoration()!.copyWith(
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: () { onPressed: () {
forgetBloc.add( forgetBloc.add(PasswordVisibleEvent(
PasswordVisibleEvent( newValue: forgetBloc.obscureText));
newValue: forgetBloc
.obscureText));
}, },
icon: SizedBox( icon: SizedBox(
child: SvgPicture.asset( child: SvgPicture.asset(
forgetBloc.obscureText forgetBloc.obscureText
? Assets.visiblePassword ? Assets.visiblePassword
: Assets : Assets.invisiblePassword,
.invisiblePassword,
height: 15, height: 15,
width: 15, width: 15,
), ),
@ -313,13 +285,10 @@ class ForgetPasswordWebPage extends StatelessWidget {
.textTheme .textTheme
.bodySmall! .bodySmall!
.copyWith( .copyWith(
color: color: ColorsManager.grayColor,
ColorsManager.grayColor, fontWeight: FontWeight.w400),
fontWeight:
FontWeight.w400),
), ),
style: const TextStyle( style: const TextStyle(color: Colors.black),
color: Colors.black),
), ),
), ),
], ],
@ -329,21 +298,22 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
const SizedBox(height: 20.0), const SizedBox(height: 20.0),
Row( Row(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.center,
CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SizedBox( SizedBox(
width: size.width * 0.2, width: size.width * 0.2,
child: DefaultButton( child: DefaultButton(
backgroundColor: backgroundColor: ColorsManager.btnColor,
ColorsManager.btnColor,
child: const Text('Submit'), child: const Text('Submit'),
onPressed: () { onPressed: () {
if (forgetBloc.forgetFormKey.currentState!.validate() || if (forgetBloc.forgetFormKey.currentState!.validate() ||
forgetBloc.forgetEmailKey.currentState!.validate() ) { forgetBloc.forgetEmailKey.currentState!
if( forgetBloc.forgetEmailKey.currentState!.validate() .validate()) {
&&forgetBloc.forgetFormKey.currentState!.validate() ){ if (forgetBloc.forgetEmailKey.currentState!
.validate() &&
forgetBloc.forgetFormKey.currentState!
.validate()) {
forgetBloc.add(ChangePasswordEvent()); forgetBloc.add(ChangePasswordEvent());
} }
} }
@ -358,8 +328,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
child: Text( child: Text(
forgetBloc.validate, forgetBloc.validate,
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700, color: ColorsManager.red),
color: ColorsManager.red),
), ),
), ),
), ),
@ -372,8 +341,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
children: [ children: [
const Text( const Text(
"Do you have an account? ", "Do you have an account? ",
style: style: TextStyle(color: Colors.white),
TextStyle(color: Colors.white),
), ),
InkWell( InkWell(
onTap: () { onTap: () {
@ -407,8 +375,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
)); ));
} }
Widget _buildDropdownField( Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) {
BuildContext context, AuthBloc loginBloc, Size size) {
final TextEditingController textEditingController = TextEditingController(); final TextEditingController textEditingController = TextEditingController();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -434,13 +401,10 @@ class ForgetPasswordWebPage extends StatelessWidget {
builder: (FormFieldState<String> field) { builder: (FormFieldState<String> field) {
return InputDecorator( return InputDecorator(
decoration: InputDecoration( decoration: InputDecoration(
contentPadding: contentPadding: const EdgeInsets.symmetric(horizontal: 2, vertical: 10),
const EdgeInsets.symmetric(horizontal: 2, vertical: 10),
errorText: field.errorText, errorText: field.errorText,
filled: filled: true, // Ensure the dropdown is filled with the background color
true, // Ensure the dropdown is filled with the background color fillColor: ColorsManager.boxColor, // Match the dropdown container color
fillColor: ColorsManager
.boxColor, // Match the dropdown container color
border: OutlineInputBorder( border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide( borderSide: BorderSide(
@ -451,22 +415,20 @@ class ForgetPasswordWebPage extends StatelessWidget {
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide( borderSide: BorderSide(
color: color: field.hasError ? Colors.red : ColorsManager.grayColor,
field.hasError ? Colors.red : ColorsManager.grayColor,
width: 1.5, width: 1.5,
), ),
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide( borderSide: BorderSide(
color: color: field.hasError ? Colors.red : ColorsManager.grayColor,
field.hasError ? Colors.red : ColorsManager.grayColor,
width: 1.5, width: 1.5,
), ),
), ),
errorBorder: OutlineInputBorder( errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(8.0), borderRadius: BorderRadius.circular(8.0),
borderSide: BorderSide( borderSide: const BorderSide(
color: Colors.red, color: Colors.red,
width: 1.5, width: 1.5,
), ),
@ -497,15 +459,13 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
); );
}).toList(), }).toList(),
value: loginBloc.regionList! value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid)
.any((region) => region.id == loginBloc.regionUuid)
? loginBloc.regionUuid ? loginBloc.regionUuid
: null, : null,
onChanged: (String? value) { onChanged: (String? value) {
if (value != null) { if (value != null) {
loginBloc.add(SelectRegionEvent(val: value)); loginBloc.add(SelectRegionEvent(val: value));
field.didChange( field.didChange(value); // Notify the form field of the change
value); // Notify the form field of the change
} }
}, },
buttonStyleData: const ButtonStyleData( buttonStyleData: const ButtonStyleData(
@ -529,8 +489,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
searchInnerWidgetHeight: 50, searchInnerWidgetHeight: 50,
searchInnerWidget: Container( searchInnerWidget: Container(
height: 50, height: 50,
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
horizontal: 8, vertical: 4),
child: TextFormField( child: TextFormField(
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
controller: textEditingController, controller: textEditingController,
@ -544,8 +503,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
), ),
), ),
searchMatchFn: (item, searchValue) { searchMatchFn: (item, searchValue) {
final regionName = final regionName = (item.child as Text).data?.toLowerCase() ?? '';
(item.child as Text).data?.toLowerCase() ?? '';
final search = searchValue.toLowerCase().trim(); final search = searchValue.toLowerCase().trim();
return regionName.contains(search); return regionName.contains(search);
}, },
@ -564,6 +522,4 @@ class ForgetPasswordWebPage extends StatelessWidget {
], ],
); );
} }
} }

View File

@ -24,8 +24,7 @@ class LoginWebPage extends StatefulWidget {
State<LoginWebPage> createState() => _LoginWebPageState(); State<LoginWebPage> createState() => _LoginWebPageState();
} }
class _LoginWebPageState extends State<LoginWebPage> class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout {
with HelperResponsiveLayout {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@ -60,8 +59,7 @@ class _LoginWebPageState extends State<LoginWebPage>
_scrollController = ScrollController(); _scrollController = ScrollController();
void _scrollToCenter() { void _scrollToCenter() {
final double middlePosition = final double middlePosition = _scrollController.position.maxScrollExtent / 2;
_scrollController.position.maxScrollExtent / 2;
_scrollController.animateTo( _scrollController.animateTo(
middlePosition, middlePosition,
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),
@ -123,8 +121,7 @@ class _LoginWebPageState extends State<LoginWebPage>
const Spacer(), const Spacer(),
Expanded( Expanded(
flex: 2, flex: 2,
child: _buildLoginFormFields( child: _buildLoginFormFields(context, loginBloc, size),
context, loginBloc, size),
), ),
const Spacer(), const Spacer(),
], ],
@ -135,14 +132,12 @@ class _LoginWebPageState extends State<LoginWebPage>
), ),
), ),
), ),
if (state is AuthLoading) if (state is AuthLoading) const Center(child: CircularProgressIndicator())
const Center(child: CircularProgressIndicator())
], ],
); );
} }
Widget _buildLoginFormFields( Widget _buildLoginFormFields(BuildContext context, AuthBloc loginBloc, Size size) {
BuildContext context, AuthBloc loginBloc, Size size) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1), color: Colors.white.withOpacity(0.1),
@ -152,8 +147,8 @@ class _LoginWebPageState extends State<LoginWebPage>
child: Form( child: Form(
key: loginBloc.loginFormKey, key: loginBloc.loginFormKey,
child: Padding( child: Padding(
padding: EdgeInsets.symmetric( padding:
horizontal: size.width * 0.02, vertical: size.width * 0.003), EdgeInsets.symmetric(horizontal: size.width * 0.02, vertical: size.width * 0.003),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -181,9 +176,7 @@ class _LoginWebPageState extends State<LoginWebPage>
); );
} }
Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) {
Widget _buildDropdownField(
BuildContext context, AuthBloc loginBloc, Size size) {
final TextEditingController textEditingController = TextEditingController(); final TextEditingController textEditingController = TextEditingController();
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -227,7 +220,8 @@ class _LoginWebPageState extends State<LoginWebPage>
); );
}).toList(), }).toList(),
value: loginBloc.regionList!.any( value: loginBloc.regionList!.any(
(region) => region.id == loginBloc.regionUuid,) (region) => region.id == loginBloc.regionUuid,
)
? loginBloc.regionUuid ? loginBloc.regionUuid
: null, : null,
onChanged: (String? value) { onChanged: (String? value) {
@ -286,7 +280,6 @@ class _LoginWebPageState extends State<LoginWebPage>
); );
} }
Widget _buildEmailField(BuildContext context, AuthBloc loginBloc) { Widget _buildEmailField(BuildContext context, AuthBloc loginBloc) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -310,9 +303,10 @@ class _LoginWebPageState extends State<LoginWebPage>
decoration: textBoxDecoration()!.copyWith( decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(height: 0), errorStyle: const TextStyle(height: 0),
hintText: 'Enter your email address', hintText: 'Enter your email address',
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( hintStyle: Theme.of(context)
color: ColorsManager.grayColor, .textTheme
fontWeight: FontWeight.w400)), .bodySmall!
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400)),
style: const TextStyle(color: Colors.black), style: const TextStyle(color: Colors.black),
), ),
), ),
@ -344,18 +338,17 @@ class _LoginWebPageState extends State<LoginWebPage>
controller: loginBloc.loginPasswordController, controller: loginBloc.loginPasswordController,
decoration: textBoxDecoration()!.copyWith( decoration: textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters', hintText: 'At least 8 characters',
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith( hintStyle: Theme.of(context)
color: ColorsManager.grayColor, fontWeight: FontWeight.w400), .textTheme
.bodySmall!
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400),
suffixIcon: IconButton( suffixIcon: IconButton(
onPressed: () { onPressed: () {
loginBloc.add( loginBloc.add(PasswordVisibleEvent(newValue: loginBloc.obscureText));
PasswordVisibleEvent(newValue: loginBloc.obscureText));
}, },
icon: SizedBox( icon: SizedBox(
child: SvgPicture.asset( child: SvgPicture.asset(
loginBloc.obscureText loginBloc.obscureText ? Assets.visiblePassword : Assets.invisiblePassword,
? Assets.visiblePassword
: Assets.invisiblePassword,
height: 15, height: 15,
width: 15, width: 15,
), ),
@ -383,10 +376,10 @@ class _LoginWebPageState extends State<LoginWebPage>
}, },
child: Text( child: Text(
"Forgot Password?", "Forgot Password?",
style: Theme.of(context).textTheme.bodySmall!.copyWith( style: Theme.of(context)
color: Colors.black, .textTheme
fontSize: 14, .bodySmall!
fontWeight: FontWeight.w400), .copyWith(color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400),
), ),
), ),
], ],
@ -450,8 +443,7 @@ class _LoginWebPageState extends State<LoginWebPage>
); );
} }
Widget _buildSignInButton( Widget _buildSignInButton(BuildContext context, AuthBloc loginBloc, Size size) {
BuildContext context, AuthBloc loginBloc, Size size) {
return Row( return Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -492,8 +484,7 @@ class _LoginWebPageState extends State<LoginWebPage>
SizedBox( SizedBox(
child: Text( child: Text(
loginBloc.validate, loginBloc.validate,
style: const TextStyle( style: const TextStyle(fontWeight: FontWeight.w700, color: ColorsManager.red),
fontWeight: FontWeight.w700, color: ColorsManager.red),
), ),
) )
], ],

View File

@ -0,0 +1,304 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class AccessDeviceTable extends StatefulWidget {
final List<String> headers;
final String? tableName;
final List<List<dynamic>> data;
final BoxDecoration? headerDecoration;
final BoxDecoration? cellDecoration;
final Size size;
final bool withCheckBox;
final bool withSelectAll;
final bool isEmpty;
final void Function(bool?)? selectAll;
final void Function(int, bool, dynamic)? onRowSelected;
final List<String>? initialSelectedIds;
final int uuidIndex;
const AccessDeviceTable({
super.key,
required this.headers,
required this.data,
required this.size,
this.tableName,
required this.isEmpty,
required this.withCheckBox,
required this.withSelectAll,
this.headerDecoration,
this.cellDecoration,
this.selectAll,
this.onRowSelected,
this.initialSelectedIds,
required this.uuidIndex,
});
@override
_DynamicTableState createState() => _DynamicTableState();
}
class _DynamicTableState extends State<AccessDeviceTable> {
late List<bool> _selected;
bool _selectAll = false;
@override
void initState() {
super.initState();
_initializeSelection();
}
@override
void didUpdateWidget(AccessDeviceTable oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.data != widget.data) {
_initializeSelection();
}
}
void _initializeSelection() {
if (widget.data.isEmpty) {
_selected = [];
_selectAll = false;
} else {
_selected = List<bool>.generate(widget.data.length, (index) {
// Check if the initialSelectedIds contains the deviceUuid
// uuidIndex is the index of the column containing the deviceUuid
final deviceUuid = widget.data[index][widget.uuidIndex];
return widget.initialSelectedIds != null &&
widget.initialSelectedIds!.contains(deviceUuid);
});
_selectAll = _selected.every((element) => element == true);
}
}
void _toggleRowSelection(int index) {
setState(() {
_selected[index] = !_selected[index];
if (widget.onRowSelected != null) {
widget.onRowSelected!(index, _selected[index], widget.data[index]);
}
});
}
void _toggleSelectAll(bool? value) {
setState(() {
_selectAll = value ?? false;
_selected = List<bool>.filled(widget.data.length, _selectAll);
if (widget.selectAll != null) {
widget.selectAll!(_selectAll);
}
});
}
@override
Widget build(BuildContext context) {
return Container(
decoration: widget.cellDecoration,
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SizedBox(
width: widget.size.width,
child: Column(
children: [
Container(
decoration: widget.headerDecoration ??
BoxDecoration(color: Colors.grey[200]),
child: Row(
children: [
if (widget.withCheckBox) _buildSelectAllCheckbox(),
...widget.headers
.map((header) => _buildTableHeaderCell(header)),
],
),
),
widget.isEmpty
? Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Column(
children: [
SvgPicture.asset(Assets.emptyTable),
const SizedBox(
height: 15,
),
Text(
// no password
widget.tableName == 'AccessManagement'
? 'No Password '
: 'No Devices',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor),
)
],
),
],
),
],
),
)
: Expanded(
child: Container(
color: Colors.white,
child: ListView.builder(
shrinkWrap: true,
itemCount: widget.data.length,
itemBuilder: (context, index) {
final row = widget.data[index];
return Row(
children: [
if (widget.withCheckBox)
_buildRowCheckbox(
index, widget.size.height * 0.10),
...row.map((cell) => _buildTableCell(
cell.toString(),
widget.size.height * 0.10)),
],
);
},
),
),
),
],
),
),
),
);
}
Widget _buildSelectAllCheckbox() {
return Container(
width: 50,
padding: const EdgeInsets.all(8.0),
decoration: const BoxDecoration(
border: Border.symmetric(
vertical: BorderSide(color: ColorsManager.boxDivider),
),
),
child: Checkbox(
value: widget.data.isNotEmpty &&
_selected.every((element) => element == true),
onChanged: widget.withSelectAll && widget.data.isNotEmpty
? _toggleSelectAll
: null,
),
);
}
Widget _buildRowCheckbox(int index, double size) {
return Container(
width: 50,
padding: const EdgeInsets.all(8.0),
height: size,
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: ColorsManager.boxDivider,
width: 1.0,
),
),
),
alignment: Alignment.centerLeft,
child: Center(
child: Checkbox(
value: _selected[index],
onChanged: (bool? value) {
_toggleRowSelection(index);
},
),
),
);
}
Widget _buildTableHeaderCell(String title) {
return Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border.symmetric(
vertical: BorderSide(color: ColorsManager.boxDivider),
),
),
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
title,
style: const TextStyle(
fontWeight: FontWeight.w400,
fontSize: 13,
color: Color(0xFF999999),
),
maxLines: 2,
),
),
),
);
}
Widget _buildTableCell(String content, double size) {
bool isBatteryLevel = content.endsWith('%');
double? batteryLevel;
if (isBatteryLevel) {
batteryLevel = double.tryParse(content.replaceAll('%', '').trim());
}
Color? statusColor;
switch (content) {
case 'Effective':
statusColor = ColorsManager.textGreen;
break;
case 'Expired':
statusColor = ColorsManager.red;
break;
case 'To be effective':
statusColor = ColorsManager.yaGreen;
break;
case 'Online':
statusColor = ColorsManager.green;
break;
case 'Offline':
statusColor = ColorsManager.red;
break;
default:
statusColor = Colors.black;
}
return Expanded(
child: Container(
height: size,
padding: const EdgeInsets.all(5.0),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide(
color: ColorsManager.boxDivider,
width: 1.0,
),
),
),
alignment: Alignment.centerLeft,
child: Text(
content,
style: TextStyle(
color: (batteryLevel != null && batteryLevel < 20)
? ColorsManager.red
: (batteryLevel != null && batteryLevel > 20)
? ColorsManager.green
: statusColor,
fontSize: 10,
fontWeight: FontWeight.w400),
maxLines: 2,
),
),
);
}
}

View File

@ -14,10 +14,9 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
int _lowBatteryCount = 0; int _lowBatteryCount = 0;
List<AllDevicesModel> _selectedDevices = []; List<AllDevicesModel> _selectedDevices = [];
List<AllDevicesModel> _filteredDevices = []; List<AllDevicesModel> _filteredDevices = [];
String productName = ''; String currentProductName = '';
String? currentCommunity; String? currentCommunity;
String? currentUnitName; String? currentUnitName;
String? currentProductName;
DeviceManagementBloc() : super(DeviceManagementInitial()) { DeviceManagementBloc() : super(DeviceManagementInitial()) {
on<FetchDevices>(_onFetchDevices); on<FetchDevices>(_onFetchDevices);
@ -77,14 +76,14 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
isControlButtonEnabled: _selectedDevices.isNotEmpty, isControlButtonEnabled: _selectedDevices.isNotEmpty,
)); ));
if (productName.isNotEmpty) { if (currentProductName.isNotEmpty) {
add(SearchDevices(productName: productName)); add(SearchDevices(productName: currentProductName));
} }
} }
} }
Future<void> _onResetFilters(ResetFilters event, Emitter<DeviceManagementState> emit) async { Future<void> _onResetFilters(ResetFilters event, Emitter<DeviceManagementState> emit) async {
productName = ''; currentProductName = '';
_selectedDevices.clear(); _selectedDevices.clear();
_filteredDevices = List.from(_devices); _filteredDevices = List.from(_devices);
_selectedIndex = 0; _selectedIndex = 0;
@ -238,20 +237,10 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
} }
void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) { void _onSearchDevices(SearchDevices event, Emitter<DeviceManagementState> emit) {
if (event.productName == currentProductName &&
event.community == currentCommunity &&
event.unitName == currentUnitName) {
return;
}
currentProductName = event.productName;
currentCommunity = event.community;
currentUnitName = event.unitName;
if ((event.community == null || event.community!.isEmpty) && if ((event.community == null || event.community!.isEmpty) &&
(event.unitName == null || event.unitName!.isEmpty) && (event.unitName == null || event.unitName!.isEmpty) &&
(event.productName == null || event.productName!.isEmpty)) { (event.productName == null || event.productName!.isEmpty)) {
productName = ''; currentProductName = '';
if (state is DeviceManagementFiltered) { if (state is DeviceManagementFiltered) {
add(FilterDevices(_getFilterFromIndex(_selectedIndex))); add(FilterDevices(_getFilterFromIndex(_selectedIndex)));
} else { } else {
@ -259,7 +248,17 @@ class DeviceManagementBloc extends Bloc<DeviceManagementEvent, DeviceManagementS
} }
} }
productName = event.productName ?? ''; if (event.productName == currentProductName &&
event.community == currentCommunity &&
event.unitName == currentUnitName &&
event.searchField) {
return;
}
currentProductName = event.productName ?? '';
currentCommunity = event.community;
currentUnitName = event.unitName;
List<AllDevicesModel> devicesToSearch = _filteredDevices; List<AllDevicesModel> devicesToSearch = _filteredDevices;
if (devicesToSearch.isNotEmpty) { if (devicesToSearch.isNotEmpty) {

View File

@ -31,11 +31,13 @@ class SearchDevices extends DeviceManagementEvent {
final String? community; final String? community;
final String? unitName; final String? unitName;
final String? productName; final String? productName;
final bool searchField;
const SearchDevices({ const SearchDevices({
this.community, this.community,
this.unitName, this.unitName,
this.productName, this.productName,
this.searchField = false,
}); });
@override @override

View File

@ -69,7 +69,8 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
context.read<DeviceManagementBloc>().add(SearchDevices( context.read<DeviceManagementBloc>().add(SearchDevices(
productName: productNameController.text, productName: productNameController.text,
unitName: unitNameController.text, unitName: unitNameController.text,
)); community: communityController.text,
searchField: true));
}, },
); );
} }
@ -81,7 +82,7 @@ class _DeviceSearchFiltersState extends State<DeviceSearchFilters> with HelperRe
community: communityController.text, community: communityController.text,
unitName: unitNameController.text, unitName: unitNameController.text,
productName: productNameController.text, productName: productNameController.text,
)); searchField: true));
}, },
onReset: () { onReset: () {
communityController.clear(); communityController.clear();

View File

@ -1,7 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/common/custom_table.dart'; import 'package:syncrow_web/pages/common/access_device_table.dart';
import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart'; import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart';
import 'package:syncrow_web/pages/common/buttons/default_button.dart'; import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
@ -49,7 +49,7 @@ class AddDeviceDialog extends StatelessWidget {
children: <Widget>[ children: <Widget>[
Container( Container(
width: size.width, width: size.width,
padding: EdgeInsets.all(15), padding: const EdgeInsets.all(15),
decoration: containerDecoration.copyWith( decoration: containerDecoration.copyWith(
color: ColorsManager.worningColor, color: ColorsManager.worningColor,
border: Border.all(color: Color(0xffFFD22F)), border: Border.all(color: Color(0xffFFD22F)),
@ -163,7 +163,7 @@ class AddDeviceDialog extends StatelessWidget {
Expanded( Expanded(
flex: 3, flex: 3,
child: state is TableLoaded child: state is TableLoaded
? DynamicTable( ? AccessDeviceTable(
uuidIndex: 1, uuidIndex: 1,
withSelectAll: true, withSelectAll: true,
initialSelectedIds: selectedDeviceIds, initialSelectedIds: selectedDeviceIds,