From 50ef283b520b1f48391f112d7ac1e8a849eb965b Mon Sep 17 00:00:00 2001 From: mohammad Date: Wed, 21 Aug 2024 09:22:31 +0300 Subject: [PATCH 01/10] password expired. --- .../access_management/bloc/access_bloc.dart | 2 +- .../view/access_management.dart | 2 +- lib/pages/auth/bloc/auth_bloc.dart | 5 ++++- .../view/add_device_dialog.dart | 6 +++++- .../visitor_password/view/repeat_widget.dart | 18 +++++++++--------- .../view/visitor_password_dialog.dart | 6 +++++- lib/utils/color_manager.dart | 2 +- 7 files changed, 26 insertions(+), 15 deletions(-) diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index 7c57bfa4..f586c56f 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -133,7 +133,7 @@ class AccessBloc extends Bloc { // Check if the password name should be used for filtering if (event.passwordName != null && event.passwordName!.isNotEmpty) { final bool matchesName = item.passwodName != null && - item.passwodName.contains(event.passwordName!); + item.passwodName.contains(event.passwordName); if (!matchesName) { matchesCriteria = false; } diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 55570324..e2f79429 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -151,7 +151,7 @@ class AccessManagementPage extends StatelessWidget { child: DefaultButton( onPressed: () { accessBloc.add(FilterDataEvent( - passwordName: accessBloc.passwordName.text, + passwordName: accessBloc.passwordName.text.toLowerCase(), startTime: accessBloc.effectiveTimeTimeStamp, endTime: accessBloc.expirationTimeTimeStamp )); diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart index bfd42eaf..2cc1a033 100644 --- a/lib/pages/auth/bloc/auth_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -85,6 +85,9 @@ class AuthBloc extends Bloc { } else if (response == "You entered wrong otp") { forgetValidate = 'Wrong one time password.'; emit(AuthInitialState()); + }else if (response == "OTP expired") { + forgetValidate = 'One time password has been expired.'; + emit(AuthInitialState()); } } catch (failure) { // forgetValidate='Invalid Credentials!'; @@ -92,7 +95,7 @@ class AuthBloc extends Bloc { // emit(FailureForgetState(error: failure.toString())); } } - +//925207 String? validateCode(String? value) { if (value == null || value.isEmpty) { return 'Code is required'; diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index 58e49182..7dc5407d 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -25,7 +25,11 @@ class AddDeviceDialog extends StatelessWidget { final visitorBloc = BlocProvider.of(context); return AlertDialog( backgroundColor: Colors.white, - title: const Text('Add Accessible Device'), + title: Text('Add Accessible Device', + style: Theme.of(context).textTheme.headlineLarge!.copyWith( + fontWeight: FontWeight.w400, + fontSize: 24, + color: Colors.black),), content: Container( height: MediaQuery.of(context).size.height/1.7, width: MediaQuery.of(context).size.width/2, diff --git a/lib/pages/visitor_password/view/repeat_widget.dart b/lib/pages/visitor_password/view/repeat_widget.dart index ecbd2b89..b04614fe 100644 --- a/lib/pages/visitor_password/view/repeat_widget.dart +++ b/lib/pages/visitor_password/view/repeat_widget.dart @@ -17,7 +17,7 @@ class RepeatWidget extends StatelessWidget { return BlocBuilder( builder: (context, state) { - final smartDoorBloc = BlocProvider.of(context); + final visitorBloc = BlocProvider.of(context); return Column( children: [ Container( @@ -25,7 +25,7 @@ class RepeatWidget extends StatelessWidget { height: size.height * 0.06, // Adjust height as needed child: ListView( scrollDirection: Axis.horizontal, - children: smartDoorBloc.days.map((day) { + children: visitorBloc.days.map((day) { return Container( width: size.width* 0.09, child: CheckboxListTile( @@ -33,15 +33,15 @@ class RepeatWidget extends StatelessWidget { day['day']!, style: TextStyle( fontSize: 18, - color: smartDoorBloc.selectedDays.contains(day['key']) + color: visitorBloc.selectedDays.contains(day['key']) ? Colors.black : ColorsManager.grayColor, ), ), - value: smartDoorBloc.selectedDays.contains(day['key']), + value: visitorBloc.selectedDays.contains(day['key']), onChanged: (bool? value) { if (value != null) { - smartDoorBloc.add(ToggleDaySelectionEvent(key: day['key']!)); + visitorBloc.add(ToggleDaySelectionEvent(key: day['key']!)); } }, ), @@ -56,19 +56,19 @@ class RepeatWidget extends StatelessWidget { title: '', size: size, endTime: () { - smartDoorBloc.add(SelectTimeVisitorPassword( + visitorBloc.add(SelectTimeVisitorPassword( isRepeat: true, context: context, isStart: false )); }, startTime: () { - smartDoorBloc.add(SelectTimeVisitorPassword( + visitorBloc.add(SelectTimeVisitorPassword( isRepeat: true, context: context, isStart: true )); }, - firstString: smartDoorBloc.repeatStartTime.toString(), - secondString: smartDoorBloc.repeatEndTime.toString(), + firstString: visitorBloc.repeatStartTime.toString(), + secondString: visitorBloc.repeatEndTime.toString(), ), ), diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index eadee6dc..e91ab834 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -26,7 +26,11 @@ class VisitorPasswordDialog extends StatelessWidget { bool isRepeat = state is IsRepeatState ? state.repeat : visitorBloc.repeat; return AlertDialog( backgroundColor: Colors.white, - title: const Text('Create visitor password'), + title: Text('Create visitor password', + style: Theme.of(context).textTheme.headlineLarge!.copyWith( + fontWeight: FontWeight.w400, + fontSize: 24, + color: Colors.black),), content: SingleChildScrollView( child: Form( key: visitorBloc.forgetFormKey, diff --git a/lib/utils/color_manager.dart b/lib/utils/color_manager.dart index 9b5b6d44..2ee12718 100644 --- a/lib/utils/color_manager.dart +++ b/lib/utils/color_manager.dart @@ -25,7 +25,7 @@ abstract class ColorsManager { static const Color blackColor = Color(0xFF000000); static const Color lightGreen = Color(0xFF00FF0A); static const Color grayColor = Color(0xFF999999); - static const Color red = Colors.red; + static const Color red = Color(0xFFFF0000); static const Color graysColor = Color(0xffEBEBEB); static const Color textGray = Color(0xffD5D5D5); static const Color btnColor = Color(0xFF00008B); From 4b7567a6fe01e241ec923f382397160f76dee0d5 Mon Sep 17 00:00:00 2001 From: mohammad Date: Wed, 21 Aug 2024 16:02:08 +0300 Subject: [PATCH 02/10] padding and text them --- lib/main.dart | 2 +- lib/pages/common/custom_web_textfield.dart | 24 +- lib/pages/common/date_time_widget.dart | 10 +- lib/pages/common/hour_picker_dialog.dart | 92 +++ .../bloc/visitor_password_bloc.dart | 269 ++++++--- .../bloc/visitor_password_event.dart | 22 +- .../bloc/visitor_password_state.dart | 1 + .../view/add_device_dialog.dart | 1 + .../visitor_password/view/repeat_widget.dart | 27 +- .../view/visitor_password_dialog.dart | 534 +++++++++++------- lib/services/access_mang_api.dart | 56 +- 11 files changed, 720 insertions(+), 318 deletions(-) create mode 100644 lib/pages/common/hour_picker_dialog.dart diff --git a/lib/main.dart b/lib/main.dart index dcabeaa2..c00a8da7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -59,7 +59,7 @@ class MyApp extends StatelessWidget { colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), // Set up color scheme useMaterial3: true, // Enable Material 3 ), - // home: AddDeviceDialog() + // home: VisitorPasswordDialog() home:isLoggedIn == 'Success' ? const HomePage() : const LoginPage(), )); } diff --git a/lib/pages/common/custom_web_textfield.dart b/lib/pages/common/custom_web_textfield.dart index 4ec0aa81..82fb86c9 100644 --- a/lib/pages/common/custom_web_textfield.dart +++ b/lib/pages/common/custom_web_textfield.dart @@ -37,19 +37,23 @@ class CustomWebTextField extends StatelessWidget { .bodyMedium! .copyWith(color: Colors.red), ), - Text(textFieldName), + Text(textFieldName, + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), ], ), const SizedBox(width: 10,), - Text( - description??'', // ' The password will be sent to the visitor’s email address.', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - fontSize: 9, - fontWeight: FontWeight.w400, - color: ColorsManager.textGray), + Expanded( + child: Text( + description??'', + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith( + fontSize: 9, + fontWeight: FontWeight.w400, + color: ColorsManager.textGray), + ), ), ], ), diff --git a/lib/pages/common/date_time_widget.dart b/lib/pages/common/date_time_widget.dart index ace2cf8d..f5034342 100644 --- a/lib/pages/common/date_time_widget.dart +++ b/lib/pages/common/date_time_widget.dart @@ -1,5 +1,6 @@ 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'; import 'package:syncrow_web/utils/style.dart'; @@ -39,7 +40,8 @@ class DateTimeWebWidget extends StatelessWidget { .bodyMedium! .copyWith(color: Colors.red), ), - Text(title??''), + Text(title??'' , style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), ], ), SizedBox(height: 8,), @@ -55,12 +57,14 @@ class DateTimeWebWidget extends StatelessWidget { children: [ InkWell( onTap: startTime, - child: Text(firstString) + child: Text(firstString, style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),) ), const Icon(Icons.arrow_right_alt), InkWell( onTap:endTime, - child: Text(secondString)), + child: Text(secondString, style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),)), SvgPicture.asset( Assets.calendarIcon, ), diff --git a/lib/pages/common/hour_picker_dialog.dart b/lib/pages/common/hour_picker_dialog.dart new file mode 100644 index 00000000..63e95e21 --- /dev/null +++ b/lib/pages/common/hour_picker_dialog.dart @@ -0,0 +1,92 @@ + + +import 'package:flutter/material.dart'; + +class HourPickerDialog extends StatefulWidget { + final TimeOfDay initialTime; + HourPickerDialog({required this.initialTime}); + + @override + _HourPickerDialogState createState() => _HourPickerDialogState(); +} + +class _HourPickerDialogState extends State { + late int _selectedHour; + bool _isPm = false; + + @override + void initState() { + super.initState(); + _selectedHour = widget.initialTime.hour > 12 ? widget.initialTime.hour - 12 : widget.initialTime.hour; + _isPm = widget.initialTime.period == DayPeriod.pm; + } + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: Text('Select Hour'), + content: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + DropdownButton( + value: _selectedHour, + items: List.generate(12, (index) { + int displayHour = index + 1; + return DropdownMenuItem( + value: displayHour, + child: Text(displayHour.toString()), + ); + }), + onChanged: (value) { + setState(() { + _selectedHour = value!; + }); + }, + ), + SizedBox(width: 16.0), + DropdownButton( + value: _isPm, + items: [ + DropdownMenuItem( + value: false, + child: Text('AM'), + ), + DropdownMenuItem( + value: true, + child: Text('PM'), + ), + ], + onChanged: (value) { + setState(() { + _isPm = value!; + }); + }, + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(null), + child: Text('Cancel'), + ), + TextButton( + onPressed: () { + int hour = _isPm ? _selectedHour + 12 : _selectedHour; + Navigator.of(context).pop(TimeOfDay(hour: hour, minute: 0)); + }, + child: Text('OK'), + ), + ], + ); + } +} + +Future showHourPicker({ + required BuildContext context, + required TimeOfDay initialTime, +}) { + return showDialog( + context: context, + builder: (context) => HourPickerDialog(initialTime: initialTime), + ); +} diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index d9f49e56..e620cc59 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -1,8 +1,8 @@ import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; +import 'package:syncrow_web/pages/common/hour_picker_dialog.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart'; import 'package:syncrow_web/pages/visitor_password/model/device_model.dart'; @@ -10,7 +10,8 @@ import 'package:syncrow_web/pages/visitor_password/model/schedule_model.dart'; import 'package:syncrow_web/services/access_mang_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; - List selectedDevices = []; + +List selectedDevices = []; // Define the BLoC class VisitorPasswordBloc @@ -30,7 +31,8 @@ class VisitorPasswordBloc on(postOfflineMultipleTimePassword); on(postOfflineOneTimePassword); - + on(selectTimeOfLinePassword); + on(changeTime); } final TextEditingController userNameController = TextEditingController(); final TextEditingController emailController = TextEditingController(); @@ -38,14 +40,14 @@ class VisitorPasswordBloc final TextEditingController deviceNameController = TextEditingController(); final TextEditingController deviceIdController = TextEditingController(); final TextEditingController unitNameController = TextEditingController(); - final TextEditingController virtualAddressController = TextEditingController(); - - + final TextEditingController virtualAddressController = + TextEditingController(); List data = []; List selectedDeviceIds = []; + String effectiveTime = 'Select Time'; - + String expirationTime = 'Select Time'; final forgetFormKey = GlobalKey(); @@ -61,12 +63,11 @@ class VisitorPasswordBloc int? repeatEffectiveTimeTimeStamp; int? repeatExpirationTimeTimeStamp; - String startTime = 'Start Time'; - String endTime = 'End Time'; + DateTime? startTime = DateTime.now(); + DateTime? endTime; - - String repeatStartTime = 'Start Time'; - String repeatEndTime = 'End Time'; + String startTimeAccess = 'Start Time'; + String endTimeAccess = 'End Time'; // DateTime? repeatStartTime=DateTime.now(); // DateTime? repeatEndTime; @@ -85,13 +86,15 @@ class VisitorPasswordBloc Future selectTimeVisitorPassword( SelectTimeVisitorPassword event, - Emitter emit) async { + Emitter emit, + ) async { final DateTime? picked = await showDatePicker( context: event.context, initialDate: DateTime.now(), firstDate: DateTime(2015, 8), lastDate: DateTime(3101), ); + if (picked != null) { final TimeOfDay? timePicked = await showTimePicker( context: event.context, @@ -113,6 +116,7 @@ class VisitorPasswordBloc ); }, ); + if (timePicked != null) { final selectedDateTime = DateTime( picked.year, @@ -121,49 +125,39 @@ class VisitorPasswordBloc timePicked.hour, timePicked.minute, ); - final selectedTimestamp = DateTime( - selectedDateTime.year, - selectedDateTime.month, - selectedDateTime.day, - selectedDateTime.hour, - selectedDateTime.minute, - ).millisecondsSinceEpoch ~/ - 1000; // Divide by 1000 to remove milliseconds - if (event.isStart) { - if (expirationTimeTimeStamp != null && selectedTimestamp >expirationTimeTimeStamp!) { - CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.'); - } else { - if(event.isRepeat==true) - {repeatStartTime = selectedDateTime.toString().split('.').first;} - else // Remove seconds and milliseconds - {startTime = selectedDateTime.toString().split('.').first;} - effectiveTimeTimeStamp = selectedTimestamp; - emit(ChangeTimeState()); + final selectedTimestamp = selectedDateTime.millisecondsSinceEpoch ~/ 1000; + + if (event.isStart) { + if (expirationTimeTimeStamp != null && + selectedTimestamp > expirationTimeTimeStamp!) { + CustomSnackBar.displaySnackBar( + 'Effective Time cannot be later than Expiration Time.', + ); + return; } - emit(ChangeTimeState()); + effectiveTimeTimeStamp = selectedTimestamp; + + startTimeAccess = selectedDateTime.toString().split('.').first; + } else { if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { - CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.'); - } else { - if(event.isRepeat==true) - {repeatEndTime = selectedDateTime.toString().split('.').first;} - else - {endTime = selectedDateTime.toString().split('.').first;} - expirationTimeTimeStamp = selectedTimestamp; - emit(ChangeTimeState()); - + CustomSnackBar.displaySnackBar( + 'Expiration Time cannot be earlier than Effective Time.', + ); + return; } - emit(ChangeTimeState()); + expirationTimeTimeStamp = selectedTimestamp; + + endTimeAccess = selectedDateTime.toString().split('.').first; - emit(VisitorPasswordInitial()); } + + emit(ChangeTimeState()); + emit(VisitorPasswordInitial()); } } - - // emit(AccessInitial()); - // emit(TableLoaded(data)); } bool toggleRepeat( @@ -212,17 +206,24 @@ class VisitorPasswordBloc //online password - Future postOnlineOneTimePassword( - OnlineOneTimePasswordEvent event, + Future postOnlineOneTimePassword(OnlineOneTimePasswordEvent event, Emitter emit) async { try { + generate7DigitNumber(); + print('selectedDevices$selectedDevices'); // emit(DeviceLoaded()); - await AccessMangApi().postOnlineOneTime( + bool res = await AccessMangApi().postOnlineOneTime( email: event.email, + password: passwordController, devicesUuid: selectedDevices, - passwordName: event.passwordName); - // emit(TableLoaded(data)); + passwordName: event.passwordName, + effectiveTime: effectiveTimeTimeStamp.toString(), + invalidTime: expirationTimeTimeStamp.toString()); + if (res = true) { + Navigator.pop(event.context!); + } + emit(TableLoaded(data)); } catch (e) { emit(FailedState(e.toString())); } @@ -233,33 +234,31 @@ class VisitorPasswordBloc Emitter emit) async { try { generate7DigitNumber(); - // emit(DeviceLoaded()); - await AccessMangApi().postOnlineMultipleTime( - scheduleList:[ - // if (repeat) - // Schedule( - // effectiveTime: getTimeOnly(repeatStartTime), - // invalidTime: getTimeOnly(repeatEndTime).toString(), - // workingDay: selectedDays, - // ), - ] , + bool res = await AccessMangApi().postOnlineMultipleTime( + scheduleList: [ + if (repeat) + Schedule( + effectiveTime: getTimeFromDateTimeString(expirationTime), + invalidTime: getTimeFromDateTimeString(effectiveTime).toString(), + workingDay: selectedDays, + ), + ], password: passwordController, - invalidTime:event.invalidTime , - effectiveTime:event.effectiveTime , + invalidTime: expirationTimeTimeStamp.toString(), + effectiveTime: effectiveTimeTimeStamp.toString(), email: event.email, devicesUuid: selectedDevices, - passwordName: event.passwordName - ); - // emit(TableLoaded(data)); + passwordName: event.passwordName); + if(res==true){ + Navigator.pop(event.context!); + } } catch (e) { emit(FailedState(e.toString())); } } - //offline password - Future postOfflineOneTimePassword( - OfflineOneTimePasswordEvent event, + Future postOfflineOneTimePassword(OfflineOneTimePasswordEvent event, Emitter emit) async { try { generate7DigitNumber(); @@ -267,8 +266,7 @@ class VisitorPasswordBloc await AccessMangApi().postOffLineOneTime( email: event.email, devicesUuid: selectedDevices, - passwordName: event.passwordName - ); + passwordName: event.passwordName); // emit(TableLoaded(data)); } catch (e) { emit(FailedState(e.toString())); @@ -285,16 +283,14 @@ class VisitorPasswordBloc email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName, - invalidTime:event.invalidTime , - effectiveTime:event.effectiveTime - ); + invalidTime: event.invalidTime, + effectiveTime: event.effectiveTime); // emit(TableLoaded(data)); } catch (e) { emit(FailedState(e.toString())); } } - void selectDevice( SelectDeviceEvent event, Emitter emit) { if (selectedDeviceIds.contains(event.deviceId)) { @@ -302,8 +298,6 @@ class VisitorPasswordBloc } else { selectedDeviceIds.add(event.deviceId); } - selectedDevices=selectedDeviceIds; - print(selectedDevices); } String? validate(String? value) { @@ -313,10 +307,9 @@ class VisitorPasswordBloc return null; } - Future generate7DigitNumber() async { emit(LoadingInitialState()); - passwordController=''; + passwordController = ''; Random random = Random(); int min = 1000000; int max = 9999999; @@ -324,12 +317,12 @@ class VisitorPasswordBloc emit(GeneratePasswordState()); return passwordController; } + String getTimeOnly(DateTime? dateTime) { if (dateTime == null) return ''; return DateFormat('HH:mm').format(dateTime); } - void filterDevices() { final deviceName = deviceNameController.text.toLowerCase(); final deviceId = deviceIdController.text.toLowerCase(); @@ -340,14 +333,16 @@ class VisitorPasswordBloc final matchesDeviceId = device.uuid.toLowerCase().contains(deviceId); // final matchesUnitName = device.unitName.toLowerCase().contains(unitName); // Assuming unitName is a property of the device - return matchesDeviceName && matchesDeviceId ; + return matchesDeviceName && matchesDeviceId; }).toList(); // emit(TableLoaded(filteredData)); - add(UpdateFilteredDevicesEvent(filteredData)); + add(UpdateFilteredDevicesEvent(filteredData)); } + @override - Stream mapEventToState(VisitorPasswordEvent event) async* { + Stream mapEventToState( + VisitorPasswordEvent event) async* { if (event is FetchDevice) { // Fetching logic... } else if (event is UpdateFilteredDevicesEvent) { @@ -355,7 +350,113 @@ class VisitorPasswordBloc } } - void _onUpdateFilteredDevices(UpdateFilteredDevicesEvent event, Emitter emit) { + void _onUpdateFilteredDevices( + UpdateFilteredDevicesEvent event, Emitter emit) { emit(TableLoaded(event.filteredData)); } + + addDeviceToList() { + selectedDevices = selectedDeviceIds; + print(selectedDevices); + } + + Future selectTimeOfLinePassword(SelectTimeEvent event, Emitter emit) async { + emit(ChangeTimeState()); + final DateTime? picked = await showDatePicker( + context: event.context, + initialDate: DateTime.now(), + firstDate: DateTime.now(), + lastDate: DateTime(3101), + ); + if (picked != null) { + final TimeOfDay? timePicked = await showHourPicker( + context: event.context, + initialTime: TimeOfDay.now(), + ); + if (timePicked != null) { + final selectedDateTime = DateTime( + picked.year, + picked.month, + picked.day, + timePicked.hour, + 0, + ); + final selectedTimestamp = DateTime( + selectedDateTime.year, + selectedDateTime.month, + selectedDateTime.day, + selectedDateTime.hour, + selectedDateTime.minute, + ).millisecondsSinceEpoch ~/ + 1000; // Divide by 1000 to remove milliseconds + if (event.isEffective) { + if (expirationTimeTimeStamp != null && + selectedTimestamp > expirationTimeTimeStamp!) { + CustomSnackBar.displaySnackBar( + 'Effective Time cannot be later than Expiration Time.'); + } else { + effectiveTime = selectedDateTime + .toString() + .split('.') + .first; // Remove seconds and milliseconds + effectiveTimeTimeStamp = selectedTimestamp; + } + } else { + if (effectiveTimeTimeStamp != null && + selectedTimestamp < effectiveTimeTimeStamp!) { + CustomSnackBar.displaySnackBar( + 'Expiration Time cannot be earlier than Effective Time.'); + } else { + expirationTime = selectedDateTime + .toString() + .split('.') + .first; // Remove seconds and milliseconds + expirationTimeTimeStamp = selectedTimestamp; + } + } + print('effectiveTime=$effectiveTime'); + print('expirationTime=$expirationTime'); + + print('expirationTimeTimeStamp=$expirationTimeTimeStamp'); + print('effectiveTimeTimeStamp=$effectiveTimeTimeStamp'); + emit(TimeSelectedState()); + } + } + } + + changeTime(ChangeTimeEvent event, Emitter emit) { + if (event.isStartEndTime == true) { + startTime = event.val; + } else { + endTime = event.val; + } + } + DateTime? convertStringToDateTime(String dateTimeString) { + try { + // Define the input format. Adjust this pattern based on your input string format. + final DateFormat inputFormat = DateFormat('yyyy-MM-dd HH:mm:ss'); + // Convert the string to a DateTime object. + DateTime dateTime = inputFormat.parse(dateTimeString); + return dateTime; + } catch (e) { + print("Error parsing date: $e"); + return null; + } + } + + String getTimeFromDateTimeString(String dateTimeString) { + DateTime? dateTime = convertStringToDateTime(dateTimeString); + if (dateTime == null) return ''; + + // Extract the time component from the DateTime object. + return DateFormat('HH:mm').format(dateTime); + } + + String? validateEmail(String? value) { + if (!RegExp(r'^[^@]+@[^@]+\.[^@]+').hasMatch(value!)) { + return ''; + } + return null; + } + } diff --git a/lib/pages/visitor_password/bloc/visitor_password_event.dart b/lib/pages/visitor_password/bloc/visitor_password_event.dart index 9990ad9a..723ac052 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_event.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_event.dart @@ -57,8 +57,9 @@ class FetchDevice extends VisitorPasswordEvent {} class OnlineOneTimePasswordEvent extends VisitorPasswordEvent { final String? email; final String? passwordName; + final BuildContext? context; - const OnlineOneTimePasswordEvent({this.email,this.passwordName}); + const OnlineOneTimePasswordEvent({this.email,this.passwordName,this.context}); @override List get props => [email!,passwordName!,]; @@ -68,9 +69,10 @@ class OnlineMultipleTimePasswordEvent extends VisitorPasswordEvent { final String? passwordName; final String? invalidTime; final String? effectiveTime; - const OnlineMultipleTimePasswordEvent({this.email,this.passwordName,this.invalidTime,this.effectiveTime}); + final BuildContext? context; + const OnlineMultipleTimePasswordEvent({this.email,this.passwordName,this.invalidTime,this.effectiveTime,this.context}); @override - List get props => [email!,passwordName!,invalidTime!,effectiveTime!]; + List get props => [email!,passwordName!,invalidTime!,effectiveTime!,context!]; } //offline password @@ -115,4 +117,18 @@ class UpdateFilteredDevicesEvent extends VisitorPasswordEvent { final List filteredData; UpdateFilteredDevicesEvent(this.filteredData); +}class SelectTimeEvent extends VisitorPasswordEvent { + final BuildContext context; + final bool isEffective; + const SelectTimeEvent({required this.context,required this.isEffective}); + @override + List get props => [context,isEffective]; +} +class ChangeTimeEvent extends VisitorPasswordEvent { + final dynamic val; + final bool isStartEndTime; + + const ChangeTimeEvent({required this.val,required this.isStartEndTime}); + @override + List get props => [val,isStartEndTime]; } \ No newline at end of file diff --git a/lib/pages/visitor_password/bloc/visitor_password_state.dart b/lib/pages/visitor_password/bloc/visitor_password_state.dart index 374433af..27008a30 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_state.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_state.dart @@ -41,6 +41,7 @@ class IsRepeatState extends VisitorPasswordState { class LoadingInitialState extends VisitorPasswordState {} class ChangeTimeState extends VisitorPasswordState {} +class TimeSelectedState extends VisitorPasswordState {} class DeviceLoaded extends VisitorPasswordState {} class GeneratePasswordState extends VisitorPasswordState {} diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index 7dc5407d..844e0ca9 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -207,6 +207,7 @@ class AddDeviceDialog extends StatelessWidget { width: size.width * 0.2, child: DefaultButton( onPressed: () { + visitorBloc.addDeviceToList(); Navigator.of(context).pop(); // Close the dialog }, borderRadius: 8, diff --git a/lib/pages/visitor_password/view/repeat_widget.dart b/lib/pages/visitor_password/view/repeat_widget.dart index b04614fe..73770100 100644 --- a/lib/pages/visitor_password/view/repeat_widget.dart +++ b/lib/pages/visitor_password/view/repeat_widget.dart @@ -56,19 +56,26 @@ class RepeatWidget extends StatelessWidget { title: '', size: size, endTime: () { - visitorBloc.add(SelectTimeVisitorPassword( - isRepeat: true, - context: context, isStart: false - )); + print('sadasd'); + visitorBloc.add(SelectTimeEvent( + context: context, + isEffective: false)); + new Future.delayed(const Duration(milliseconds: 500), () { + visitorBloc.add(ChangeTimeEvent(val: visitorBloc.endTime, isStartEndTime: true)); + + }); + + }, startTime: () { - visitorBloc.add(SelectTimeVisitorPassword( - isRepeat: true, - context: context, isStart: true - )); + new Future.delayed(const Duration(milliseconds: 500), () { + visitorBloc.add(ChangeTimeEvent(val: visitorBloc.endTime, isStartEndTime: true)); + }); + visitorBloc.add(SelectTimeEvent(context: context, isEffective: true)); + }, - firstString: visitorBloc.repeatStartTime.toString(), - secondString: visitorBloc.repeatEndTime.toString(), + firstString:visitorBloc.effectiveTime , + secondString: visitorBloc.expirationTime , ), ), diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index e91ab834..2299877f 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -1,6 +1,7 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_web/pages/common/custom_web_textfield.dart'; import 'package:syncrow_web/pages/common/date_time_widget.dart'; import 'package:syncrow_web/pages/common/default_button.dart'; @@ -10,6 +11,8 @@ import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.d import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart'; import 'package:syncrow_web/pages/visitor_password/view/add_device_dialog.dart'; import 'package:syncrow_web/pages/visitor_password/view/repeat_widget.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/style.dart'; class VisitorPasswordDialog extends StatelessWidget { @@ -23,19 +26,22 @@ class VisitorPasswordDialog extends StatelessWidget { child: BlocBuilder( builder: (BuildContext context, VisitorPasswordState state) { final visitorBloc = BlocProvider.of(context); - bool isRepeat = state is IsRepeatState ? state.repeat : visitorBloc.repeat; + bool isRepeat = + state is IsRepeatState ? state.repeat : visitorBloc.repeat; return AlertDialog( backgroundColor: Colors.white, - title: Text('Create visitor password', - style: Theme.of(context).textTheme.headlineLarge!.copyWith( - fontWeight: FontWeight.w400, - fontSize: 24, - color: Colors.black),), + title: Text( + 'Create visitor password', + style: Theme.of(context).textTheme.headlineLarge!.copyWith( + fontWeight: FontWeight.w400, + fontSize: 24, + color: Colors.black), + ), content: SingleChildScrollView( child: Form( key: visitorBloc.forgetFormKey, child: Padding( - padding: const EdgeInsets.all(10.0), + padding: const EdgeInsets.all(5.0), child: ListBody( children: [ Container( @@ -55,18 +61,21 @@ class VisitorPasswordDialog extends StatelessWidget { Expanded( flex: 2, child: CustomWebTextField( - validator: visitorBloc.validate, + validator: visitorBloc.validateEmail, controller: visitorBloc.emailController, isRequired: true, textFieldName: 'Email Address', - description: 'The password will be sent to the visitor’s email address.', + description: + 'The password will be sent to the visitor’s email address.', ), ), const Spacer(), ], ), ), - SizedBox(height: 20,), + const SizedBox( + height: 15, + ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -79,7 +88,9 @@ class VisitorPasswordDialog extends StatelessWidget { .bodyMedium! .copyWith(color: Colors.red), ), - const Text('Access Type'), + Text('Access Type', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), ], ), Row( @@ -87,7 +98,10 @@ class VisitorPasswordDialog extends StatelessWidget { SizedBox( width: size.width * 0.15, child: RadioListTile( - title: const Text('Online Password'), + title: Text('Online Password', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13), + ), value: 'Online Password', groupValue: (state is PasswordTypeSelected) ? state.selectedType @@ -95,16 +109,19 @@ class VisitorPasswordDialog extends StatelessWidget { onChanged: (String? value) { if (value != null) { print(value); - context.read().add(SelectPasswordType(value)); + context + .read() + .add(SelectPasswordType(value)); } }, ), ), - SizedBox( width: size.width * 0.15, child: RadioListTile( - title: const Text('Offline Password'), + title: Text('Offline Password', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), value: 'Offline Password', groupValue: (state is PasswordTypeSelected) ? state.selectedType @@ -113,36 +130,146 @@ class VisitorPasswordDialog extends StatelessWidget { if (value != null) { print(value); - context.read().add(SelectPasswordType(value)); + context + .read() + .add(SelectPasswordType(value)); } }, ), ), - SizedBox( width: size.width * 0.15, child: RadioListTile( - title: const Text('Dynamic Password'), + title: Text('Dynamic Password', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), value: 'Dynamic Password', groupValue: (state is PasswordTypeSelected) ? state.selectedType : visitorBloc.accessTypeSelected, onChanged: (String? value) { if (value != null) { - context.read().add(SelectPasswordType(value)); - visitorBloc.usageFrequencySelected=''; + context + .read() + .add(SelectPasswordType(value)); + visitorBloc.usageFrequencySelected = ''; } }, ), ), ], ), - const Text('Only currently online devices can be selected. It is recommended to use when the device network is stable, and the system randomly generates a digital password'), - const SizedBox(height: 20,) + Text( + 'Only currently online devices can be selected. It is recommended to use when the device network is stable, and the system randomly generates a digital password', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.grayColor,fontSize: 9),), + const SizedBox( + height: 20, + ) ], ), - visitorBloc.accessTypeSelected=='Dynamic Password' ? - SizedBox(): + visitorBloc.accessTypeSelected == 'Dynamic Password' + ? SizedBox() + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text( + '* ', + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Colors.red), + ), + Text('Usage Frequency',style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), + ], + ), + Row( + children: [ + SizedBox( + width: 200, + child: RadioListTile( + title: Text('One-Time',style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), + value: 'One-Time', + groupValue: + (state is UsageFrequencySelected) + ? state.selectedFrequency + : visitorBloc + .usageFrequencySelected, + onChanged: (String? value) { + if (value != null) { + print(value); + + context + .read() + .add(SelectUsageFrequency( + value)); + } + }, + ), + ), + SizedBox( + width: 200, + child: RadioListTile( + title: Text('Periodic', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), + value: 'Periodic', + groupValue: + (state is UsageFrequencySelected) + ? state.selectedFrequency + : visitorBloc + .usageFrequencySelected, + onChanged: (String? value) { + if (value != null) { + context + .read() + .add(SelectUsageFrequency( + value)); + } + }, + ), + ), + ], + ), + Text('Within the validity period, each device can be unlocked only once.', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor,fontSize: 9),) + ], + ), + const SizedBox( + height: 20, + ), + if ((visitorBloc.usageFrequencySelected != 'One-Time' || + visitorBloc.accessTypeSelected != + 'Offline Password') && + (visitorBloc.usageFrequencySelected != '')) + DateTimeWebWidget( + isRequired: true, + title: 'Access Period', + size: size, + endTime: () { + visitorBloc.add(SelectTimeVisitorPassword( + context: context, + isStart: false, + isRepeat: false)); + }, + startTime: () { + visitorBloc.add(SelectTimeVisitorPassword( + context: context, + isStart: true, + isRepeat: false)); + }, + firstString: visitorBloc.startTimeAccess.toString(), + secondString: visitorBloc.endTimeAccess.toString(), + ), + const SizedBox( + height: 20, + ), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ @@ -155,111 +282,47 @@ class VisitorPasswordDialog extends StatelessWidget { .bodyMedium! .copyWith(color: Colors.red), ), - const Text('Usage Frequency'), + Text('Access Devices', style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), ], ), - Row( - children: [ - SizedBox( - width: 200, - child: RadioListTile( - title: const Text('One-Time'), - value: 'One-Time', - groupValue: (state is UsageFrequencySelected) - ? state.selectedFrequency - : visitorBloc.usageFrequencySelected, - onChanged: (String? value) { - if (value != null) { - print(value); - - context.read().add(SelectUsageFrequency(value)); - } - }, - ), - ), - SizedBox( - width: 200, - child: RadioListTile( - title: const Text('Periodic'), - value: 'Periodic', - groupValue: (state is UsageFrequencySelected) - ? state.selectedFrequency - : visitorBloc.usageFrequencySelected, - onChanged: (String? value) { - if (value != null) { - context.read().add(SelectUsageFrequency(value)); - } - }, - ), - ), - ], + Text( + 'Within the validity period, each device can be unlocked only once.',style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.grayColor,fontSize: 9),), + const SizedBox( + height: 20, ), - - const Text('Within the validity period, each device can be unlocked only once.') - ], - ), - const SizedBox(height: 20,), - if((visitorBloc.usageFrequencySelected!='One-Time'||visitorBloc.accessTypeSelected!='Offline Password')&&(visitorBloc.usageFrequencySelected!='')) - DateTimeWebWidget( - - isRequired: true, - title: 'Access Period', - size: size, - endTime: () { - visitorBloc.add(SelectTimeVisitorPassword( - context: context, isStart: false,isRepeat:false)); - }, - startTime: () { - visitorBloc.add(SelectTimeVisitorPassword( - context: context, isStart: true,isRepeat:false)); - }, - firstString: visitorBloc.startTime, - secondString: visitorBloc.endTime, - ), - - const SizedBox(height: 20,), - - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - '* ', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Colors.red), - ), - const Text('Access Devices'), - ], - ), - const Text('Within the validity period, each device can be unlocked only once.'), - const SizedBox(height: 20,), - if(visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Online Password') - SizedBox( - width: 100, - child: ListTile( - contentPadding: EdgeInsets.zero, - leading: const Text('Repeat'), - trailing: Transform.scale( - scale: .8, - child: CupertinoSwitch( - value: visitorBloc.repeat, - onChanged: (value) { - visitorBloc.add(ToggleRepeatEvent()); - }, - applyTheme: true, + if (visitorBloc.usageFrequencySelected == + 'Periodic' && + visitorBloc.accessTypeSelected == + 'Online Password') + SizedBox( + width: 100, + child: ListTile( + contentPadding: EdgeInsets.zero, + leading: const Text('Repeat'), + trailing: Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: visitorBloc.repeat, + onChanged: (value) { + visitorBloc.add(ToggleRepeatEvent()); + }, + applyTheme: true, + ), ), ), ), - ), - if(visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Online Password') + if (visitorBloc.usageFrequencySelected == + 'Periodic' && + visitorBloc.accessTypeSelected == + 'Online Password') isRepeat ? const RepeatWidget() : const SizedBox(), Container( decoration: containerDecoration, - width: size.width * 0.1, - child: DefaultButton( + width: size.width * 0.08, + child: DefaultButton( onPressed: () { showDialog( context: context, @@ -270,12 +333,13 @@ class VisitorPasswordDialog extends StatelessWidget { ); }, borderRadius: 8, - child: Text('+ Add Device'), + child: Text('+ Add Device',style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.whiteColors,fontSize: 12),), ), ), ], ), - ], ), ), @@ -294,88 +358,176 @@ class VisitorPasswordDialog extends StatelessWidget { backgroundColor: Colors.white, child: Text( 'Cancel', - style: Theme.of(context).textTheme.bodyMedium!, + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.blackColor,fontSize: 16), ), ), ), Container( decoration: containerDecoration, width: size.width * 0.2, - child: DefaultButton( + child: DefaultButton( onPressed: () { - if(visitorBloc.forgetFormKey.currentState!.validate()){ - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return InfoDialog( - size: size, - title: 'Set Password', - content: 'This action will update all of the selected\n door locks passwords in the property.\n\nAre you sure you want to continue?', + print(selectedDevices); + if (visitorBloc.forgetFormKey.currentState!.validate()) { + if (selectedDevices.toString() != '[]') { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return InfoDialog( + size: size, + title: 'Set Password', + content: + 'This action will update all of the selected\n door locks passwords in the property.\n\nAre you sure you want to continue?', + actions: [ + Container( + decoration: containerDecoration, + width: size.width * 0.1, + child: DefaultButton( + borderRadius: 8, + onPressed: () { + Navigator.of(context) + .pop(); // Close the dialog + }, + backgroundColor: Colors.white, + child: Text( + 'Cancel', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.blackColor,fontSize: 16), + ), + ), + ), + Container( + decoration: containerDecoration, + width: size.width * 0.1, + child: DefaultButton( + borderRadius: 8, + onPressed: () { + if (visitorBloc.usageFrequencySelected == + 'One-Time' && + visitorBloc.accessTypeSelected == + 'Online Password') { + visitorBloc.add( + OnlineOneTimePasswordEvent( + context: context, + passwordName: visitorBloc + .userNameController.text, + email: visitorBloc + .emailController.text)); + } else if (visitorBloc + .usageFrequencySelected == + 'Periodic' && + visitorBloc.accessTypeSelected == + 'Online Password') { + visitorBloc.add( + OnlineMultipleTimePasswordEvent( + passwordName: + visitorBloc + .userNameController + .text, + email: + visitorBloc + .emailController.text, + effectiveTime: visitorBloc + .effectiveTimeTimeStamp + .toString(), + invalidTime: visitorBloc + .expirationTimeTimeStamp + .toString())); + } else if (visitorBloc + .usageFrequencySelected == + 'One-Time' && + visitorBloc.accessTypeSelected == + 'Offline Password') { + visitorBloc + .add(OfflineOneTimePasswordEvent( + passwordName: visitorBloc + .userNameController.text, + email: + visitorBloc.emailController.text, + )); + } else if (visitorBloc + .usageFrequencySelected == + 'Periodic' && + visitorBloc.accessTypeSelected == + 'Offline Password') { + visitorBloc.add( + OfflineMultipleTimePasswordEvent( + passwordName: visitorBloc + .userNameController.text, + email: visitorBloc + .emailController.text, + effectiveTime: visitorBloc + .effectiveTimeTimeStamp + .toString(), + invalidTime: visitorBloc + .expirationTimeTimeStamp + .toString())); + } + }, + child: const Text( + 'Ok', + ), + ), + ), + ], + ); + }, + ); + } else { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return AlertDialog( + alignment: Alignment.center, + content: SizedBox( + height: size!.height * 0.15, + child: Column( + children: [ + SizedBox( + child: SvgPicture.asset( + Assets.deviceNoteIcon, + height: 35, + width: 35, + ), + ), - actions: [ - Container( - decoration: containerDecoration, - width: size.width * 0.1, - child: DefaultButton( - borderRadius: 8, - onPressed: () { - Navigator.of(context).pop(); // Close the dialog - }, - backgroundColor: Colors.white, - child: Text( - 'Cancel', - style: Theme.of(context).textTheme.bodyMedium!, - ), + const SizedBox( + width: 15, + ), + Text( + 'Please select devices to continue', + style: Theme.of(context) + .textTheme + .headlineLarge! + .copyWith( + fontSize: 20, + fontWeight: FontWeight.w400, + color: Colors.black), + ), + ], ), ), - Container( - decoration: containerDecoration, - width: size.width * 0.1, - child: DefaultButton( - borderRadius: 8, + actionsAlignment: MainAxisAlignment.center, + actions: [ + TextButton( onPressed: () { - if(visitorBloc.usageFrequencySelected=='One-Time'&&visitorBloc.accessTypeSelected=='Online Password'){ - visitorBloc.add(OnlineOneTimePasswordEvent( - passwordName:visitorBloc.userNameController.text , - email: visitorBloc.emailController.text - ) - ); - } - else if(visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Online Password') { - visitorBloc.add(OnlineMultipleTimePasswordEvent( - passwordName:visitorBloc.userNameController.text , - email: visitorBloc.emailController.text, - effectiveTime:visitorBloc.effectiveTimeTimeStamp.toString() , - invalidTime:visitorBloc.expirationTimeTimeStamp.toString() - ) - ); - } - else if(visitorBloc.usageFrequencySelected=='One-Time'&&visitorBloc.accessTypeSelected=='Offline Password') { - visitorBloc.add(OfflineOneTimePasswordEvent( - passwordName:visitorBloc.userNameController.text , - email: visitorBloc.emailController.text, - ) - ); - } - else if(visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Offline Password') { - visitorBloc.add(OfflineMultipleTimePasswordEvent( - passwordName:visitorBloc.userNameController.text , - email: visitorBloc.emailController.text, - effectiveTime:visitorBloc.effectiveTimeTimeStamp.toString() , - invalidTime:visitorBloc.expirationTimeTimeStamp.toString() - ) - ); - } + Navigator.of(context).pop(); }, - child: const Text( - 'Ok', - ), + child: Text('OK', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.whiteColors,fontSize: 16),), ), - ), - ],); - }, - ); + ], + ); + }, + ); + } } }, borderRadius: 8, diff --git a/lib/services/access_mang_api.dart b/lib/services/access_mang_api.dart index 38730553..26d7eeea 100644 --- a/lib/services/access_mang_api.dart +++ b/lib/services/access_mang_api.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:syncrow_web/pages/access_management/model/password_model.dart'; import 'package:syncrow_web/pages/visitor_password/model/schedule_model.dart'; @@ -51,15 +52,24 @@ class AccessMangApi{ } } - Future postOnlineOneTime({String? email,String? passwordName,List? devicesUuid}) async { + Future postOnlineOneTime({ + String? email, + String? passwordName, + String? password, + String? effectiveTime, + String? invalidTime, + List? devicesUuid}) async { try { print('postOfflineOneTime List: ${ - { + jsonEncode({ "email": email, "passwordName": passwordName, - "devicesUuid": devicesUuid - } + "password": password, + "devicesUuid": devicesUuid, + "effectiveTime":effectiveTime , + "invalidTime": invalidTime + }) }'); final response = await HTTPService().post( @@ -67,18 +77,27 @@ class AccessMangApi{ body: jsonEncode({ "email": email, "passwordName": passwordName, - "devicesUuid": devicesUuid + "password": password, + "devicesUuid": devicesUuid, + "effectiveTime":effectiveTime , + "invalidTime": invalidTime }), showServerMessage: true, expectedResponseModel: (json) { - List jsonData = json; print('postOfflineOneTime List: $json'); + if(json['statusCode'].toString()=='201'){ + return true; + }else{ + return false; + } }, ); return response; - } catch (e) { - debugPrint('Error fetching $e'); - return []; + } on DioException catch (e) { + debugPrint('Error: ${e.message}'); + + debugPrint('Error fetching ${e.response!.statusMessage}'); + return false; } } @@ -99,25 +118,30 @@ class AccessMangApi{ "effectiveTime": effectiveTime, "invalidTime": invalidTime, }; - print('createPassword =${scheduleList![0].workingDay}'); if (scheduleList != null) { body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList(); } - print('createPassword =$body'); + print('createPassword =${jsonEncode(body)}'); final response = await HTTPService().post( path: ApiEndpoints.sendOnlineMultipleTime, body: jsonEncode(body), showServerMessage: true, expectedResponseModel: (json) { - List jsonData = json; - print('postOfflineOneTime List: $json'); + print('createPassword =${json}'); + + if(json['data']['successOperations'][0]['success'].toString()=='true'){ + return true; + }else{ + return false; + } }, ); return response; - } catch (e) { - debugPrint('Error fetching $e'); - return []; + } on DioException catch (e){ + debugPrint('Error fetching ${e.type.name}'); + debugPrint('Error fetching ${e.response!.statusMessage}'); + return false; } } From e4f8924e93635e97c782db302aaed2ac145c7ac4 Mon Sep 17 00:00:00 2001 From: mohammad Date: Wed, 21 Aug 2024 16:58:28 +0300 Subject: [PATCH 03/10] padding and text them --- assets/images/time_icon.svg | 4 + lib/main.dart | 1 - .../view/access_management.dart | 1 + lib/pages/common/custom_table.dart | 2 +- lib/pages/common/custom_web_textfield.dart | 3 +- lib/pages/common/date_time_widget.dart | 4 + .../bloc/visitor_password_bloc.dart | 17 +-- .../view/add_device_dialog.dart | 6 +- .../visitor_password/view/repeat_widget.dart | 33 ++--- .../view/visitor_password_dialog.dart | 140 +++++++----------- lib/utils/constants/assets.dart | 1 + 11 files changed, 93 insertions(+), 119 deletions(-) create mode 100644 assets/images/time_icon.svg diff --git a/assets/images/time_icon.svg b/assets/images/time_icon.svg new file mode 100644 index 00000000..a8f06677 --- /dev/null +++ b/assets/images/time_icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/lib/main.dart b/lib/main.dart index c00a8da7..af74170d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -59,7 +59,6 @@ class MyApp extends StatelessWidget { colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), // Set up color scheme useMaterial3: true, // Enable Material 3 ), - // home: VisitorPasswordDialog() home:isLoggedIn == 'Success' ? const HomePage() : const LoginPage(), )); } diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index e2f79429..e202194f 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -125,6 +125,7 @@ class AccessManagementPage extends StatelessWidget { width: 15, ), DateTimeWebWidget( + isTime: false, isRequired: false, title: 'Access Time', size: size, diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index c2a83273..86f34124 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -143,7 +143,7 @@ class _DynamicTableState extends State { alignment: Alignment.centerLeft, child: Padding( padding: const EdgeInsets.all(8.0), - child: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)), + child: Text(title, style: const TextStyle(fontWeight: FontWeight.w400,fontSize: 13,color: Color(0xFF999999))), ), ), ); diff --git a/lib/pages/common/custom_web_textfield.dart b/lib/pages/common/custom_web_textfield.dart index 82fb86c9..daaa2c13 100644 --- a/lib/pages/common/custom_web_textfield.dart +++ b/lib/pages/common/custom_web_textfield.dart @@ -37,8 +37,7 @@ class CustomWebTextField extends StatelessWidget { .bodyMedium! .copyWith(color: Colors.red), ), - Text(textFieldName, - style: Theme.of(context).textTheme.bodySmall!.copyWith( + Text(textFieldName, style: Theme.of(context).textTheme.bodySmall!.copyWith( color: Colors.black,fontSize: 13),), ], ), diff --git a/lib/pages/common/date_time_widget.dart b/lib/pages/common/date_time_widget.dart index f5034342..39dc582c 100644 --- a/lib/pages/common/date_time_widget.dart +++ b/lib/pages/common/date_time_widget.dart @@ -12,6 +12,7 @@ class DateTimeWebWidget extends StatelessWidget { required this.title, required this.startTime, required this.endTime, + required this.isTime, required this.firstString, required this.secondString, }); @@ -19,6 +20,7 @@ class DateTimeWebWidget extends StatelessWidget { final Size size; final String title; final bool isRequired; + final bool isTime; final String firstString; final String secondString; final Function()? startTime; @@ -66,6 +68,8 @@ class DateTimeWebWidget extends StatelessWidget { child: Text(secondString, style: Theme.of(context).textTheme.bodySmall!.copyWith( color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),)), SvgPicture.asset( + isTime? + Assets.timeIcon: Assets.calendarIcon, ), ], diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index e620cc59..65d82dda 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -262,12 +262,10 @@ class VisitorPasswordBloc Emitter emit) async { try { generate7DigitNumber(); - // emit(DeviceLoaded()); await AccessMangApi().postOffLineOneTime( email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName); - // emit(TableLoaded(data)); } catch (e) { emit(FailedState(e.toString())); } @@ -278,14 +276,14 @@ class VisitorPasswordBloc Emitter emit) async { try { generate7DigitNumber(); - // emit(DeviceLoaded()); await AccessMangApi().postOffLineMultipleTime( email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName, - invalidTime: event.invalidTime, - effectiveTime: event.effectiveTime); - // emit(TableLoaded(data)); + invalidTime: expirationTimeTimeStamp.toString(), + effectiveTime: effectiveTimeTimeStamp.toString(), + + ); } catch (e) { emit(FailedState(e.toString())); } @@ -335,8 +333,6 @@ class VisitorPasswordBloc return matchesDeviceName && matchesDeviceId; }).toList(); - // emit(TableLoaded(filteredData)); - add(UpdateFilteredDevicesEvent(filteredData)); } @@ -414,11 +410,6 @@ class VisitorPasswordBloc expirationTimeTimeStamp = selectedTimestamp; } } - print('effectiveTime=$effectiveTime'); - print('expirationTime=$expirationTime'); - - print('expirationTimeTimeStamp=$expirationTimeTimeStamp'); - print('effectiveTimeTimeStamp=$effectiveTimeTimeStamp'); emit(TimeSelectedState()); } } diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index 844e0ca9..7f9ca94e 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -55,7 +55,11 @@ class AddDeviceDialog extends StatelessWidget { ), ), SizedBox(width: 10,), - Text('Only online accessible devices can be added'), + Text('Only online accessible devices can be added', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + fontSize: 12, + color: ColorsManager.grayColor),), ], ) ), diff --git a/lib/pages/visitor_password/view/repeat_widget.dart b/lib/pages/visitor_password/view/repeat_widget.dart index 73770100..31bedb05 100644 --- a/lib/pages/visitor_password/view/repeat_widget.dart +++ b/lib/pages/visitor_password/view/repeat_widget.dart @@ -14,28 +14,29 @@ class RepeatWidget extends StatelessWidget { @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; - return BlocBuilder( builder: (context, state) { final visitorBloc = BlocProvider.of(context); return Column( + mainAxisAlignment: MainAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.start, children: [ + Container( - width: size.width * 0.8, - height: size.height * 0.06, // Adjust height as needed - child: ListView( - scrollDirection: Axis.horizontal, + height: size.height * 0.05, // Adjust height as needed + child: Wrap( children: visitorBloc.days.map((day) { return Container( - width: size.width* 0.09, + width: size.width * 0.05, child: CheckboxListTile( + contentPadding: EdgeInsets.zero, title: Text( day['day']!, style: TextStyle( - fontSize: 18, + fontSize: 12, color: visitorBloc.selectedDays.contains(day['key']) ? Colors.black - : ColorsManager.grayColor, + : ColorsManager.blackColor, ), ), value: visitorBloc.selectedDays.contains(day['key']), @@ -52,27 +53,23 @@ class RepeatWidget extends StatelessWidget { Padding( padding: const EdgeInsets.all(8.0), child: DateTimeWebWidget( + isTime: true, isRequired: false, title: '', size: size, endTime: () { - print('sadasd'); - visitorBloc.add(SelectTimeEvent( - context: context, - isEffective: false)); - new Future.delayed(const Duration(milliseconds: 500), () { + visitorBloc.add(SelectTimeEvent( + context: context, + isEffective: false)); + Future.delayed(const Duration(milliseconds: 500), () { visitorBloc.add(ChangeTimeEvent(val: visitorBloc.endTime, isStartEndTime: true)); - }); - - }, startTime: () { - new Future.delayed(const Duration(milliseconds: 500), () { + Future.delayed(const Duration(milliseconds: 500), () { visitorBloc.add(ChangeTimeEvent(val: visitorBloc.endTime, isStartEndTime: true)); }); visitorBloc.add(SelectTimeEvent(context: context, isEffective: true)); - }, firstString:visitorBloc.effectiveTime , secondString: visitorBloc.expirationTime , diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index 2299877f..9998ec3e 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -245,10 +245,10 @@ class VisitorPasswordDialog extends StatelessWidget { height: 20, ), if ((visitorBloc.usageFrequencySelected != 'One-Time' || - visitorBloc.accessTypeSelected != - 'Offline Password') && - (visitorBloc.usageFrequencySelected != '')) + visitorBloc.accessTypeSelected != 'Offline Password') && + (visitorBloc.usageFrequencySelected != '')) DateTimeWebWidget( + isTime: false, isRequired: true, title: 'Access Period', size: size, @@ -282,42 +282,44 @@ class VisitorPasswordDialog extends StatelessWidget { .bodyMedium! .copyWith(color: Colors.red), ), - Text('Access Devices', style: Theme.of(context).textTheme.bodySmall!.copyWith( + Text('Access Devices', + style: Theme.of(context).textTheme.bodySmall!.copyWith( color: Colors.black,fontSize: 13),), ], ), Text( - 'Within the validity period, each device can be unlocked only once.',style: Theme.of(context).textTheme.bodySmall!.copyWith( + 'Within the validity period, each device can be unlocked only once.', + style: Theme.of(context).textTheme.bodySmall!.copyWith( fontWeight: FontWeight.w400, color: ColorsManager.grayColor,fontSize: 9),), const SizedBox( height: 20, ), - if (visitorBloc.usageFrequencySelected == - 'Periodic' && - visitorBloc.accessTypeSelected == - 'Online Password') + if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Online Password') SizedBox( width: 100, - child: ListTile( - contentPadding: EdgeInsets.zero, - leading: const Text('Repeat'), - trailing: Transform.scale( - scale: .8, - child: CupertinoSwitch( - value: visitorBloc.repeat, - onChanged: (value) { - visitorBloc.add(ToggleRepeatEvent()); - }, - applyTheme: true, - ), - ), + child: Column( + children: [ + Text('Repeat', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), + Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: visitorBloc.repeat, + onChanged: (value) { + visitorBloc.add(ToggleRepeatEvent()); + }, + applyTheme: true, + ), + ), + ], + ), ), - if (visitorBloc.usageFrequencySelected == - 'Periodic' && - visitorBloc.accessTypeSelected == - 'Online Password') + if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Online Password') isRepeat ? const RepeatWidget() : const SizedBox(), Container( decoration: containerDecoration, @@ -406,70 +408,40 @@ class VisitorPasswordDialog extends StatelessWidget { child: DefaultButton( borderRadius: 8, onPressed: () { - if (visitorBloc.usageFrequencySelected == - 'One-Time' && - visitorBloc.accessTypeSelected == - 'Online Password') { + if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Online Password') { visitorBloc.add( OnlineOneTimePasswordEvent( context: context, - passwordName: visitorBloc - .userNameController.text, - email: visitorBloc - .emailController.text)); - } else if (visitorBloc - .usageFrequencySelected == - 'Periodic' && - visitorBloc.accessTypeSelected == - 'Online Password') { - visitorBloc.add( - OnlineMultipleTimePasswordEvent( - passwordName: - visitorBloc - .userNameController - .text, - email: - visitorBloc - .emailController.text, - effectiveTime: visitorBloc - .effectiveTimeTimeStamp - .toString(), - invalidTime: visitorBloc - .expirationTimeTimeStamp - .toString())); - } else if (visitorBloc - .usageFrequencySelected == - 'One-Time' && - visitorBloc.accessTypeSelected == - 'Offline Password') { - visitorBloc - .add(OfflineOneTimePasswordEvent( - passwordName: visitorBloc - .userNameController.text, - email: - visitorBloc.emailController.text, + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text)); + } else if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Online Password') { + visitorBloc.add(OnlineMultipleTimePasswordEvent( + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), + invalidTime: visitorBloc.expirationTimeTimeStamp.toString())); + } else if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Offline Password') { + visitorBloc.add(OfflineOneTimePasswordEvent( + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, )); - } else if (visitorBloc - .usageFrequencySelected == - 'Periodic' && - visitorBloc.accessTypeSelected == - 'Offline Password') { + } else if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password') { visitorBloc.add( OfflineMultipleTimePasswordEvent( - passwordName: visitorBloc - .userNameController.text, - email: visitorBloc - .emailController.text, - effectiveTime: visitorBloc - .effectiveTimeTimeStamp - .toString(), - invalidTime: visitorBloc - .expirationTimeTimeStamp - .toString())); + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), + invalidTime: visitorBloc.expirationTimeTimeStamp.toString())); } }, - child: const Text( - 'Ok', + child: Text('Ok', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.whiteColors,fontSize: 16), ), ), ), @@ -531,7 +503,9 @@ class VisitorPasswordDialog extends StatelessWidget { } }, borderRadius: 8, - child: Text('Ok'), + child: Text('Ok', style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.whiteColors,fontSize: 16),), ), ), ], diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index 2c2a6e43..62f991fe 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -25,4 +25,5 @@ class Assets { static const String assetIcon = "assets/images/asset_icon.svg"; static const String calendarIcon = "assets/images/calendar_icon.svg"; static const String deviceNoteIcon = "assets/images/device_note.svg"; + static const String timeIcon = "assets/images/time_icon.svg"; } From f5a7441b3c2af02525bff97868d42363a70320db Mon Sep 17 00:00:00 2001 From: mohammad Date: Thu, 22 Aug 2024 16:52:41 +0300 Subject: [PATCH 04/10] tap filter --- assets/images/empty_table.svg | 23 ++ .../access_management/bloc/access_bloc.dart | 97 +++++-- .../access_management/bloc/access_event.dart | 6 + .../model/password_model.dart | 20 +- .../view/access_management.dart | 147 +++-------- lib/pages/auth/bloc/auth_bloc.dart | 1 - lib/pages/auth/view/login_web_page.dart | 3 +- lib/pages/common/custom_table.dart | 32 ++- lib/pages/common/date_time_widget.dart | 5 +- lib/pages/home/bloc/home_bloc.dart | 2 +- lib/pages/home/view/home_card.dart | 18 +- .../bloc/visitor_password_bloc.dart | 18 +- .../view/add_device_dialog.dart | 4 +- .../view/visitor_password_dialog.dart | 236 +++++++----------- lib/utils/constants/assets.dart | 1 + lib/utils/constants/const.dart | 38 ++- 16 files changed, 333 insertions(+), 318 deletions(-) create mode 100644 assets/images/empty_table.svg diff --git a/assets/images/empty_table.svg b/assets/images/empty_table.svg new file mode 100644 index 00000000..24ac359d --- /dev/null +++ b/assets/images/empty_table.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index f586c56f..5b406add 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -5,23 +5,25 @@ 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/services/access_mang_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/const.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; class AccessBloc extends Bloc { AccessBloc() : super((AccessInitial())) { on(_onFetchTableData); - on(selectFilterTap); + // on(selectFilterTap); on(selectTime); on(_filterData); on(resetSearch); + on(onTabChanged); } - String startTime = 'Start Time'; - String endTime = 'End Time'; + String startTime = 'Start Date'; + String endTime = 'End Date'; int? effectiveTimeTimeStamp; int? expirationTimeTimeStamp; TextEditingController passwordName= TextEditingController(); - List filteredData = []; // To store filtered data + List filteredData = []; List data=[]; Future _onFetchTableData( @@ -29,11 +31,26 @@ class AccessBloc extends Bloc { try { emit(AccessLoaded()); data = await AccessMangApi().fetchVisitorPassword(); - emit(TableLoaded(data)); + filteredData= data; + updateTabsCount(); + emit(TableLoaded(data)); } catch (e) { emit(FailedState(e.toString())); } } + void updateTabsCount() { + // Count occurrences based on the type field + int toBeEffectiveCount = data.where((item) => item.passwordStatus.value== 'To Be Effective').length; + int effectiveCount = data.where((item) => item.passwordStatus.value == 'Effective').length; + int expiredCount = data.where((item) => item.passwordStatus.value == 'Expired').length; + + // Update tab labels with counts + tabs[1] = 'To Be Effective ($toBeEffectiveCount)'; + tabs[2] = 'Effective ($effectiveCount)'; + tabs[3] = 'Expired ($expiredCount)'; + } + + int selectedIndex = 0; @@ -49,9 +66,8 @@ class AccessBloc extends Bloc { try { emit(AccessLoaded()); selectedIndex= event.selectedIndex; - emit(AccessInitial()); + emit(AccessInitial()); emit(TableLoaded(data)); - } catch (e) { emit(FailedState( e.toString())); return; @@ -60,6 +76,7 @@ class AccessBloc extends Bloc { Future selectTime(SelectTime event, Emitter emit) async { + final DateTime? picked = await showDatePicker( context: event.context, initialDate: DateTime.now(), @@ -120,27 +137,27 @@ class AccessBloc extends Bloc { } } } - emit(AccessInitial()); - emit(TableLoaded(data)); + emit(ChangeTimeState()); } + Future _filterData(FilterDataEvent event, Emitter emit) async { emit(AccessLoaded()); try { - // Filter the data based on the provided criteria filteredData = data.where((item) { bool matchesCriteria = true; - // Check if the password name should be used for filtering + + // Filter by password name if provided if (event.passwordName != null && event.passwordName!.isNotEmpty) { - final bool matchesName = item.passwodName != null && - item.passwodName.contains(event.passwordName); + final bool matchesName = item.passwordName != null && + item.passwordName.contains(event.passwordName); if (!matchesName) { matchesCriteria = false; } } - // Check if the time range should be used for filtering + + // Filter by date range if provided if (event.startTime != null && event.endTime != null) { - // Ensure effectiveTime and invalidTime are treated as integers final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); final int? invalidTime = int.tryParse(item.invalidTime.toString()); if (effectiveTime == null || invalidTime == null) { @@ -153,22 +170,31 @@ class AccessBloc extends Bloc { } } } + + // Filter by tab selection + if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To Be Effective') { + matchesCriteria = false; + } else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') { + matchesCriteria = false; + } else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') { + matchesCriteria = false; + } + return matchesCriteria; }).toList(); - print('Filtered data: $filteredData'); emit(TableLoaded(filteredData)); } catch (e) { - print('Error occurred during filtering: $e'); + emit(FailedState(e.toString())); } } - // ResetSearch + resetSearch(ResetSearch event, Emitter emit) async{ emit(AccessLoaded()); startTime = 'Start Time'; endTime = 'End Time'; passwordName.clear(); + selectedIndex=0; add(FetchTableData()); - } String timestampToDate(dynamic timestamp) { @@ -176,5 +202,38 @@ class AccessBloc extends Bloc { return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}"; } + Future onTabChanged(TabChangedEvent event, Emitter emit) async { + try { + emit(AccessLoaded()); + selectedIndex = event.selectedIndex; + // Apply filtering based on selected tab + switch (selectedIndex) { + case 0: // All + filteredData = data; + break; + case 1: // To Be Effective + filteredData = data.where((item) => item.passwordStatus.value == "To Be Effective").toList(); + break; + case 2: // Effective + filteredData = data.where((item) => item.passwordStatus.value == "Effective").toList(); + + break; + case 3: // Expired + filteredData = data.where((item) => item.passwordStatus.value == "Expired").toList(); + break; + default: + filteredData = data; + } + add(FilterDataEvent( + selectedTabIndex: selectedIndex, // Pass the selected tab index + passwordName: passwordName.text.toLowerCase(), + startTime: effectiveTimeTimeStamp, + endTime: expirationTimeTimeStamp + )); + emit(TableLoaded(filteredData)); + } catch (e) { + emit(FailedState(e.toString())); + } + } } diff --git a/lib/pages/access_management/bloc/access_event.dart b/lib/pages/access_management/bloc/access_event.dart index 3a64a11a..f2f631b4 100644 --- a/lib/pages/access_management/bloc/access_event.dart +++ b/lib/pages/access_management/bloc/access_event.dart @@ -31,10 +31,16 @@ class FilterDataEvent extends AccessEvent { final String? passwordName; final int? startTime; final int? endTime; + final int selectedTabIndex; // Add this field const FilterDataEvent({ this.passwordName, this.startTime, this.endTime, + required this.selectedTabIndex, // Initialize this field + }); } + + + diff --git a/lib/pages/access_management/model/password_model.dart b/lib/pages/access_management/model/password_model.dart index acd3e13a..584e9b7e 100644 --- a/lib/pages/access_management/model/password_model.dart +++ b/lib/pages/access_management/model/password_model.dart @@ -6,8 +6,8 @@ class PasswordModel { final dynamic effectiveTime; final dynamic passwordCreated; final dynamic createdTime; - final dynamic passwodName; // New field - final dynamic passwordStatus; + final dynamic passwordName; // New field + final AccessStatus passwordStatus; final AccessType passwordType; final dynamic deviceUuid; @@ -17,8 +17,8 @@ class PasswordModel { this.effectiveTime, this.passwordCreated, this.createdTime, - this.passwodName, // New field - this.passwordStatus, + this.passwordName, // New field + required this.passwordStatus, required this.passwordType, this.deviceUuid, }); @@ -30,9 +30,9 @@ class PasswordModel { effectiveTime: json['effectiveTime'], passwordCreated: json['passwordCreated'], createdTime: json['createdTime'], - passwodName: json['passwodName']??'No name', // New field - passwordStatus: json['passwordStatus'], - passwordType:AccessTypeExtension.fromString(json['passwordType']) , + passwordName: json['passwordName']??'No name', // New field + passwordStatus:AccessStatusExtension.fromString(json['passwordStatus']), + passwordType:AccessTypeExtension.fromString(json['passwordType']), deviceUuid: json['deviceUuid'], ); } @@ -44,13 +44,11 @@ class PasswordModel { 'effectiveTime': effectiveTime, 'passwordCreated': passwordCreated, 'createdTime': createdTime, - 'passwodName': passwodName, // New field + 'passwodName': passwordName, // New field 'passwordStatus': passwordStatus, 'passwordType': passwordType, 'deviceUuid': deviceUuid, }; } - List parsePasswordList(List jsonList) { - return jsonList.map((json) => PasswordModel.fromJson(json)).toList(); - } + } diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index e202194f..38fb545e 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -38,14 +38,13 @@ class AccessManagementPage extends StatelessWidget { ], scaffoldBody: BlocProvider(create: (BuildContext context) => AccessBloc()..add(FetchTableData()), child: BlocConsumer(listener: (context, state) { - if (state is FailedState) { - // CustomSnackBar.displaySnackBar( - // state.errorMessage - // ); - } + }, builder: (context, state) { final accessBloc = BlocProvider.of(context); - return Container( + final filteredData = accessBloc.filteredData; + return state is AccessLoaded? + const Center(child: CircularProgressIndicator()): + Container( padding: EdgeInsets.all(30), height: size.height, width: size.width, @@ -61,35 +60,34 @@ class AccessManagementPage extends StatelessWidget { itemCount: BlocProvider.of(context).tabs.length, shrinkWrap: true, itemBuilder: (context, index) { - final isSelected = index == - BlocProvider.of(context).selectedIndex; + final isSelected = index == BlocProvider.of(context).selectedIndex; return InkWell( onTap: () { BlocProvider.of(context).add(TabChangedEvent(index)); }, child: Container( decoration: BoxDecoration( - color: ColorsManager.boxColor, - border: Border.all( - color: isSelected ? Colors.blue : Colors.transparent, - width: 2.0,), - borderRadius: index == 0 - ? const BorderRadius.only( - topLeft: Radius.circular(10), - bottomLeft: Radius.circular(10)) - : index == 3 - ? const BorderRadius.only( - topRight: Radius.circular(10), - bottomRight: Radius.circular(10)) - : null), - padding: const EdgeInsets.only(left: 10,right: 10), + color: ColorsManager.boxColor, + border: Border.all( + color: isSelected ? Colors.blue : Colors.transparent, + width: 2.0, + ), + borderRadius: index == 0 + ? const BorderRadius.only( + topLeft: Radius.circular(10), + bottomLeft: Radius.circular(10)) + : index == 3 + ? const BorderRadius.only( + topRight: Radius.circular(10), + bottomRight: Radius.circular(10)) + : null, + ), + padding: const EdgeInsets.only(left: 10, right: 10), child: Center( child: Text( BlocProvider.of(context).tabs[index], style: TextStyle( - color: isSelected - ? Colors.blue - : Colors.black, + color: isSelected ? Colors.blue : Colors.black, ), ), ), @@ -105,12 +103,15 @@ class AccessManagementPage extends StatelessWidget { Row( children: [ Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - const Text('Name'), + Text('Name', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13),), + const SizedBox(height: 5,), Container( + height:size.height * 0.053, width: size.width * 0.15, decoration: containerDecoration, child: TextFormField( @@ -118,7 +119,8 @@ class AccessManagementPage extends StatelessWidget { style: const TextStyle(color: Colors.black), decoration: textBoxDecoration()! .copyWith(hintText: 'Please enter'), - )), + ) + ), ], ), const SizedBox( @@ -152,6 +154,7 @@ class AccessManagementPage extends StatelessWidget { child: DefaultButton( onPressed: () { accessBloc.add(FilterDataEvent( + selectedTabIndex: BlocProvider.of(context).selectedIndex, // Pass the selected tab index passwordName: accessBloc.passwordName.text.toLowerCase(), startTime: accessBloc.effectiveTimeTimeStamp, endTime: accessBloc.expirationTimeTimeStamp @@ -234,8 +237,8 @@ class AccessManagementPage extends StatelessWidget { height: 20, ), Expanded( - child: state is TableLoaded - ? DynamicTable( + child: DynamicTable( + isEmpty: filteredData.isEmpty , withCheckBox: false, size: size, cellDecoration: containerDecoration, @@ -243,102 +246,30 @@ class AccessManagementPage extends StatelessWidget { 'Name', 'Access Type', 'Access Period', - 'Device Id', + 'Accessible Device', 'Authorizer', 'Authorization Date & Time', 'Access Status' ], - data: state.data.map((item) { + data: filteredData.map((item) { return [ - item.passwodName.toString(), + item.passwordName.toString(), item.passwordType.value, ('${accessBloc.timestampToDate(item.effectiveTime)} - ${accessBloc.timestampToDate(item.invalidTime)}'), item.deviceUuid.toString(), '', '', - '' + item.passwordStatus.value ]; }).toList(), ) - : const Center(child: CircularProgressIndicator()), + // : const Center(child: CircularProgressIndicator()), ) - ], ), ); }))); } - - - // Container TableWidget(Size size, TableLoaded state,AccessBloc accessBloc) { - // return Container( - // decoration: containerDecoration, - // width: size.width, - // child: Padding( - // padding: const EdgeInsets.all(10.0), - // child: ListView( - // scrollDirection: Axis.horizontal, - // children: [ - // Container( - // width: size.width, - // height: size.height, - // child: Column( - // children: [ - // Container( - // color: ColorsManager.boxColor, - // child: Row( - // children: [ - // _buildTableHeaderCell('Password name'), - // _buildTableHeaderCell(' Password Type'), - // _buildTableHeaderCell('Start Time'), - // _buildTableHeaderCell('End Time'), - // _buildTableHeaderCell('Device Id'), - // // _buildTableHeaderCell('Authorization Source'), - // // _buildTableHeaderCell('Authorizer'), - // _buildTableHeaderCell('Password Created'), - // // _buildTableHeaderCell('Access Status'), - // _buildTableHeaderCell('Password Status'), - // ], - // ), - // ), - // Expanded( - // child: Container( - // width: size.width, - // color: ColorsManager.whiteColors, - // child: ListView( - // shrinkWrap: true, - // children: [ - // Column( - // children: state.data.map((item) { - // return Row( - // children: [ - // _buildTableCell(item.passwodName), - // _buildTableCell(item.passwordType), - // - // _buildTableCell(accessBloc.timestampToDateTime(item.effectiveTime).toString()), - // _buildTableCell(accessBloc.timestampToDateTime(item.invalidTime).toString()), - // _buildTableCell(item.deviceUuid.toString()), - // // _buildTableCell(item.authorizationSource), - // // _buildTableCell(item.authorizer), - // _buildTableCell(item.passwordCreated!=null?accessBloc.timestampToDateTime(item.passwordCreated).toString():'no data'), - // // _buildTableCell(item.accessStatus), - // _buildTableCell(item.passwordStatus.toString()), - // ], - // ); - // }).toList(), - // ), - // ], - // ), - // ), - // ), - // ], - // ), - // ), - // ], - // ), - // ), - // ); - // } } diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart index 2cc1a033..125c2817 100644 --- a/lib/pages/auth/bloc/auth_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -159,7 +159,6 @@ class AuthBloc extends Bloc { loginPasswordController.clear(); emit(LoginSuccess()); } else { - emit(const LoginFailure(error: 'Something went wrong')); } } else { diff --git a/lib/pages/auth/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart index b819669e..d8b22d38 100644 --- a/lib/pages/auth/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -166,8 +166,7 @@ class _LoginWebPageState extends State { return DropdownMenuItem( value: region.id, child: SizedBox( - width: size.width*0.06, - + width: size.width*0.08, child: Text(region.name)), ); }).toList(), diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index 86f34124..b7aa71a5 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -1,5 +1,7 @@ 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 DynamicTable extends StatefulWidget { final List headers; @@ -8,6 +10,7 @@ class DynamicTable extends StatefulWidget { final BoxDecoration? cellDecoration; final Size size; final bool withCheckBox; + final bool isEmpty; final void Function(bool?)? selectAll; final void Function(int, bool?)? onRowCheckboxChanged; @@ -16,6 +19,7 @@ class DynamicTable extends StatefulWidget { required this.headers, required this.data, required this.size, + required this.isEmpty, required this.withCheckBox, this.headerDecoration, this.cellDecoration, @@ -63,7 +67,8 @@ class _DynamicTableState extends State { decoration: widget.cellDecoration, child: Padding( padding: const EdgeInsets.all(10.0), - child: ListView( + child: + ListView( scrollDirection: Axis.horizontal, children: [ SizedBox( @@ -83,6 +88,29 @@ class _DynamicTableState extends State { ], ), ), + widget.isEmpty? + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Column( + children: [ + SvgPicture.asset( + Assets.emptyTable + ), + SizedBox(height: 15,), + Text('No Passwords',style: Theme.of(context).textTheme.bodySmall!.copyWith(color:ColorsManager.grayColor ),) + ], + ), + ], + ), + ], + ), + ): Expanded( child: Container( color: Colors.white, @@ -164,7 +192,7 @@ class _DynamicTableState extends State { alignment: Alignment.centerLeft, child: Text( content, - style: const TextStyle(color: Colors.black, fontSize: 12), + style: const TextStyle(color: Colors.black, fontSize: 10,fontWeight: FontWeight.w400), ), ), ); diff --git a/lib/pages/common/date_time_widget.dart b/lib/pages/common/date_time_widget.dart index 39dc582c..55d5b9a9 100644 --- a/lib/pages/common/date_time_widget.dart +++ b/lib/pages/common/date_time_widget.dart @@ -42,11 +42,12 @@ class DateTimeWebWidget extends StatelessWidget { .bodyMedium! .copyWith(color: Colors.red), ), - Text(title??'' , style: Theme.of(context).textTheme.bodySmall!.copyWith( + Text(title??'' , + style: Theme.of(context).textTheme.bodySmall!.copyWith( color: Colors.black,fontSize: 13),), ], ), - SizedBox(height: 8,), + const SizedBox(height: 8,), Container( width: size.width * 0.25, padding: EdgeInsets.all(10), diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index db233d3c..ebcc6b4e 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -67,7 +67,7 @@ class HomeBloc extends Bloc { color: null, ), HomeItemModel( - title: 'Space\nManagement', + title: 'Space Management', icon: Assets.spaseManagementIcon, active: true, onPress: (context) { diff --git a/lib/pages/home/view/home_card.dart b/lib/pages/home/view/home_card.dart index 287bb4f4..ce152c1c 100644 --- a/lib/pages/home/view/home_card.dart +++ b/lib/pages/home/view/home_card.dart @@ -37,14 +37,16 @@ class HomeCard extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.start, children: [ - FittedBox( - fit: BoxFit.scaleDown, - child: Text( - name, - style: const TextStyle( - fontSize: 20, - color: Colors.white, - fontWeight: FontWeight.bold, + Flexible( + child: FittedBox( + fit: BoxFit.scaleDown, + child: Text( + name, + style: const TextStyle( + fontSize: 20, + color: Colors.white, + fontWeight: FontWeight.bold, + ), ), ), ), diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index 65d82dda..ff3b57e4 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -11,9 +11,7 @@ import 'package:syncrow_web/services/access_mang_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; -List selectedDevices = []; -// Define the BLoC class VisitorPasswordBloc extends Bloc { VisitorPasswordBloc() : super(VisitorPasswordInitial()) { @@ -42,12 +40,12 @@ class VisitorPasswordBloc final TextEditingController unitNameController = TextEditingController(); final TextEditingController virtualAddressController = TextEditingController(); + List selectedDevices = []; List data = []; List selectedDeviceIds = []; - String effectiveTime = 'Select Time'; - - String expirationTime = 'Select Time'; + String effectiveTime = 'Start Time'; + String expirationTime = 'End Time'; final forgetFormKey = GlobalKey(); @@ -69,8 +67,6 @@ class VisitorPasswordBloc String startTimeAccess = 'Start Time'; String endTimeAccess = 'End Time'; - // DateTime? repeatStartTime=DateTime.now(); - // DateTime? repeatEndTime; selectAccessType( SelectPasswordType event, Emitter emit) { @@ -210,9 +206,6 @@ class VisitorPasswordBloc Emitter emit) async { try { generate7DigitNumber(); - - print('selectedDevices$selectedDevices'); - // emit(DeviceLoaded()); bool res = await AccessMangApi().postOnlineOneTime( email: event.email, password: passwordController, @@ -225,6 +218,7 @@ class VisitorPasswordBloc } emit(TableLoaded(data)); } catch (e) { + emit(FailedState(e.toString())); } } @@ -351,9 +345,9 @@ class VisitorPasswordBloc emit(TableLoaded(event.filteredData)); } - addDeviceToList() { + addDeviceToList(context) { selectedDevices = selectedDeviceIds; - print(selectedDevices); + Navigator.of(context).pop(selectedDevices); // Close the dialog } Future selectTimeOfLinePassword(SelectTimeEvent event, Emitter emit) async { diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index 7f9ca94e..9d7be636 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -161,6 +161,7 @@ class AddDeviceDialog extends StatelessWidget { child: state is TableLoaded ? DynamicTable( cellDecoration: containerDecoration, + isEmpty:visitorBloc.data.isEmpty, selectAll: (p0) { visitorBloc.selectedDeviceIds.clear(); for (var item in state.data) { @@ -211,8 +212,7 @@ class AddDeviceDialog extends StatelessWidget { width: size.width * 0.2, child: DefaultButton( onPressed: () { - visitorBloc.addDeviceToList(); - Navigator.of(context).pop(); // Close the dialog + visitorBloc.addDeviceToList(context); }, borderRadius: 8, child: Text('Ok'), diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index 9998ec3e..1f7e3a14 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -128,10 +128,7 @@ class VisitorPasswordDialog extends StatelessWidget { : visitorBloc.accessTypeSelected, onChanged: (String? value) { if (value != null) { - print(value); - - context - .read() + context.read() .add(SelectPasswordType(value)); } }, @@ -192,22 +189,18 @@ class VisitorPasswordDialog extends StatelessWidget { SizedBox( width: 200, child: RadioListTile( - title: Text('One-Time',style: Theme.of(context).textTheme.bodySmall!.copyWith( + title: Text('One-Time', + style: Theme.of(context).textTheme.bodySmall!.copyWith( color: Colors.black,fontSize: 13),), value: 'One-Time', groupValue: (state is UsageFrequencySelected) ? state.selectedFrequency - : visitorBloc - .usageFrequencySelected, + : visitorBloc.usageFrequencySelected, onChanged: (String? value) { if (value != null) { - print(value); - - context - .read() - .add(SelectUsageFrequency( - value)); + context.read() + .add(SelectUsageFrequency(value)); } }, ), @@ -219,17 +212,14 @@ class VisitorPasswordDialog extends StatelessWidget { style: Theme.of(context).textTheme.bodySmall!.copyWith( color: Colors.black,fontSize: 13),), value: 'Periodic', - groupValue: - (state is UsageFrequencySelected) + groupValue: (state is UsageFrequencySelected) ? state.selectedFrequency - : visitorBloc - .usageFrequencySelected, + : visitorBloc.usageFrequencySelected, onChanged: (String? value) { if (value != null) { context .read() - .add(SelectUsageFrequency( - value)); + .add(SelectUsageFrequency(value)); } }, ), @@ -238,7 +228,8 @@ class VisitorPasswordDialog extends StatelessWidget { ), Text('Within the validity period, each device can be unlocked only once.', style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor,fontSize: 9),) + color: ColorsManager.grayColor,fontSize: 9), + ) ], ), const SizedBox( @@ -288,7 +279,7 @@ class VisitorPasswordDialog extends StatelessWidget { ], ), Text( - 'Within the validity period, each device can be unlocked only once.', + 'Within the validity period, each device can be unlocked only once.', style: Theme.of(context).textTheme.bodySmall!.copyWith( fontWeight: FontWeight.w400, color: ColorsManager.grayColor,fontSize: 9),), @@ -326,13 +317,20 @@ class VisitorPasswordDialog extends StatelessWidget { width: size.width * 0.08, child: DefaultButton( onPressed: () { - showDialog( + showDialog( context: context, barrierDismissible: false, builder: (BuildContext context) { return const AddDeviceDialog(); }, - ); + ).then((listDevice) { + if(listDevice!=null){ + print('selectedDevices==$listDevice'); + visitorBloc.selectedDevices = listDevice; + + } + }); + }, borderRadius: 8, child: Text('+ Add Device',style: Theme.of(context).textTheme.bodySmall!.copyWith( @@ -371,135 +369,81 @@ class VisitorPasswordDialog extends StatelessWidget { width: size.width * 0.2, child: DefaultButton( onPressed: () { - print(selectedDevices); if (visitorBloc.forgetFormKey.currentState!.validate()) { - if (selectedDevices.toString() != '[]') { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return InfoDialog( - size: size, - title: 'Set Password', - content: - 'This action will update all of the selected\n door locks passwords in the property.\n\nAre you sure you want to continue?', - actions: [ - Container( - decoration: containerDecoration, - width: size.width * 0.1, - child: DefaultButton( - borderRadius: 8, - onPressed: () { - Navigator.of(context) - .pop(); // Close the dialog - }, - backgroundColor: Colors.white, - child: Text( - 'Cancel', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.blackColor,fontSize: 16), - ), - ), - ), - Container( - decoration: containerDecoration, - width: size.width * 0.1, - child: DefaultButton( - borderRadius: 8, - onPressed: () { - if (visitorBloc.usageFrequencySelected == 'One-Time' && - visitorBloc.accessTypeSelected == 'Online Password') { - visitorBloc.add( - OnlineOneTimePasswordEvent( - context: context, - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text)); - } else if (visitorBloc.usageFrequencySelected == 'Periodic' && - visitorBloc.accessTypeSelected == 'Online Password') { - visitorBloc.add(OnlineMultipleTimePasswordEvent( - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), - invalidTime: visitorBloc.expirationTimeTimeStamp.toString())); - } else if (visitorBloc.usageFrequencySelected == 'One-Time' && - visitorBloc.accessTypeSelected == 'Offline Password') { - visitorBloc.add(OfflineOneTimePasswordEvent( - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - )); - } else if (visitorBloc.usageFrequencySelected == 'Periodic' && - visitorBloc.accessTypeSelected == 'Offline Password') { - visitorBloc.add( - OfflineMultipleTimePasswordEvent( - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), - invalidTime: visitorBloc.expirationTimeTimeStamp.toString())); - } - }, - child: Text('Ok', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.whiteColors,fontSize: 16), - ), - ), - ), - ], - ); - }, - ); - } else { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return AlertDialog( - alignment: Alignment.center, - content: SizedBox( - height: size!.height * 0.15, - child: Column( - children: [ - SizedBox( - child: SvgPicture.asset( - Assets.deviceNoteIcon, - height: 35, - width: 35, - ), - ), - - const SizedBox( - width: 15, - ), - Text( - 'Please select devices to continue', - style: Theme.of(context) - .textTheme - .headlineLarge! - .copyWith( - fontSize: 20, - fontWeight: FontWeight.w400, - color: Colors.black), - ), - ], - ), - ), - actionsAlignment: MainAxisAlignment.center, - actions: [ - TextButton( + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return InfoDialog( + size: size, + title: 'Set Password', + content: + 'This action will update all of the selected\n door locks passwords in the property.\n\nAre you sure you want to continue?', + actions: [ + Container( + decoration: containerDecoration, + width: size.width * 0.1, + child: DefaultButton( + borderRadius: 8, onPressed: () { Navigator.of(context).pop(); }, - child: Text('OK', + backgroundColor: Colors.white, + child: Text( + 'Cancel', style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.whiteColors,fontSize: 16),), + fontWeight: FontWeight.w400, + color: ColorsManager.blackColor,fontSize: 16), + ), ), - ], - ); - }, - ); - } + ), + Container( + decoration: containerDecoration, + width: size.width * 0.1, + child: DefaultButton( + borderRadius: 8, + onPressed: () { + if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Online Password') { + visitorBloc.add( + OnlineOneTimePasswordEvent( + context: context, + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text)); + } else if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Online Password') { + visitorBloc.add(OnlineMultipleTimePasswordEvent( + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), + invalidTime: visitorBloc.expirationTimeTimeStamp.toString())); + } else if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Offline Password') { + visitorBloc.add(OfflineOneTimePasswordEvent( + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + )); + } else if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password') { + visitorBloc.add( + OfflineMultipleTimePasswordEvent( + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), + invalidTime: visitorBloc.expirationTimeTimeStamp.toString())); + } + }, + child: Text('Ok', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.whiteColors,fontSize: 16), + ), + ), + ), + ], + ); + }, + ); } }, borderRadius: 8, diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index 62f991fe..f4a2859e 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -26,4 +26,5 @@ class Assets { static const String calendarIcon = "assets/images/calendar_icon.svg"; static const String deviceNoteIcon = "assets/images/device_note.svg"; static const String timeIcon = "assets/images/time_icon.svg"; + static const String emptyTable = "assets/images/empty_table.svg"; } diff --git a/lib/utils/constants/const.dart b/lib/utils/constants/const.dart index 7afa399d..77beff69 100644 --- a/lib/utils/constants/const.dart +++ b/lib/utils/constants/const.dart @@ -1,6 +1,4 @@ - - enum AccessType { onlineOnetime, onlineMultiple, @@ -43,8 +41,6 @@ extension AccessTypeExtension on AccessType { - - enum DeviseStatus { online, offline, @@ -74,6 +70,40 @@ extension OnlineTypeExtension on DeviseStatus { } +enum AccessStatus { + expired , + effective , + toBeEffective, +} + +extension AccessStatusExtension on AccessStatus { + String get value { + switch (this) { + case AccessStatus.expired: + return "Expired"; + case AccessStatus.effective: + return "Effective" ; + case AccessStatus.toBeEffective: + return "To be effective"; + + } + } + + static AccessStatus fromString(String value) { + switch (value) { + case "EXPIRED" : + return AccessStatus.expired; + case "EFFECTIVE" : + return AccessStatus.effective; + case "TO_BE_EFFECTIVE": + return AccessStatus.toBeEffective; + default: + throw ArgumentError("Invalid access type: $value"); + } + } +} + + From cf1a21e121eab6a0399be3a12b70345dc7fd7ede Mon Sep 17 00:00:00 2001 From: mohammad Date: Fri, 23 Aug 2024 22:16:48 +0300 Subject: [PATCH 05/10] Success dialog and Failed dialog changes with VisitorPasswordDialog --- assets/dome.json | 96 -- lib/main.dart | 5 +- .../access_management/bloc/access_bloc.dart | 16 +- .../view/access_management.dart | 82 +- lib/pages/auth/view/login_mobile_page.dart | 2 - lib/pages/common/custom_dialog.dart | 75 ++ lib/pages/common/custom_table.dart | 47 +- lib/pages/common/custom_web_textfield.dart | 29 +- lib/pages/common/hour_picker_dialog.dart | 10 +- lib/pages/common/info_dialog.dart | 2 +- lib/pages/home/view/home_page_web.dart | 4 +- .../bloc/visitor_password_bloc.dart | 120 ++- .../bloc/visitor_password_event.dart | 10 +- .../bloc/visitor_password_state.dart | 2 +- .../view/add_device_dialog.dart | 97 +- .../view/visitor_password_dialog.dart | 897 ++++++++++-------- lib/services/access_mang_api.dart | 69 +- lib/services/auth_api.dart | 12 - lib/web_layout/web_scaffold.dart | 2 - 19 files changed, 792 insertions(+), 785 deletions(-) delete mode 100644 assets/dome.json create mode 100644 lib/pages/common/custom_dialog.dart diff --git a/assets/dome.json b/assets/dome.json deleted file mode 100644 index 91186608..00000000 --- a/assets/dome.json +++ /dev/null @@ -1,96 +0,0 @@ -[ - { - "accessUser": "Ali Doe", - "accessType": "Admin", - "startTime": "2023-08-01", - "endTime": "2023-08-02", - "accessibleDevice": "Smart Door", - "authorizationSource": "System", - "authorizer": "Jane Smith", - "authorizationTime": "2023-08-01 10:00 AM", - "accessStatus": "Granted", - "actions": "View" - }, { - "accessUser": "oamr Doe", - "accessType": "Admin", - "startTime": "2023-08-01", - "endTime": "2023-08-05", - "accessibleDevice": "Smart Door", - "authorizationSource": "System", - "authorizer": "Jane Smith", - "authorizationTime": "2023-08-01 10:00 AM", - "accessStatus": "Granted", - "actions": "View" - }, { - "accessUser": "John Doe", - "accessType": "Admin", - "startTime": "2023-08-01", - "endTime": "2023-08-10", - "accessibleDevice": "Smart Door", - "authorizationSource": "System", - "authorizer": "Jane Smith", - "authorizationTime": "2023-08-01 10:00 AM", - "accessStatus": "Granted", - "actions": "View" - }, - - { - "accessUser": "John Doe", - "accessType": "Admin", - "startTime": "2023-08-01", - "endTime": "2023-10-10", - "accessibleDevice": "Smart Door", - "authorizationSource": "System", - "authorizer": "Jane Smith", - "authorizationTime": "2023-08-01 10:00 AM", - "accessStatus": "Granted", - "actions": "View" - }, - { - "accessUser": "John Doe", - "accessType": "Admin", - "startTime": "2023-03-01", - "endTime": "2023-05-10", - "accessibleDevice": "Smart Door", - "authorizationSource": "System", - "authorizer": "Jane Smith", - "authorizationTime": "2023-08-01 10:00 AM", - "accessStatus": "Granted", - "actions": "View" - }, - { - "accessUser": "John Doe", - "accessType": "Admin", - "startTime": "2023-07-01", - "endTime": "2023-08-10", - "accessibleDevice": "Smart Door", - "authorizationSource": "System", - "authorizer": "Jane Smith", - "authorizationTime": "2023-08-01 10:00 AM", - "accessStatus": "Granted", - "actions": "View" - }, { - "accessUser": "John Doe", - "accessType": "Admin", - "startTime": "2023-01-01", - "endTime": "2023-09-05", - "accessibleDevice": "Smart Door", - "authorizationSource": "System", - "authorizer": "Jane Smith", - "authorizationTime": "2023-08-01 10:00 AM", - "accessStatus": "Granted", - "actions": "View" - }, - { - "accessUser": "Alice Johnson", - "accessType": "User", - "startTime": "2023-08-01", - "endTime": "2023-08-10", - "accessibleDevice": "Smart Lock", - "authorizationSource": "Admin", - "authorizer": "John Doe", - "authorizationTime": "2023-08-02 11:00 AM", - "accessStatus": "Pending", - "actions": "Approve" - } -] diff --git a/lib/main.dart b/lib/main.dart index af74170d..01911d05 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -5,8 +5,7 @@ import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; import 'package:syncrow_web/pages/auth/view/login_page.dart'; import 'package:syncrow_web/pages/home/bloc/home_bloc.dart'; import 'package:syncrow_web/pages/home/view/home_page.dart'; -import 'package:syncrow_web/pages/visitor_password/view/add_device_dialog.dart'; -import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart'; +import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart'; import 'package:syncrow_web/services/locator.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -30,6 +29,8 @@ class MyApp extends StatelessWidget { return MultiBlocProvider( providers: [ BlocProvider(create: (context) => HomeBloc()), + BlocProvider( + create: (context) => VisitorPasswordBloc(),) ], child: MaterialApp( debugShowCheckedModeBanner: false, // Hide debug banner diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index 5b406add..4ed61291 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -39,12 +39,9 @@ class AccessBloc extends Bloc { } } void updateTabsCount() { - // Count occurrences based on the type field int toBeEffectiveCount = data.where((item) => item.passwordStatus.value== 'To Be Effective').length; int effectiveCount = data.where((item) => item.passwordStatus.value == 'Effective').length; int expiredCount = data.where((item) => item.passwordStatus.value == 'Expired').length; - - // Update tab labels with counts tabs[1] = 'To Be Effective ($toBeEffectiveCount)'; tabs[2] = 'Effective ($effectiveCount)'; tabs[3] = 'Expired ($expiredCount)'; @@ -53,7 +50,6 @@ class AccessBloc extends Bloc { int selectedIndex = 0; - final List tabs = [ 'All', 'To Be Effective (0)', @@ -76,7 +72,6 @@ class AccessBloc extends Bloc { Future selectTime(SelectTime event, Emitter emit) async { - final DateTime? picked = await showDatePicker( context: event.context, initialDate: DateTime.now(), @@ -146,8 +141,6 @@ class AccessBloc extends Bloc { try { filteredData = data.where((item) { bool matchesCriteria = true; - - // Filter by password name if provided if (event.passwordName != null && event.passwordName!.isNotEmpty) { final bool matchesName = item.passwordName != null && item.passwordName.contains(event.passwordName); @@ -155,8 +148,6 @@ class AccessBloc extends Bloc { matchesCriteria = false; } } - - // Filter by date range if provided if (event.startTime != null && event.endTime != null) { final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); final int? invalidTime = int.tryParse(item.invalidTime.toString()); @@ -170,8 +161,6 @@ class AccessBloc extends Bloc { } } } - - // Filter by tab selection if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To Be Effective') { matchesCriteria = false; } else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') { @@ -179,7 +168,6 @@ class AccessBloc extends Bloc { } else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') { matchesCriteria = false; } - return matchesCriteria; }).toList(); emit(TableLoaded(filteredData)); @@ -206,7 +194,6 @@ class AccessBloc extends Bloc { try { emit(AccessLoaded()); selectedIndex = event.selectedIndex; - // Apply filtering based on selected tab switch (selectedIndex) { case 0: // All filteredData = data; @@ -216,7 +203,6 @@ class AccessBloc extends Bloc { break; case 2: // Effective filteredData = data.where((item) => item.passwordStatus.value == "Effective").toList(); - break; case 3: // Expired filteredData = data.where((item) => item.passwordStatus.value == "Expired").toList(); @@ -225,7 +211,7 @@ class AccessBloc extends Bloc { filteredData = data; } add(FilterDataEvent( - selectedTabIndex: selectedIndex, // Pass the selected tab index + selectedTabIndex: selectedIndex, passwordName: passwordName.text.toLowerCase(), startTime: effectiveTimeTimeStamp, endTime: expirationTimeTimeStamp diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 38fb545e..6245dcda 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -21,17 +21,14 @@ class AccessManagementPage extends StatelessWidget { enableMenuSideba: false, appBarTitle: Row( children: [ - Text( - 'Access Management', + Text('Access Management', style: Theme.of(context).textTheme.headlineLarge, ) ], ), appBarBody: [ - Text( - 'Physical Access', - style: Theme.of(context) - .textTheme + Text('Physical Access', + style: Theme.of(context).textTheme .headlineMedium! .copyWith(color: Colors.white), ), @@ -101,7 +98,9 @@ class AccessManagementPage extends StatelessWidget { height: 20, ), Row( - children: [ + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + textBaseline: TextBaseline.ideographic, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.spaceBetween, @@ -111,7 +110,7 @@ class AccessManagementPage extends StatelessWidget { color: Colors.black,fontSize: 13),), const SizedBox(height: 5,), Container( - height:size.height * 0.053, + height:43, width: size.width * 0.15, decoration: containerDecoration, child: TextFormField( @@ -145,51 +144,44 @@ class AccessManagementPage extends StatelessWidget { ), SizedBox( + height:45, + width: size.width * 0.06, - child: Column( - children: [ - Text(''), - Container( - decoration: containerDecoration, - child: DefaultButton( - onPressed: () { - accessBloc.add(FilterDataEvent( - selectedTabIndex: BlocProvider.of(context).selectedIndex, // Pass the selected tab index - passwordName: accessBloc.passwordName.text.toLowerCase(), - startTime: accessBloc.effectiveTimeTimeStamp, - endTime: accessBloc.expirationTimeTimeStamp - )); - }, borderRadius: 9, - child: const Text('Search'))), - ], - ), + child:Container( + decoration: containerDecoration, + child: DefaultButton( + onPressed: () { + accessBloc.add(FilterDataEvent( + selectedTabIndex: BlocProvider.of(context).selectedIndex, // Pass the selected tab index + passwordName: accessBloc.passwordName.text.toLowerCase(), + startTime: accessBloc.effectiveTimeTimeStamp, + endTime: accessBloc.expirationTimeTimeStamp + )); + }, borderRadius: 9, + child: const Text('Search'))), ), const SizedBox( width: 10, ), SizedBox( + height:45, width: size.width * 0.06, - child: Column( - children: [ - Text(''), - Container( - decoration: containerDecoration, - child: DefaultButton( - onPressed: () { - accessBloc.add(ResetSearch()); - }, - backgroundColor: ColorsManager.whiteColors, - borderRadius: 9, - child: Text( - 'Reset', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: Colors.black), - ), - ), + child: Container( + decoration: containerDecoration, + child: DefaultButton( + onPressed: () { + accessBloc.add(ResetSearch()); + }, + backgroundColor: ColorsManager.whiteColors, + borderRadius: 9, + child: Text( + 'Reset', + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: Colors.black), ), - ], + ), ), ), ], diff --git a/lib/pages/auth/view/login_mobile_page.dart b/lib/pages/auth/view/login_mobile_page.dart index 98402f59..d6544a98 100644 --- a/lib/pages/auth/view/login_mobile_page.dart +++ b/lib/pages/auth/view/login_mobile_page.dart @@ -146,7 +146,6 @@ class LoginMobilePage extends StatelessWidget { textAlign: TextAlign.center, ), ), - isDense: true, style: const TextStyle(color: Colors.black), items:loginBloc.regionList!.map((RegionModel region) { @@ -156,7 +155,6 @@ class LoginMobilePage extends StatelessWidget { ); }).toList(), onChanged: (String? value) { - print(value); }, ), ) diff --git a/lib/pages/common/custom_dialog.dart b/lib/pages/common/custom_dialog.dart new file mode 100644 index 00000000..3b667811 --- /dev/null +++ b/lib/pages/common/custom_dialog.dart @@ -0,0 +1,75 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; + +Future showCustomDialog({ + required BuildContext context, + required String message, + String? title, + String? iconPath, + double? dialogHeight, + double? iconHeight, + double? iconWidth, + VoidCallback? onOkPressed, + bool barrierDismissible = false, required actions, +}) { + return showDialog( + context: context, + barrierDismissible: barrierDismissible, + builder: (BuildContext context) { + final size = MediaQuery.of(context).size; + return AlertDialog( + alignment: Alignment.center, + content: SizedBox( + height: dialogHeight ?? size.height * 0.15, + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (iconPath != null) + SvgPicture.asset( + iconPath, + height: iconHeight ?? 35, + width: iconWidth ?? 35, + ), + if (title != null) + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + title, + style: Theme.of(context).textTheme.headlineLarge!.copyWith( + fontSize: 20, + fontWeight: FontWeight.w400, + color: Colors.black), + ), + ), + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: Text( + message, + style: Theme.of(context) + .textTheme + .bodyMedium! + .copyWith(color: Colors.black), + textAlign: TextAlign.center, + ), + ), + ], + ), + ), + actionsAlignment: MainAxisAlignment.center, + actions: [ + TextButton( + onPressed: onOkPressed ?? () => Navigator.of(context).pop(), + child: Text( + 'OK', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.blackColor, + fontSize: 16), + ), + ), + ], + ); + }, + ); +} diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index b7aa71a5..a691b673 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -15,7 +15,7 @@ class DynamicTable extends StatefulWidget { final void Function(int, bool?)? onRowCheckboxChanged; const DynamicTable({ - Key? key, + super.key, required this.headers, required this.data, required this.size, @@ -25,7 +25,7 @@ class DynamicTable extends StatefulWidget { this.cellDecoration, this.selectAll, this.onRowCheckboxChanged, - }) : super(key: key); + }); @override _DynamicTableState createState() => _DynamicTableState(); @@ -66,7 +66,7 @@ class _DynamicTableState extends State { return Container( decoration: widget.cellDecoration, child: Padding( - padding: const EdgeInsets.all(10.0), + padding: const EdgeInsets.all(2.0), child: ListView( scrollDirection: Axis.horizontal, @@ -102,7 +102,7 @@ class _DynamicTableState extends State { SvgPicture.asset( Assets.emptyTable ), - SizedBox(height: 15,), + const SizedBox(height: 15,), Text('No Passwords',style: Theme.of(context).textTheme.bodySmall!.copyWith(color:ColorsManager.grayColor ),) ], ), @@ -122,9 +122,9 @@ class _DynamicTableState extends State { return Row( children: [ if (widget.withCheckBox) - _buildRowCheckbox(index), + _buildRowCheckbox(index,widget.size.height*0.10), ...row.map((cell) => - _buildTableCell(cell.toString())).toList(), + _buildTableCell(cell.toString(),widget.size.height*0.10)).toList(), ], ); }, @@ -141,8 +141,12 @@ class _DynamicTableState extends State { } Widget _buildSelectAllCheckbox() { - return SizedBox( - width: 50, + return Container( + padding: const EdgeInsets.all(8.0), + + decoration: const BoxDecoration( + border: Border.symmetric( + vertical: BorderSide(color: ColorsManager.boxDivider))), child: Checkbox( value: _selectAll, onChanged: _toggleSelectAll, @@ -150,16 +154,27 @@ class _DynamicTableState extends State { ); } - Widget _buildRowCheckbox(int index) { - return SizedBox( - width: 50, - child: Checkbox( + Widget _buildRowCheckbox(int index,size) { + return Container( + 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, value); }, - ), + ),) ); + } Widget _buildTableHeaderCell(String title) { @@ -177,11 +192,11 @@ class _DynamicTableState extends State { ); } - Widget _buildTableCell(String content) { + Widget _buildTableCell(String content,size) { return Expanded( child: Container( - height: 80, - padding: const EdgeInsets.all(15.0), + height:size , + padding: const EdgeInsets.all(5.0), decoration: const BoxDecoration( border: Border( bottom: BorderSide( diff --git a/lib/pages/common/custom_web_textfield.dart b/lib/pages/common/custom_web_textfield.dart index daaa2c13..363a1994 100644 --- a/lib/pages/common/custom_web_textfield.dart +++ b/lib/pages/common/custom_web_textfield.dart @@ -33,8 +33,7 @@ class CustomWebTextField extends StatelessWidget { children: [ Text('* ', style: Theme.of(context) - .textTheme - .bodyMedium! + .textTheme.bodyMedium! .copyWith(color: Colors.red), ), Text(textFieldName, style: Theme.of(context).textTheme.bodySmall!.copyWith( @@ -46,10 +45,8 @@ class CustomWebTextField extends StatelessWidget { child: Text( description??'', style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith( - fontSize: 9, + .textTheme.bodySmall! + .copyWith(fontSize: 9, fontWeight: FontWeight.w400, color: ColorsManager.textGray), ), @@ -65,21 +62,19 @@ class CustomWebTextField extends StatelessWidget { color: Colors.grey.withOpacity(0.3), spreadRadius:2, blurRadius: 3, - offset: Offset(1, 1), // changes position of shadow + offset: const Offset(1, 1), // changes position of shadow ), ] ), - child: Container( - child: TextFormField( - validator: validator, - controller: controller, - style: const TextStyle(color: Colors.black), - decoration: textBoxDecoration()! - .copyWith( - errorStyle: const TextStyle(height: 0), // Hide the error text space + child: TextFormField( + validator: validator, + controller: controller, + style: const TextStyle(color: Colors.black), + decoration: textBoxDecoration()! + .copyWith( + errorStyle: const TextStyle(height: 0), // Hide the error text space - hintText: 'Please enter'), - ), + hintText: 'Please enter'), ), ), ], diff --git a/lib/pages/common/hour_picker_dialog.dart b/lib/pages/common/hour_picker_dialog.dart index 63e95e21..718f1ebf 100644 --- a/lib/pages/common/hour_picker_dialog.dart +++ b/lib/pages/common/hour_picker_dialog.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; class HourPickerDialog extends StatefulWidget { final TimeOfDay initialTime; - HourPickerDialog({required this.initialTime}); + const HourPickerDialog({super.key, required this.initialTime}); @override _HourPickerDialogState createState() => _HourPickerDialogState(); @@ -24,7 +24,7 @@ class _HourPickerDialogState extends State { @override Widget build(BuildContext context) { return AlertDialog( - title: Text('Select Hour'), + title: const Text('Select Hour'), content: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ @@ -46,7 +46,7 @@ class _HourPickerDialogState extends State { SizedBox(width: 16.0), DropdownButton( value: _isPm, - items: [ + items: const [ DropdownMenuItem( value: false, child: Text('AM'), @@ -67,14 +67,14 @@ class _HourPickerDialogState extends State { actions: [ TextButton( onPressed: () => Navigator.of(context).pop(null), - child: Text('Cancel'), + child: const Text('Cancel'), ), TextButton( onPressed: () { int hour = _isPm ? _selectedHour + 12 : _selectedHour; Navigator.of(context).pop(TimeOfDay(hour: hour, minute: 0)); }, - child: Text('OK'), + child: const Text('OK'), ), ], ); diff --git a/lib/pages/common/info_dialog.dart b/lib/pages/common/info_dialog.dart index 4465ced6..cfd2cbd4 100644 --- a/lib/pages/common/info_dialog.dart +++ b/lib/pages/common/info_dialog.dart @@ -66,7 +66,7 @@ class InfoDialog extends StatelessWidget { onPressed: () { Navigator.of(context).pop(); }, - child: Text('OK'), + child: const Text('OK'), ), ], ); diff --git a/lib/pages/home/view/home_page_web.dart b/lib/pages/home/view/home_page_web.dart index 0124acad..39a79a57 100644 --- a/lib/pages/home/view/home_page_web.dart +++ b/lib/pages/home/view/home_page_web.dart @@ -2,13 +2,11 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/pages/home/bloc/home_bloc.dart'; +import 'package:syncrow_web/pages/home/bloc/home_state.dart'; import 'package:syncrow_web/pages/home/view/home_card.dart'; -import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; -import '../bloc/home_state.dart'; - class HomeWebPage extends StatelessWidget { HomeWebPage({super.key}); @override diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index ff3b57e4..ee40de87 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -2,6 +2,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; +import 'package:syncrow_web/pages/common/custom_dialog.dart'; import 'package:syncrow_web/pages/common/hour_picker_dialog.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart'; @@ -9,9 +10,9 @@ import 'package:syncrow_web/pages/visitor_password/model/device_model.dart'; import 'package:syncrow_web/pages/visitor_password/model/schedule_model.dart'; import 'package:syncrow_web/services/access_mang_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; - class VisitorPasswordBloc extends Bloc { VisitorPasswordBloc() : super(VisitorPasswordInitial()) { @@ -23,10 +24,8 @@ class VisitorPasswordBloc on(toggleDaySelection); on(selectDevice); on(_onUpdateFilteredDevices); - on(postOnlineOneTimePassword); on(postOnlineMultipleTimePassword); - on(postOfflineMultipleTimePassword); on(postOfflineOneTimePassword); on(selectTimeOfLinePassword); @@ -58,16 +57,12 @@ class VisitorPasswordBloc int? effectiveTimeTimeStamp; int? expirationTimeTimeStamp; - int? repeatEffectiveTimeTimeStamp; - int? repeatExpirationTimeTimeStamp; - DateTime? startTime = DateTime.now(); DateTime? endTime; String startTimeAccess = 'Start Time'; String endTimeAccess = 'End Time'; - selectAccessType( SelectPasswordType event, Emitter emit) { accessTypeSelected = event.type; @@ -81,9 +76,9 @@ class VisitorPasswordBloc } Future selectTimeVisitorPassword( - SelectTimeVisitorPassword event, - Emitter emit, - ) async { + SelectTimeVisitorPassword event, + Emitter emit, + ) async { final DateTime? picked = await showDatePicker( context: event.context, initialDate: DateTime.now(), @@ -122,7 +117,8 @@ class VisitorPasswordBloc timePicked.minute, ); - final selectedTimestamp = selectedDateTime.millisecondsSinceEpoch ~/ 1000; + final selectedTimestamp = + selectedDateTime.millisecondsSinceEpoch ~/ 1000; if (event.isStart) { if (expirationTimeTimeStamp != null && @@ -133,9 +129,7 @@ class VisitorPasswordBloc return; } effectiveTimeTimeStamp = selectedTimestamp; - - startTimeAccess = selectedDateTime.toString().split('.').first; - + startTimeAccess = selectedDateTime.toString().split('.').first; } else { if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) { @@ -145,11 +139,8 @@ class VisitorPasswordBloc return; } expirationTimeTimeStamp = selectedTimestamp; - - endTimeAccess = selectedDateTime.toString().split('.').first; - + endTimeAccess = selectedDateTime.toString().split('.').first; } - emit(ChangeTimeState()); emit(VisitorPasswordInitial()); } @@ -201,10 +192,10 @@ class VisitorPasswordBloc } //online password - Future postOnlineOneTimePassword(OnlineOneTimePasswordEvent event, Emitter emit) async { try { + emit(LoadingInitialState()); generate7DigitNumber(); bool res = await AccessMangApi().postOnlineOneTime( email: event.email, @@ -213,27 +204,37 @@ class VisitorPasswordBloc passwordName: event.passwordName, effectiveTime: effectiveTimeTimeStamp.toString(), invalidTime: expirationTimeTimeStamp.toString()); - if (res = true) { - Navigator.pop(event.context!); + if (res == true) { + emit(SuccessState()); + } else { + throw Exception('Failed to create password'); } emit(TableLoaded(data)); } catch (e) { - emit(FailedState(e.toString())); + Navigator.pop(event.context!); + stateDialog( + context: event.context!, + message: e.toString(), + title: 'Something Wrong'); } } + Future postOnlineMultipleTimePassword( OnlineMultipleTimePasswordEvent event, Emitter emit) async { try { - generate7DigitNumber(); - bool res = await AccessMangApi().postOnlineMultipleTime( + emit(LoadingInitialState()); + + await generate7DigitNumber(); + bool res = await AccessMangApi().postOnlineMultipleTime( scheduleList: [ if (repeat) Schedule( effectiveTime: getTimeFromDateTimeString(expirationTime), - invalidTime: getTimeFromDateTimeString(effectiveTime).toString(), + invalidTime: + getTimeFromDateTimeString(effectiveTime).toString(), workingDay: selectedDays, ), ], @@ -243,9 +244,11 @@ class VisitorPasswordBloc email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName); - if(res==true){ - Navigator.pop(event.context!); + if (res == true) { + emit(SuccessState()); + emit(TableLoaded(data)); } + } catch (e) { emit(FailedState(e.toString())); } @@ -255,11 +258,16 @@ class VisitorPasswordBloc Future postOfflineOneTimePassword(OfflineOneTimePasswordEvent event, Emitter emit) async { try { - generate7DigitNumber(); - await AccessMangApi().postOffLineOneTime( + emit(LoadingInitialState()); + await generate7DigitNumber(); + bool res = await AccessMangApi().postOffLineOneTime( email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName); + if (res == true) { + emit(SuccessState()); + emit(TableLoaded(data)); + } } catch (e) { emit(FailedState(e.toString())); } @@ -269,15 +277,19 @@ class VisitorPasswordBloc OfflineMultipleTimePasswordEvent event, Emitter emit) async { try { - generate7DigitNumber(); - await AccessMangApi().postOffLineMultipleTime( - email: event.email, - devicesUuid: selectedDevices, - passwordName: event.passwordName, + emit(LoadingInitialState()); + await generate7DigitNumber(); + bool res = await AccessMangApi().postOffLineMultipleTime( + email: event.email, + devicesUuid: selectedDevices, + passwordName: event.passwordName, invalidTime: expirationTimeTimeStamp.toString(), effectiveTime: effectiveTimeTimeStamp.toString(), - ); + if (res == true) { + emit(SuccessState()); + emit(TableLoaded(data)); + } } catch (e) { emit(FailedState(e.toString())); } @@ -300,13 +312,11 @@ class VisitorPasswordBloc } Future generate7DigitNumber() async { - emit(LoadingInitialState()); passwordController = ''; Random random = Random(); int min = 1000000; int max = 9999999; passwordController = (min + random.nextInt(max - min + 1)).toString(); - emit(GeneratePasswordState()); return passwordController; } @@ -319,12 +329,10 @@ class VisitorPasswordBloc final deviceName = deviceNameController.text.toLowerCase(); final deviceId = deviceIdController.text.toLowerCase(); final unitName = unitNameController.text.toLowerCase(); - final filteredData = data.where((device) { final matchesDeviceName = device.name.toLowerCase().contains(deviceName); final matchesDeviceId = device.uuid.toLowerCase().contains(deviceId); // final matchesUnitName = device.unitName.toLowerCase().contains(unitName); // Assuming unitName is a property of the device - return matchesDeviceName && matchesDeviceId; }).toList(); add(UpdateFilteredDevicesEvent(filteredData)); @@ -334,7 +342,6 @@ class VisitorPasswordBloc Stream mapEventToState( VisitorPasswordEvent event) async* { if (event is FetchDevice) { - // Fetching logic... } else if (event is UpdateFilteredDevicesEvent) { yield TableLoaded(event.filteredData); } @@ -347,10 +354,11 @@ class VisitorPasswordBloc addDeviceToList(context) { selectedDevices = selectedDeviceIds; - Navigator.of(context).pop(selectedDevices); // Close the dialog + Navigator.of(context).pop(selectedDevices); } - Future selectTimeOfLinePassword(SelectTimeEvent event, Emitter emit) async { + Future selectTimeOfLinePassword( + SelectTimeEvent event, Emitter emit) async { emit(ChangeTimeState()); final DateTime? picked = await showDatePicker( context: event.context, @@ -416,11 +424,10 @@ class VisitorPasswordBloc endTime = event.val; } } + DateTime? convertStringToDateTime(String dateTimeString) { try { - // Define the input format. Adjust this pattern based on your input string format. final DateFormat inputFormat = DateFormat('yyyy-MM-dd HH:mm:ss'); - // Convert the string to a DateTime object. DateTime dateTime = inputFormat.parse(dateTimeString); return dateTime; } catch (e) { @@ -432,8 +439,6 @@ class VisitorPasswordBloc String getTimeFromDateTimeString(String dateTimeString) { DateTime? dateTime = convertStringToDateTime(dateTimeString); if (dateTime == null) return ''; - - // Extract the time component from the DateTime object. return DateFormat('HH:mm').format(dateTime); } @@ -444,4 +449,27 @@ class VisitorPasswordBloc return null; } + Future stateDialog({ + BuildContext? context, + String? message, + String? title, + dynamic actions, + }) { + return showCustomDialog( + context: context!, + message: message!, + iconPath: Assets.deviceNoteIcon, + title: title, + dialogHeight: 150, + actions: actions ?? + [ + TextButton( + onPressed: () { + Navigator.of(context).pop(); + }, + child: const Text('OK'), + ), + ], + ); + } } diff --git a/lib/pages/visitor_password/bloc/visitor_password_event.dart b/lib/pages/visitor_password/bloc/visitor_password_event.dart index 723ac052..05ad73d1 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_event.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_event.dart @@ -77,11 +77,12 @@ class OnlineMultipleTimePasswordEvent extends VisitorPasswordEvent { //offline password class OfflineOneTimePasswordEvent extends VisitorPasswordEvent { + final BuildContext? context; final String? email; final String? passwordName; - const OfflineOneTimePasswordEvent({this.email,this.passwordName}); + const OfflineOneTimePasswordEvent({this.email,this.passwordName,this.context}); @override - List get props => [email!,passwordName!,]; + List get props => [email!,passwordName!,context!,]; } class OfflineMultipleTimePasswordEvent extends VisitorPasswordEvent { @@ -89,11 +90,12 @@ class OfflineMultipleTimePasswordEvent extends VisitorPasswordEvent { final String? passwordName; final String? invalidTime; final String? effectiveTime; + final BuildContext? context; - const OfflineMultipleTimePasswordEvent({this.email,this.passwordName,this.invalidTime,this.effectiveTime}); + const OfflineMultipleTimePasswordEvent({this.context,this.email,this.passwordName,this.invalidTime,this.effectiveTime}); @override - List get props => [email!,passwordName!,invalidTime!,effectiveTime!]; + List get props => [email!,passwordName!,invalidTime!,effectiveTime!,context!]; } diff --git a/lib/pages/visitor_password/bloc/visitor_password_state.dart b/lib/pages/visitor_password/bloc/visitor_password_state.dart index 27008a30..279c9809 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_state.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_state.dart @@ -43,7 +43,7 @@ class LoadingInitialState extends VisitorPasswordState {} class ChangeTimeState extends VisitorPasswordState {} class TimeSelectedState extends VisitorPasswordState {} class DeviceLoaded extends VisitorPasswordState {} -class GeneratePasswordState extends VisitorPasswordState {} +class SuccessState extends VisitorPasswordState {} class FailedState extends VisitorPasswordState { final String message; diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index 9d7be636..eccdfd78 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -12,7 +12,6 @@ import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/const.dart'; import 'package:syncrow_web/utils/style.dart'; - class AddDeviceDialog extends StatelessWidget { const AddDeviceDialog({super.key}); @override @@ -54,7 +53,7 @@ class AddDeviceDialog extends StatelessWidget { width: 15, ), ), - SizedBox(width: 10,), + const SizedBox(width: 10,), Text('Only online accessible devices can be added', style: Theme.of(context).textTheme.bodySmall!.copyWith( fontWeight: FontWeight.w400, @@ -63,13 +62,15 @@ class AddDeviceDialog extends StatelessWidget { ], ) ), - SizedBox(height: 20,), + const SizedBox(height: 20,), Row( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.end, + textBaseline: TextBaseline.alphabetic, + children: [ Expanded( - flex: 2, + flex: 4, child: CustomWebTextField( controller: visitorBloc.deviceNameController, isRequired: true, @@ -79,7 +80,7 @@ class AddDeviceDialog extends StatelessWidget { ), const SizedBox(width: 10), Expanded( - flex: 2, + flex: 4, child: CustomWebTextField( controller: visitorBloc.deviceIdController, isRequired: true, @@ -89,7 +90,7 @@ class AddDeviceDialog extends StatelessWidget { ), const SizedBox(width: 10), Expanded( - flex: 2, + flex: 4, child: CustomWebTextField( controller: visitorBloc.unitNameController, isRequired: true, @@ -97,67 +98,49 @@ class AddDeviceDialog extends StatelessWidget { description: '', ), ), - const SizedBox(width: 10), - Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 25), - Center( - child: Container( - height: 43, - width: 100, - decoration: containerDecoration, - child: Center( - child: DefaultButton( - onPressed: () { - visitorBloc.filterDevices(); // Call filter function - }, - borderRadius: 9, - child: const Text('Search'), - ), + Expanded( + flex: 2, + child: Container( + child: SizedBox( + width: size.width * 0.06, + child: Center( + child: DefaultButton( + onPressed: () { + visitorBloc.filterDevices(); + }, + borderRadius: 9, + child: const Text('Search'), ), ), ), - - ], + ), ), const SizedBox(width: 10), - Column( - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - const SizedBox(height: 25), - - Center( - child: Container( - height: 43, - width: 100, - decoration: containerDecoration, - child: Center( - child: DefaultButton( - backgroundColor: ColorsManager.whiteColors, - borderRadius: 9, - child: Text( - 'Reset', - style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black), - ), - onPressed: () { - visitorBloc.deviceNameController.clear(); - visitorBloc.deviceIdController.clear(); - visitorBloc.unitNameController.clear(); - visitorBloc.add(FetchDevice()); // Reset to original list - }, - ), - ), + Expanded( + flex: 2, + child: Container( + width: size.width * 0.06, + child: DefaultButton( + backgroundColor: ColorsManager.whiteColors, + borderRadius: 9, + child: Text('Reset', + style: Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black), ), + onPressed: () { + visitorBloc.deviceNameController.clear(); + visitorBloc.deviceIdController.clear(); + visitorBloc.unitNameController.clear(); + visitorBloc.add(FetchDevice()); // Reset to original list + }, ), - ], - ), - + ), + ) ], ), const SizedBox(height: 20), Expanded( + flex: 3, child: state is TableLoaded ? DynamicTable( cellDecoration: containerDecoration, diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index 1f7e3a14..0aa63638 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -1,11 +1,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:flutter_svg/flutter_svg.dart'; +import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/pages/common/custom_web_textfield.dart'; import 'package:syncrow_web/pages/common/date_time_widget.dart'; import 'package:syncrow_web/pages/common/default_button.dart'; -import 'package:syncrow_web/pages/common/info_dialog.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart'; @@ -21,441 +20,517 @@ class VisitorPasswordDialog extends StatelessWidget { @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; + var text = Theme.of(context).textTheme.bodySmall!.copyWith( + color: Colors.black,fontSize: 13); return BlocProvider( create: (context) => VisitorPasswordBloc(), - child: BlocBuilder( - builder: (BuildContext context, VisitorPasswordState state) { + child: BlocListener( + listener: (context, state) { final visitorBloc = BlocProvider.of(context); - bool isRepeat = - state is IsRepeatState ? state.repeat : visitorBloc.repeat; - return AlertDialog( - backgroundColor: Colors.white, - title: Text( - 'Create visitor password', - style: Theme.of(context).textTheme.headlineLarge!.copyWith( - fontWeight: FontWeight.w400, - fontSize: 24, - color: Colors.black), - ), - content: SingleChildScrollView( - child: Form( - key: visitorBloc.forgetFormKey, - child: Padding( - padding: const EdgeInsets.all(5.0), - child: ListBody( - children: [ - Container( - child: Row( - children: [ - Expanded( - flex: 2, - child: CustomWebTextField( - validator: visitorBloc.validate, - controller: visitorBloc.userNameController, - isRequired: true, - textFieldName: 'Name', - description: '', - ), - ), - const Spacer(), - Expanded( - flex: 2, - child: CustomWebTextField( - validator: visitorBloc.validateEmail, - controller: visitorBloc.emailController, - isRequired: true, - textFieldName: 'Email Address', - description: - 'The password will be sent to the visitor’s email address.', - ), - ), - const Spacer(), - ], - ), - ), - const SizedBox( - height: 15, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( + if (state is SuccessState) { + visitorBloc.stateDialog( + context: context, + message: 'Password Created Successfully', + title: 'Send Success', + ); + } else if (state is FailedState) { + visitorBloc.stateDialog( + context: context, + message: state.message, + title: 'Something Wrong', + ); + } + }, + child: BlocBuilder( + builder: (BuildContext context, VisitorPasswordState state) { + final visitorBloc = BlocProvider.of(context); + bool isRepeat = state is IsRepeatState ? state.repeat : visitorBloc.repeat; + return AlertDialog( + backgroundColor: Colors.white, + title: Text( + 'Create visitor password', + style: Theme.of(context).textTheme.headlineLarge!.copyWith( + fontWeight: FontWeight.w400, + fontSize: 24, + color: Colors.black), + ), + content: + state is LoadingInitialState ?const Center(child: CircularProgressIndicator()): + SingleChildScrollView( + child: Form( + key: visitorBloc.forgetFormKey, + child: Padding( + padding: const EdgeInsets.all(5.0), + child: ListBody( + children: [ + Container( + child: Row( children: [ - Text( - '* ', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Colors.red), + Expanded( + flex: 2, + child: CustomWebTextField( + validator: visitorBloc.validate, + controller: visitorBloc.userNameController, + isRequired: true, + textFieldName: 'Name', + description: '', + ), ), - Text('Access Type', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13),), + const Spacer(), + Expanded( + flex: 2, + child: CustomWebTextField( + validator: visitorBloc.validateEmail, + controller: visitorBloc.emailController, + isRequired: true, + textFieldName: 'Email Address', + description: + 'The password will be sent to the visitor’s email address.', + ), + ), + const Spacer(), ], ), - Row( - children: [ - SizedBox( - width: size.width * 0.15, - child: RadioListTile( - title: Text('Online Password', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13), - ), - value: 'Online Password', - groupValue: (state is PasswordTypeSelected) - ? state.selectedType - : visitorBloc.accessTypeSelected, - onChanged: (String? value) { - if (value != null) { - print(value); - context - .read() - .add(SelectPasswordType(value)); - } - }, - ), - ), - SizedBox( - width: size.width * 0.15, - child: RadioListTile( - title: Text('Offline Password', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13),), - value: 'Offline Password', - groupValue: (state is PasswordTypeSelected) - ? state.selectedType - : visitorBloc.accessTypeSelected, - onChanged: (String? value) { - if (value != null) { - context.read() - .add(SelectPasswordType(value)); - } - }, - ), - ), - SizedBox( - width: size.width * 0.15, - child: RadioListTile( - title: Text('Dynamic Password', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13),), - value: 'Dynamic Password', - groupValue: (state is PasswordTypeSelected) - ? state.selectedType - : visitorBloc.accessTypeSelected, - onChanged: (String? value) { - if (value != null) { - context - .read() - .add(SelectPasswordType(value)); - visitorBloc.usageFrequencySelected = ''; - } - }, - ), - ), - ], - ), - Text( - 'Only currently online devices can be selected. It is recommended to use when the device network is stable, and the system randomly generates a digital password', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.grayColor,fontSize: 9),), - const SizedBox( - height: 20, - ) - ], - ), - visitorBloc.accessTypeSelected == 'Dynamic Password' - ? SizedBox() - : Column( - crossAxisAlignment: CrossAxisAlignment.start, + ), + const SizedBox( + height: 15, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( children: [ - Row( - children: [ - Text( - '* ', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Colors.red), - ), - Text('Usage Frequency',style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13),), - ], + Text( + '* ', + style: Theme.of(context).textTheme + .bodyMedium!.copyWith(color: Colors.red), ), - Row( - children: [ - SizedBox( - width: 200, - child: RadioListTile( - title: Text('One-Time', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13),), - value: 'One-Time', - groupValue: - (state is UsageFrequencySelected) - ? state.selectedFrequency - : visitorBloc.usageFrequencySelected, - onChanged: (String? value) { - if (value != null) { - context.read() - .add(SelectUsageFrequency(value)); - } - }, - ), - ), - SizedBox( - width: 200, - child: RadioListTile( - title: Text('Periodic', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13),), - value: 'Periodic', - groupValue: (state is UsageFrequencySelected) - ? state.selectedFrequency - : visitorBloc.usageFrequencySelected, - onChanged: (String? value) { - if (value != null) { - context - .read() - .add(SelectUsageFrequency(value)); - } - }, - ), - ), - ], - ), - Text('Within the validity period, each device can be unlocked only once.', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor,fontSize: 9), - ) + Text('Access Type', + style:text ), ], ), - const SizedBox( - height: 20, - ), - if ((visitorBloc.usageFrequencySelected != 'One-Time' || - visitorBloc.accessTypeSelected != 'Offline Password') && - (visitorBloc.usageFrequencySelected != '')) - DateTimeWebWidget( - isTime: false, - isRequired: true, - title: 'Access Period', - size: size, - endTime: () { - visitorBloc.add(SelectTimeVisitorPassword( - context: context, - isStart: false, - isRepeat: false)); - }, - startTime: () { - visitorBloc.add(SelectTimeVisitorPassword( - context: context, - isStart: true, - isRepeat: false)); - }, - firstString: visitorBloc.startTimeAccess.toString(), - secondString: visitorBloc.endTimeAccess.toString(), + Row( + children: [ + SizedBox( + width: size.width * 0.15, + child: RadioListTile( + title: Text('Online Password', + style: text, + ), + value: 'Online Password', + groupValue: (state is PasswordTypeSelected) + ? state.selectedType + : visitorBloc.accessTypeSelected, + onChanged: (String? value) { + if (value != null) { + context.read() + .add(SelectPasswordType(value)); + } + }, + ), + ), + SizedBox( + width: size.width * 0.15, + child: RadioListTile( + title: Text('Offline Password', + style:text ), + value: 'Offline Password', + groupValue: (state is PasswordTypeSelected) + ? state.selectedType + : visitorBloc.accessTypeSelected, + onChanged: (String? value) { + if (value != null) { + context.read().add(SelectPasswordType(value)); + } + }, + ), + ), + SizedBox( + width: size.width * 0.15, + child: RadioListTile( + title: Text('Dynamic Password', + style: text,), + value: 'Dynamic Password', + groupValue: (state is PasswordTypeSelected) + ? state.selectedType + : visitorBloc.accessTypeSelected, + onChanged: (String? value) { + if (value != null) { + context.read() + .add(SelectPasswordType(value)); + visitorBloc.usageFrequencySelected = ''; + } + }, + ), + ), + ], + ), + Text( + 'Only currently online devices can be selected. It is recommended to use when the device network is stable, and the system randomly generates a digital password', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.grayColor,fontSize: 9),), + const SizedBox( + height: 20, + ) + ], ), - const SizedBox( - height: 20, - ), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - '* ', - style: Theme.of(context) - .textTheme - .bodyMedium! - .copyWith(color: Colors.red), - ), - Text('Access Devices', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13),), - ], + visitorBloc.accessTypeSelected == 'Dynamic Password' + ? const SizedBox() + : Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text('* ', + style: Theme.of(context).textTheme.bodyMedium! + .copyWith(color: Colors.red), + ), + Text('Usage Frequency',style:text ,), + ], + ), + Row( + children: [ + SizedBox( + width: 200, + child: RadioListTile( + title: Text('One-Time', + style:text ,), + value: 'One-Time', + groupValue: + (state is UsageFrequencySelected) + ? state.selectedFrequency + : visitorBloc.usageFrequencySelected, + onChanged: (String? value) { + if (value != null) { + context.read() + .add(SelectUsageFrequency(value)); + } + }, + ), + ), + SizedBox( + width: 200, + child: RadioListTile( + title: Text('Periodic', + style: text), + value: 'Periodic', + groupValue: (state is UsageFrequencySelected) + ? state.selectedFrequency + : visitorBloc.usageFrequencySelected, + onChanged: (String? value) { + if (value != null) { + context.read() + .add(SelectUsageFrequency(value)); + } + }, + ), + ), + ], + ), + Text('Within the validity period, each device can be unlocked only once.', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor,fontSize: 9), + ) + ], + ), + const SizedBox( + height: 20, + ), + if ((visitorBloc.usageFrequencySelected != 'One-Time' || + visitorBloc.accessTypeSelected != 'Offline Password') && + (visitorBloc.usageFrequencySelected != '')) + DateTimeWebWidget( + isTime: false, + isRequired: true, + title: 'Access Period', + size: size, + endTime: () { + visitorBloc.add(SelectTimeVisitorPassword( + context: context, + isStart: false, + isRepeat: false)); + }, + startTime: () { + visitorBloc.add(SelectTimeVisitorPassword( + context: context, + isStart: true, + isRepeat: false)); + }, + firstString: visitorBloc.startTimeAccess.toString(), + secondString: visitorBloc.endTimeAccess.toString(), ), - Text( - 'Within the validity period, each device can be unlocked only once.', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.grayColor,fontSize: 9),), - const SizedBox( - height: 20, - ), - if (visitorBloc.usageFrequencySelected == 'Periodic' && - visitorBloc.accessTypeSelected == 'Online Password') - SizedBox( - width: 100, - child: Column( - children: [ - Text('Repeat', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13),), - Transform.scale( - scale: .8, - child: CupertinoSwitch( - value: visitorBloc.repeat, - onChanged: (value) { - visitorBloc.add(ToggleRepeatEvent()); - }, - applyTheme: true, - ), - ), - ], + const SizedBox( + height: 20, + ), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + Text('* ', + style: Theme.of(context).textTheme.bodyMedium! + .copyWith(color: Colors.red), + ), + Text('Access Devices', + style:text ,), + ], + ), + Text( + 'Within the validity period, each device can be unlocked only once.', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.grayColor,fontSize: 9),), + const SizedBox( + height: 20, + ), + if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Online Password') + SizedBox( + width: 100, + child: Column( + children: [ + Text('Repeat', + style:text), + Transform.scale( + scale: .8, + child: CupertinoSwitch( + value: visitorBloc.repeat, + onChanged: (value) { + visitorBloc.add(ToggleRepeatEvent()); + }, + applyTheme: true, + ), + ), + ], + ), + ), + if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Online Password') + isRepeat ? const RepeatWidget() : const SizedBox(), + Container( + decoration: containerDecoration, + width: size.width * 0.08, + child: DefaultButton( + onPressed: () { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return const AddDeviceDialog(); + }, + ).then((listDevice) { + if(listDevice!=null){ + visitorBloc.selectedDevices = listDevice; + } + }); + }, + borderRadius: 8, + child: Text('+ Add Device',style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.whiteColors,fontSize: 12),), ), ), - if (visitorBloc.usageFrequencySelected == 'Periodic' && - visitorBloc.accessTypeSelected == 'Online Password') - isRepeat ? const RepeatWidget() : const SizedBox(), - Container( - decoration: containerDecoration, - width: size.width * 0.08, - child: DefaultButton( - onPressed: () { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return const AddDeviceDialog(); - }, - ).then((listDevice) { - if(listDevice!=null){ - print('selectedDevices==$listDevice'); - visitorBloc.selectedDevices = listDevice; + ], + ), + ], + ), + ), + ), + ), + actionsAlignment: MainAxisAlignment.center, + actions: [ + Container( + decoration: containerDecoration, + width: size.width * 0.2, + child: DefaultButton( + borderRadius: 8, + onPressed: () { + Navigator.of(context).pop(); // Close the dialog + }, + backgroundColor: Colors.white, + child: Text( + 'Cancel', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.blackColor,fontSize: 16), + ), + ), + ), + Container( + decoration: containerDecoration, + width: size.width * 0.2, + child: DefaultButton( + onPressed: () { + if (visitorBloc.forgetFormKey.currentState!.validate()) { + if(visitorBloc.selectedDevices.isNotEmpty){ + if(visitorBloc.effectiveTimeTimeStamp!=null&&visitorBloc.expirationTimeTimeStamp!=null) { + setPasswordFunction(context, size, visitorBloc); + } + else{ + visitorBloc.stateDialog(context: + context,message: 'Please select Access Period to continue',title: 'Access Period'); + } + }else{ + visitorBloc.stateDialog(context: + context,message: 'Please select devices to continue',title: 'Select Devices'); + } + } + }, + borderRadius: 8, + child: Text('Ok', style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.whiteColors,fontSize: 16),), + ), + ), + ], + ); }, + ), + ), - } - }); + ); + } - }, - borderRadius: 8, - child: Text('+ Add Device',style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.whiteColors,fontSize: 12),), + Future setPasswordFunction( + BuildContext context, + Size size, + VisitorPasswordBloc visitorBloc, + ) { + return showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return BlocBuilder( + builder: (context, state) { + if (state is LoadingInitialState) { + // Show loading indicator while loading + return AlertDialog( + alignment: Alignment.center, + content: SizedBox( + height: size.height * 0.25, + child: Center( + child: CircularProgressIndicator(), // Display a loading spinner + ), + ), + ); + }else{ + return AlertDialog( + alignment: Alignment.center, + content: SizedBox( + height: size.height * 0.25, + child: Column( + children: [ + Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + SizedBox( + child: SvgPicture.asset( + Assets.deviceNoteIcon, + height: 35, + width: 35, + ), + ), + Text( + 'Set Password', + style: Theme.of(context).textTheme.headlineLarge!.copyWith( + fontSize: 30, + fontWeight: FontWeight.w400, + color: Colors.black, ), ), ], ), + const SizedBox(width: 15), + Text( + 'This action will update all of the selected\n door locks passwords in the property.\n\nAre you sure you want to continue?', + textAlign: TextAlign.center, + style: Theme.of(context).textTheme.bodyMedium!.copyWith( + color: ColorsManager.grayColor, + fontWeight: FontWeight.w400, + fontSize: 18, + ), + ), ], ), ), - ), - ), - actionsAlignment: MainAxisAlignment.center, - actions: [ - Container( - decoration: containerDecoration, - width: size.width * 0.2, - child: DefaultButton( - borderRadius: 8, - onPressed: () { - Navigator.of(context).pop(); // Close the dialog - }, - backgroundColor: Colors.white, - child: Text( - 'Cancel', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.blackColor,fontSize: 16), + actionsAlignment: MainAxisAlignment.center, + actions: [ + Container( + decoration: containerDecoration, + width: size.width * 0.1, + child: DefaultButton( + borderRadius: 8, + onPressed: () { + Navigator.of(context).pop(); + }, + backgroundColor: Colors.white, + child: Text( + 'Cancel', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.blackColor, + fontSize: 16, + ), + ), + ), ), - ), - ), - Container( - decoration: containerDecoration, - width: size.width * 0.2, - child: DefaultButton( - onPressed: () { - if (visitorBloc.forgetFormKey.currentState!.validate()) { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return InfoDialog( - size: size, - title: 'Set Password', - content: - 'This action will update all of the selected\n door locks passwords in the property.\n\nAre you sure you want to continue?', - actions: [ - Container( - decoration: containerDecoration, - width: size.width * 0.1, - child: DefaultButton( - borderRadius: 8, - onPressed: () { - Navigator.of(context).pop(); - }, - backgroundColor: Colors.white, - child: Text( - 'Cancel', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.blackColor,fontSize: 16), - ), - ), - ), - Container( - decoration: containerDecoration, - width: size.width * 0.1, - child: DefaultButton( - borderRadius: 8, - onPressed: () { - if (visitorBloc.usageFrequencySelected == 'One-Time' && - visitorBloc.accessTypeSelected == 'Online Password') { - visitorBloc.add( - OnlineOneTimePasswordEvent( - context: context, - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text)); - } else if (visitorBloc.usageFrequencySelected == 'Periodic' && - visitorBloc.accessTypeSelected == 'Online Password') { - visitorBloc.add(OnlineMultipleTimePasswordEvent( - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), - invalidTime: visitorBloc.expirationTimeTimeStamp.toString())); - } else if (visitorBloc.usageFrequencySelected == 'One-Time' && - visitorBloc.accessTypeSelected == 'Offline Password') { - visitorBloc.add(OfflineOneTimePasswordEvent( - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - )); - } else if (visitorBloc.usageFrequencySelected == 'Periodic' && - visitorBloc.accessTypeSelected == 'Offline Password') { - visitorBloc.add( - OfflineMultipleTimePasswordEvent( - passwordName: visitorBloc.userNameController.text, - email: visitorBloc.emailController.text, - effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), - invalidTime: visitorBloc.expirationTimeTimeStamp.toString())); - } - }, - child: Text('Ok', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.whiteColors,fontSize: 16), - ), - ), - ), - ], - ); - }, - ); - } - }, - borderRadius: 8, - child: Text('Ok', style: Theme.of(context).textTheme.bodySmall!.copyWith( - fontWeight: FontWeight.w400, - color: ColorsManager.whiteColors,fontSize: 16),), - ), - ), - ], - ); - }, - ), + Container( + decoration: containerDecoration, + width: size.width * 0.1, + child: DefaultButton( + borderRadius: 8, + onPressed: () { + Navigator.pop(context); + if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Online Password') { + visitorBloc.add(OnlineOneTimePasswordEvent( + context: context, + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + )); + } else if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Online Password') { + visitorBloc.add(OnlineMultipleTimePasswordEvent( + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), + invalidTime: visitorBloc.expirationTimeTimeStamp.toString(), + )); + } else if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Offline Password') { + visitorBloc.add(OfflineOneTimePasswordEvent( + context: context, + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + )); + } else if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password') { + visitorBloc.add(OfflineMultipleTimePasswordEvent( + passwordName: visitorBloc.userNameController.text, + email: visitorBloc.emailController.text, + effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(), + invalidTime: visitorBloc.expirationTimeTimeStamp.toString(), + )); + } + }, + child: Text( + 'Ok', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: FontWeight.w400, + color: ColorsManager.whiteColors, + fontSize: 16, + ), + ), + ), + ), + ], + ); + } + }, + ); + }, ); } } diff --git a/lib/services/access_mang_api.dart b/lib/services/access_mang_api.dart index 26d7eeea..6a2cf40d 100644 --- a/lib/services/access_mang_api.dart +++ b/lib/services/access_mang_api.dart @@ -2,12 +2,11 @@ import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:syncrow_web/pages/access_management/model/password_model.dart'; +import 'package:syncrow_web/pages/visitor_password/model/device_model.dart'; import 'package:syncrow_web/pages/visitor_password/model/schedule_model.dart'; import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/utils/constants/api_const.dart'; -import '../pages/visitor_password/model/device_model.dart'; - class AccessMangApi{ Future> fetchVisitorPassword() async { @@ -17,7 +16,6 @@ class AccessMangApi{ showServerMessage: true, expectedResponseModel: (json) { List jsonData = json; - print('Password List: $json'); List passwordList = jsonData.map((jsonItem) { return PasswordModel.fromJson(jsonItem); }).toList(); @@ -38,7 +36,6 @@ class AccessMangApi{ showServerMessage: true, expectedResponseModel: (json) { List jsonData = json; - print('fetchDevices List: $json'); List passwordList = jsonData.map((jsonItem) { return DeviceModel.fromJson(jsonItem); }).toList(); @@ -60,18 +57,6 @@ class AccessMangApi{ String? invalidTime, List? devicesUuid}) async { try { - - print('postOfflineOneTime List: ${ - jsonEncode({ - "email": email, - "passwordName": passwordName, - "password": password, - "devicesUuid": devicesUuid, - "effectiveTime":effectiveTime , - "invalidTime": invalidTime - }) - }'); - final response = await HTTPService().post( path: ApiEndpoints.sendOnlineOneTime, body: jsonEncode({ @@ -84,7 +69,6 @@ class AccessMangApi{ }), showServerMessage: true, expectedResponseModel: (json) { - print('postOfflineOneTime List: $json'); if(json['statusCode'].toString()=='201'){ return true; }else{ @@ -93,9 +77,8 @@ class AccessMangApi{ }, ); return response; - } on DioException catch (e) { + } on DioException catch (e) { debugPrint('Error: ${e.message}'); - debugPrint('Error fetching ${e.response!.statusMessage}'); return false; } @@ -121,15 +104,11 @@ class AccessMangApi{ if (scheduleList != null) { body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList(); } - print('createPassword =${jsonEncode(body)}'); - final response = await HTTPService().post( path: ApiEndpoints.sendOnlineMultipleTime, body: jsonEncode(body), showServerMessage: true, expectedResponseModel: (json) { - print('createPassword =${json}'); - if(json['data']['successOperations'][0]['success'].toString()=='true'){ return true; }else{ @@ -138,7 +117,7 @@ class AccessMangApi{ }, ); return response; - } on DioException catch (e){ + } on DioException catch (e){ debugPrint('Error fetching ${e.type.name}'); debugPrint('Error fetching ${e.response!.statusMessage}'); return false; @@ -149,15 +128,6 @@ class AccessMangApi{ Future postOffLineOneTime({String? email,String? passwordName,List? devicesUuid}) async { try { - - print('postOfflineOneTime List: ${ - { - "email": email, - "passwordName": passwordName, - "devicesUuid": devicesUuid - } - }'); - final response = await HTTPService().post( path: ApiEndpoints.sendOffLineOneTime, body: jsonEncode({ @@ -166,10 +136,14 @@ class AccessMangApi{ "devicesUuid": devicesUuid }), showServerMessage: true, - expectedResponseModel: (json) { - List jsonData = json; - print('postOfflineOneTime List: $json'); - }, + expectedResponseModel: (json) { + if (json['data']['successOperations'][0]['success'].toString() == + 'true') { + return true; + } else { + return false; + } + } ); return response; } catch (e) { @@ -187,15 +161,6 @@ class AccessMangApi{ }) async { try { - - print('postOfflineOneTime List: ${ - { - "email": email, - "passwordName": passwordName, - "devicesUuid": devicesUuid - } - }'); - final response = await HTTPService().post( path: ApiEndpoints.sendOffLineOneTime, body: jsonEncode({ @@ -206,10 +171,14 @@ class AccessMangApi{ "invalidTime": invalidTime }), showServerMessage: true, - expectedResponseModel: (json) { - List jsonData = json; - print('postOfflineOneTime List: $json'); - }, + expectedResponseModel: (json) { + if (json['data']['successOperations'][0]['success'].toString() == + 'true') { + return true; + } else { + return false; + } + } ); return response; } catch (e) { diff --git a/lib/services/auth_api.dart b/lib/services/auth_api.dart index 55584055..3bb8f7e7 100644 --- a/lib/services/auth_api.dart +++ b/lib/services/auth_api.dart @@ -1,4 +1,3 @@ -import 'dart:convert'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; @@ -8,9 +7,7 @@ import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/utils/constants/api_const.dart'; class AuthenticationAPI { - static Future loginWithEmail({required var model}) async { - print('model=$model'); final response = await HTTPService().post( path: ApiEndpoints.login, body: model.toJson(), @@ -46,19 +43,15 @@ class AuthenticationAPI { }, showServerMessage: true, expectedResponseModel: (json) { - print('object==$json'); return 30; } - ); return 30; } on DioException catch (e) { if (e.response != null) { if (e.response!.statusCode == 400) { - // Handle 400 Bad Request final errorData = e.response!.data; String errorMessage = errorData['message']; - debugPrint('Unexpected Error: $errorMessage'); if(errorMessage=='User not found'){ return 1; }else{ @@ -87,8 +80,6 @@ class AuthenticationAPI { body: {"email": email, "type": "PASSWORD", "otpCode": otpCode}, showServerMessage: true, expectedResponseModel: (json) { - print('json=$json'); - if (json['message'] == 'Otp Verified Successfully') { return true; } else { @@ -99,12 +90,9 @@ class AuthenticationAPI { }on DioException catch (e){ if (e.response != null) { if (e.response!.statusCode == 400) { - // Handle 400 Bad Request final errorData = e.response!.data; String errorMessage = errorData['message']; - debugPrint('Unexpected Error: $errorMessage'); return errorMessage; - } } else { debugPrint('Error: ${e.message}'); diff --git a/lib/web_layout/web_scaffold.dart b/lib/web_layout/web_scaffold.dart index 567710bd..31b8d958 100644 --- a/lib/web_layout/web_scaffold.dart +++ b/lib/web_layout/web_scaffold.dart @@ -3,14 +3,12 @@ import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/web_layout/web_app_bar.dart'; import 'menu_sidebar.dart'; - class WebScaffold extends StatelessWidget { final bool enableMenuSideba; final Widget? appBarTitle; final List? appBarBody; final Widget? scaffoldBody; const WebScaffold({super.key,this.appBarTitle,this.appBarBody,this.scaffoldBody,this.enableMenuSideba=true}); - @override Widget build(BuildContext context) { return Scaffold( From 820da1ecfb9033ef6558f563992226de54b58c4d Mon Sep 17 00:00:00 2001 From: mohammad Date: Fri, 23 Aug 2024 22:25:09 +0300 Subject: [PATCH 06/10] Success dialog and Failed dialog changes with VisitorPasswordDialog --- .../bloc/visitor_password_bloc.dart | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index ee40de87..dc4b8a5f 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -246,12 +246,18 @@ class VisitorPasswordBloc passwordName: event.passwordName); if (res == true) { emit(SuccessState()); - emit(TableLoaded(data)); + }else { + throw Exception('Failed to create password'); } + emit(TableLoaded(data)); } catch (e) { emit(FailedState(e.toString())); - } + Navigator.pop(event.context!); + stateDialog( + context: event.context!, + message: e.toString(), + title: 'Something Wrong'); } } //offline password @@ -266,10 +272,18 @@ class VisitorPasswordBloc passwordName: event.passwordName); if (res == true) { emit(SuccessState()); - emit(TableLoaded(data)); + }else { + throw Exception('Failed to create password'); } + emit(TableLoaded(data)); + } catch (e) { emit(FailedState(e.toString())); + Navigator.pop(event.context!); + stateDialog( + context: event.context!, + message: e.toString(), + title: 'Something Wrong'); } } @@ -288,11 +302,18 @@ class VisitorPasswordBloc ); if (res == true) { emit(SuccessState()); - emit(TableLoaded(data)); + }else { + throw Exception('Failed to create password'); } + emit(TableLoaded(data)); + } catch (e) { emit(FailedState(e.toString())); - } + Navigator.pop(event.context!); + stateDialog( + context: event.context!, + message: e.toString(), + title: 'Something Wrong'); } } void selectDevice( From 13ae978908f1cdecdccbc63c4f57c3695edf3be7 Mon Sep 17 00:00:00 2001 From: mohammad Date: Sat, 24 Aug 2024 09:26:37 +0300 Subject: [PATCH 07/10] check if row in the table checked --- lib/pages/common/custom_table.dart | 8 +++++++- .../bloc/visitor_password_event.dart | 5 ++++- .../visitor_password/view/add_device_dialog.dart | 15 +++++++++++++-- .../view/visitor_password_dialog.dart | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index a691b673..76e3b663 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -13,6 +13,7 @@ class DynamicTable extends StatefulWidget { final bool isEmpty; final void Function(bool?)? selectAll; final void Function(int, bool?)? onRowCheckboxChanged; + final List? initialSelectedIds; const DynamicTable({ super.key, @@ -25,6 +26,7 @@ class DynamicTable extends StatefulWidget { this.cellDecoration, this.selectAll, this.onRowCheckboxChanged, + this.initialSelectedIds, }); @override @@ -38,7 +40,11 @@ class _DynamicTableState extends State { @override void initState() { super.initState(); - _selected = List.filled(widget.data.length, false); + _selected = List.generate(widget.data.length, (index) { + return widget.initialSelectedIds != null && + widget.initialSelectedIds!.contains(widget.data[index][1]); + }); + _selectAll = _selected.every((element) => element == true); } void _toggleSelectAll(bool? value) { diff --git a/lib/pages/visitor_password/bloc/visitor_password_event.dart b/lib/pages/visitor_password/bloc/visitor_password_event.dart index 05ad73d1..b0151757 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_event.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_event.dart @@ -51,7 +51,10 @@ class ToggleDaySelectionEvent extends VisitorPasswordEvent { class ToggleRepeatEvent extends VisitorPasswordEvent {} class GeneratePasswordEvent extends VisitorPasswordEvent {} -class FetchDevice extends VisitorPasswordEvent {} +class FetchDevice extends VisitorPasswordEvent { + final List? list; + const FetchDevice({this.list}); +} //online password class OnlineOneTimePasswordEvent extends VisitorPasswordEvent { diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index eccdfd78..73098976 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -13,15 +13,25 @@ import 'package:syncrow_web/utils/constants/const.dart'; import 'package:syncrow_web/utils/style.dart'; class AddDeviceDialog extends StatelessWidget { - const AddDeviceDialog({super.key}); + final List? selectedDeviceIds; + const AddDeviceDialog({super.key,this.selectedDeviceIds }); @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; return BlocProvider( - create: (context) => VisitorPasswordBloc()..add(FetchDevice()), + create: (context) => VisitorPasswordBloc()..add(FetchDevice(list: selectedDeviceIds)), child: BlocBuilder( builder: (BuildContext context, VisitorPasswordState state) { final visitorBloc = BlocProvider.of(context); + if (state is TableLoaded) { + print('ooooooooooo${selectedDeviceIds}'); + for (var device in selectedDeviceIds!) { + if (selectedDeviceIds!.contains(device)) { + visitorBloc.add(SelectDeviceEvent(device)); + } + } + } + return AlertDialog( backgroundColor: Colors.white, title: Text('Add Accessible Device', @@ -143,6 +153,7 @@ class AddDeviceDialog extends StatelessWidget { flex: 3, child: state is TableLoaded ? DynamicTable( + initialSelectedIds:selectedDeviceIds , cellDecoration: containerDecoration, isEmpty:visitorBloc.data.isEmpty, selectAll: (p0) { diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index 0aa63638..8206d42c 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -318,7 +318,7 @@ class VisitorPasswordDialog extends StatelessWidget { context: context, barrierDismissible: false, builder: (BuildContext context) { - return const AddDeviceDialog(); + return AddDeviceDialog(selectedDeviceIds: visitorBloc.selectedDevices,); }, ).then((listDevice) { if(listDevice!=null){ From 9d21b32607235078c6072830b92d9b72a0f4b422 Mon Sep 17 00:00:00 2001 From: mohammad Date: Sat, 24 Aug 2024 09:28:29 +0300 Subject: [PATCH 08/10] check if row in the table checked --- lib/pages/visitor_password/bloc/visitor_password_bloc.dart | 3 ++- lib/pages/visitor_password/bloc/visitor_password_event.dart | 2 -- lib/pages/visitor_password/view/add_device_dialog.dart | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index dc4b8a5f..2a3e486f 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -257,7 +257,8 @@ class VisitorPasswordBloc stateDialog( context: event.context!, message: e.toString(), - title: 'Something Wrong'); } + title: 'Something Wrong'); + } } //offline password diff --git a/lib/pages/visitor_password/bloc/visitor_password_event.dart b/lib/pages/visitor_password/bloc/visitor_password_event.dart index b0151757..9526bf54 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_event.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_event.dart @@ -52,8 +52,6 @@ class ToggleRepeatEvent extends VisitorPasswordEvent {} class GeneratePasswordEvent extends VisitorPasswordEvent {} class FetchDevice extends VisitorPasswordEvent { - final List? list; - const FetchDevice({this.list}); } //online password diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index 73098976..e5e4853c 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -19,12 +19,11 @@ class AddDeviceDialog extends StatelessWidget { Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; return BlocProvider( - create: (context) => VisitorPasswordBloc()..add(FetchDevice(list: selectedDeviceIds)), + create: (context) => VisitorPasswordBloc()..add(FetchDevice()), child: BlocBuilder( builder: (BuildContext context, VisitorPasswordState state) { final visitorBloc = BlocProvider.of(context); if (state is TableLoaded) { - print('ooooooooooo${selectedDeviceIds}'); for (var device in selectedDeviceIds!) { if (selectedDeviceIds!.contains(device)) { visitorBloc.add(SelectDeviceEvent(device)); From 6d64408360d44a93683ad2622a410b038bb394fb Mon Sep 17 00:00:00 2001 From: mohammad Date: Sat, 24 Aug 2024 10:35:42 +0300 Subject: [PATCH 09/10] change some padding and when bake to AccessManagementPage get table --- .../view/access_management.dart | 9 ++- lib/pages/common/date_time_widget.dart | 71 +++++++++++-------- .../visitor_password/view/repeat_widget.dart | 35 ++++----- .../view/visitor_password_dialog.dart | 32 +++++---- 4 files changed, 83 insertions(+), 64 deletions(-) diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 6245dcda..e357216d 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -8,6 +8,7 @@ import 'package:syncrow_web/pages/common/date_time_widget.dart'; import 'package:syncrow_web/pages/common/default_button.dart'; import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/const.dart'; import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; @@ -126,7 +127,7 @@ class AccessManagementPage extends StatelessWidget { width: 15, ), DateTimeWebWidget( - isTime: false, + icon: Assets.calendarIcon, isRequired: false, title: 'Access Time', size: size, @@ -202,7 +203,11 @@ class AccessManagementPage extends StatelessWidget { builder: (BuildContext context) { return const VisitorPasswordDialog(); }, - ); + ).then((v){ + if(v!=null){ + accessBloc.add(FetchTableData()); + } + }); }, borderRadius: 8, child: const Text('+ Create Visitor Password ')), diff --git a/lib/pages/common/date_time_widget.dart b/lib/pages/common/date_time_widget.dart index 55d5b9a9..b2103ab2 100644 --- a/lib/pages/common/date_time_widget.dart +++ b/lib/pages/common/date_time_widget.dart @@ -12,17 +12,17 @@ class DateTimeWebWidget extends StatelessWidget { required this.title, required this.startTime, required this.endTime, - required this.isTime, required this.firstString, required this.secondString, + required this.icon, }); final Size size; final String title; final bool isRequired; - final bool isTime; final String firstString; final String secondString; + final String icon; final Function()? startTime; final Function()? endTime; @@ -49,34 +49,45 @@ class DateTimeWebWidget extends StatelessWidget { ), const SizedBox(height: 8,), Container( - width: size.width * 0.25, - padding: EdgeInsets.all(10), - decoration: containerDecoration, - child: Column( - children: [ - Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - InkWell( - onTap: startTime, - child: Text(firstString, style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),) - ), - const Icon(Icons.arrow_right_alt), - InkWell( - onTap:endTime, - child: Text(secondString, style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),)), - SvgPicture.asset( - isTime? - Assets.timeIcon: - Assets.calendarIcon, - ), - ], - ), - ], - )), + height:size.height * 0.055 , + padding: EdgeInsets.only(top: 10,bottom: 10,right: 30,left: 30), + decoration: containerDecoration, + child: FittedBox( + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + InkWell( + onTap: startTime, + child: FittedBox( + child: Text(firstString, + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),), + ) + ), + SizedBox(width: 10,), + const Icon(Icons.arrow_right_alt), + SizedBox(width: 10,), + + InkWell( + onTap:endTime, + child: FittedBox( + child: Text(secondString, + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400), + ), + )), + SizedBox(width: 10,), + + SvgPicture.asset( + icon, + ), + ], + ), + ], + )), + ), ], ); } diff --git a/lib/pages/visitor_password/view/repeat_widget.dart b/lib/pages/visitor_password/view/repeat_widget.dart index 31bedb05..ae37b1e3 100644 --- a/lib/pages/visitor_password/view/repeat_widget.dart +++ b/lib/pages/visitor_password/view/repeat_widget.dart @@ -5,6 +5,7 @@ import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.da import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; class RepeatWidget extends StatelessWidget { const RepeatWidget({ @@ -21,19 +22,20 @@ class RepeatWidget extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, children: [ - - Container( - height: size.height * 0.05, // Adjust height as needed - child: Wrap( + // Wrap the Row in a SingleChildScrollView to handle overflow + SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Row( children: visitorBloc.days.map((day) { return Container( - width: size.width * 0.05, + width: 70, // Adjust width as needed + margin: EdgeInsets.all(5), child: CheckboxListTile( contentPadding: EdgeInsets.zero, title: Text( day['day']!, style: TextStyle( - fontSize: 12, + fontSize: 10, color: visitorBloc.selectedDays.contains(day['key']) ? Colors.black : ColorsManager.blackColor, @@ -53,33 +55,32 @@ class RepeatWidget extends StatelessWidget { Padding( padding: const EdgeInsets.all(8.0), child: DateTimeWebWidget( - isTime: true, + icon: Assets.timeIcon, isRequired: false, title: '', size: size, endTime: () { - visitorBloc.add(SelectTimeEvent( - context: context, - isEffective: false)); - Future.delayed(const Duration(milliseconds: 500), () { + visitorBloc.add(SelectTimeEvent( + context: context, + isEffective: false)); + Future.delayed(const Duration(milliseconds: 500), () { visitorBloc.add(ChangeTimeEvent(val: visitorBloc.endTime, isStartEndTime: true)); }); }, startTime: () { - Future.delayed(const Duration(milliseconds: 500), () { + Future.delayed(const Duration(milliseconds: 500), () { visitorBloc.add(ChangeTimeEvent(val: visitorBloc.endTime, isStartEndTime: true)); }); visitorBloc.add(SelectTimeEvent(context: context, isEffective: true)); }, - firstString:visitorBloc.effectiveTime , - secondString: visitorBloc.expirationTime , + firstString: visitorBloc.effectiveTime, + secondString: visitorBloc.expirationTime, ), ), - const SizedBox(height: 20), - ], ); - }); + } + ); } } diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index 8206d42c..ff3d5a04 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -100,20 +100,20 @@ class VisitorPasswordDialog extends StatelessWidget { children: [ Row( children: [ - Text( - '* ', + Text('* ', style: Theme.of(context).textTheme .bodyMedium!.copyWith(color: Colors.red), ), Text('Access Type', style:text ), ], + ), Row( children: [ - SizedBox( - width: size.width * 0.15, + Flexible( child: RadioListTile( + contentPadding: EdgeInsets.zero, title: Text('Online Password', style: text, ), @@ -129,9 +129,10 @@ class VisitorPasswordDialog extends StatelessWidget { }, ), ), - SizedBox( - width: size.width * 0.15, + Flexible( child: RadioListTile( + contentPadding: EdgeInsets.zero, + title: Text('Offline Password', style:text ), value: 'Offline Password', @@ -145,9 +146,10 @@ class VisitorPasswordDialog extends StatelessWidget { }, ), ), - SizedBox( - width: size.width * 0.15, + Flexible( child: RadioListTile( + contentPadding: EdgeInsets.zero, + title: Text('Dynamic Password', style: text,), value: 'Dynamic Password', @@ -191,9 +193,9 @@ class VisitorPasswordDialog extends StatelessWidget { ), Row( children: [ - SizedBox( - width: 200, + Flexible( child: RadioListTile( + contentPadding: EdgeInsets.zero, title: Text('One-Time', style:text ,), value: 'One-Time', @@ -209,9 +211,9 @@ class VisitorPasswordDialog extends StatelessWidget { }, ), ), - SizedBox( - width: 200, + Flexible( child: RadioListTile( + contentPadding: EdgeInsets.zero, title: Text('Periodic', style: text), value: 'Periodic', @@ -241,7 +243,6 @@ class VisitorPasswordDialog extends StatelessWidget { visitorBloc.accessTypeSelected != 'Offline Password') && (visitorBloc.usageFrequencySelected != '')) DateTimeWebWidget( - isTime: false, isRequired: true, title: 'Access Period', size: size, @@ -259,6 +260,7 @@ class VisitorPasswordDialog extends StatelessWidget { }, firstString: visitorBloc.startTimeAccess.toString(), secondString: visitorBloc.endTimeAccess.toString(), + icon: Assets.calendarIcon ), const SizedBox( height: 20, @@ -311,7 +313,7 @@ class VisitorPasswordDialog extends StatelessWidget { isRepeat ? const RepeatWidget() : const SizedBox(), Container( decoration: containerDecoration, - width: size.width * 0.08, + width: size.width / 9, child: DefaultButton( onPressed: () { showDialog( @@ -347,7 +349,7 @@ class VisitorPasswordDialog extends StatelessWidget { child: DefaultButton( borderRadius: 8, onPressed: () { - Navigator.of(context).pop(); // Close the dialog + Navigator.of(context).pop(true); }, backgroundColor: Colors.white, child: Text( From 4e1c2ab5ceae018d58c88ba4e790701a06a66a55 Mon Sep 17 00:00:00 2001 From: mohammad Date: Sat, 24 Aug 2024 10:49:08 +0300 Subject: [PATCH 10/10] change some padding and when bake to AccessManagementPage get table --- lib/pages/access_management/bloc/access_bloc.dart | 4 ++++ .../access_management/view/access_management.dart | 1 - lib/pages/common/date_time_widget.dart | 10 +++++----- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index 4ed61291..47f865ef 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -72,6 +72,8 @@ class AccessBloc extends Bloc { Future selectTime(SelectTime event, Emitter emit) async { + emit(AccessLoaded()); + final DateTime? picked = await showDatePicker( context: event.context, initialDate: DateTime.now(), @@ -182,6 +184,8 @@ class AccessBloc extends Bloc { endTime = 'End Time'; passwordName.clear(); selectedIndex=0; + effectiveTimeTimeStamp=null; + expirationTimeTimeStamp=null; add(FetchTableData()); } diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index e357216d..d17e774b 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -36,7 +36,6 @@ class AccessManagementPage extends StatelessWidget { ], scaffoldBody: BlocProvider(create: (BuildContext context) => AccessBloc()..add(FetchTableData()), child: BlocConsumer(listener: (context, state) { - }, builder: (context, state) { final accessBloc = BlocProvider.of(context); final filteredData = accessBloc.filteredData; diff --git a/lib/pages/common/date_time_widget.dart b/lib/pages/common/date_time_widget.dart index b2103ab2..d8fbfe51 100644 --- a/lib/pages/common/date_time_widget.dart +++ b/lib/pages/common/date_time_widget.dart @@ -50,13 +50,13 @@ class DateTimeWebWidget extends StatelessWidget { const SizedBox(height: 8,), Container( height:size.height * 0.055 , - padding: EdgeInsets.only(top: 10,bottom: 10,right: 30,left: 30), + padding: EdgeInsets.only(top: 10,bottom: 10,right: 30,left: 10), decoration: containerDecoration, child: FittedBox( child: Column( children: [ Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ InkWell( onTap: startTime, @@ -66,9 +66,9 @@ class DateTimeWebWidget extends StatelessWidget { color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400),), ) ), - SizedBox(width: 10,), + SizedBox(width: 30,), const Icon(Icons.arrow_right_alt), - SizedBox(width: 10,), + SizedBox(width: 30,), InkWell( onTap:endTime, @@ -78,7 +78,7 @@ class DateTimeWebWidget extends StatelessWidget { color: ColorsManager.grayColor,fontSize: 12,fontWeight: FontWeight.w400), ), )), - SizedBox(width: 10,), + SizedBox(width: 30,), SvgPicture.asset( icon,