From 2e3f130071df5ba6e18a3feef83225a65c125b16 Mon Sep 17 00:00:00 2001 From: mohammad Date: Mon, 26 Aug 2024 19:44:55 +0300 Subject: [PATCH 1/3] fix bugs --- lib/main.dart | 3 +- .../access_management/bloc/access_bloc.dart | 182 ++++++++-- .../view/access_management.dart | 29 +- lib/pages/common/custom_dialog.dart | 3 + lib/pages/common/custom_web_textfield.dart | 2 +- lib/pages/common/date_time_widget.dart | 3 +- lib/pages/home/view/home_card.dart | 19 +- .../bloc/visitor_password_bloc.dart | 119 ++++--- .../model/failed_operation.dart | 124 +++++++ .../view/visitor_password_dialog.dart | 335 ++++++++++++++---- lib/services/access_mang_api.dart | 81 ++--- lib/services/auth_api.dart | 3 +- lib/utils/color_manager.dart | 5 + pubspec.lock | 24 +- 14 files changed, 674 insertions(+), 258 deletions(-) create mode 100644 lib/pages/visitor_password/model/failed_operation.dart diff --git a/lib/main.dart b/lib/main.dart index 01911d05..9c68747d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,6 +6,7 @@ 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/bloc/visitor_password_bloc.dart'; +import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart'; import 'package:syncrow_web/services/locator.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -56,10 +57,10 @@ class MyApp extends StatelessWidget { fontWeight: FontWeight.bold, ), ), - 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/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index 47f865ef..febdb9d3 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -81,34 +81,12 @@ class AccessBloc extends Bloc { lastDate: DateTime(2101), ); if (picked != null) { - final TimeOfDay? timePicked = await showTimePicker( - context: event.context, - initialTime: TimeOfDay.now(), - builder: (context, child) { - return Theme( - data: ThemeData.light().copyWith( - colorScheme: const ColorScheme.light( - primary: ColorsManager.primaryColor, - onSurface: Colors.black, - ), - buttonTheme: const ButtonThemeData( - colorScheme: ColorScheme.light( - primary: Colors.green, - ), - ), - ), - child: child!, - ); - }, - ); - if (timePicked != null) { final selectedDateTime = DateTime( picked.year, picked.month, picked.day, - timePicked.hour, - timePicked.minute, + ); final selectedTimestamp = DateTime( selectedDateTime.year, @@ -132,17 +110,23 @@ class AccessBloc extends Bloc { expirationTimeTimeStamp = selectedTimestamp; } } - } + } emit(ChangeTimeState()); } - - Future _filterData(FilterDataEvent event, Emitter emit) async { emit(AccessLoaded()); try { filteredData = data.where((item) { bool matchesCriteria = true; + + // Convert timestamp to DateTime and extract date component + DateTime effectiveDate = DateTime.fromMillisecondsSinceEpoch(int.parse(item.effectiveTime.toString()) * 1000).toUtc().toLocal(); + DateTime invalidDate = DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000).toUtc().toLocal(); + DateTime effectiveDateOnly = DateTime(effectiveDate.year, effectiveDate.month, effectiveDate.day); + DateTime invalidDateOnly = DateTime(invalidDate.year, invalidDate.month, invalidDate.day); + + // Filter by password name if (event.passwordName != null && event.passwordName!.isNotEmpty) { final bool matchesName = item.passwordName != null && item.passwordName.contains(event.passwordName); @@ -150,19 +134,37 @@ class AccessBloc extends Bloc { matchesCriteria = false; } } - if (event.startTime != null && event.endTime != null) { - final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); - final int? invalidTime = int.tryParse(item.invalidTime.toString()); - if (effectiveTime == null || invalidTime == null) { + + // Filter by start date only + if (event.startTime != null && event.endTime == null) { + DateTime startDateOnly = DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); + startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day); + if (effectiveDateOnly.isBefore(startDateOnly)) { matchesCriteria = false; - } else { - final bool matchesStartTime = effectiveTime >= event.startTime!; - final bool matchesEndTime = invalidTime <= event.endTime!; - if (!matchesStartTime || !matchesEndTime) { - matchesCriteria = false; - } } } + + // Filter by end date only + if (event.endTime != null && event.startTime == null) { + DateTime endDateOnly = DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal(); + endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day); + if (invalidDateOnly.isAfter(endDateOnly)) { + matchesCriteria = false; + } + } + + // Filter by both start date and end date + if (event.startTime != null && event.endTime != null) { + DateTime startDateOnly = DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal(); + DateTime endDateOnly = DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal(); + startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day); + endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day); + if (effectiveDateOnly.isBefore(startDateOnly) || invalidDateOnly.isAfter(endDateOnly)) { + matchesCriteria = false; + } + } + + // Filter by selected tab index if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To Be Effective') { matchesCriteria = false; } else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') { @@ -170,14 +172,122 @@ class AccessBloc extends Bloc { } else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') { matchesCriteria = false; } + return matchesCriteria; }).toList(); + emit(TableLoaded(filteredData)); } catch (e) { emit(FailedState(e.toString())); } } + + // Future _filterData(FilterDataEvent event, Emitter emit) async { + // emit(AccessLoaded()); + // try { + // filteredData = data.where((item) { + // bool matchesCriteria = true; + // + // // Filter by password name + // if (event.passwordName != null && event.passwordName!.isNotEmpty) { + // final bool matchesName = item.passwordName != null && + // item.passwordName.contains(event.passwordName); + // if (!matchesName) { + // matchesCriteria = false; + // } + // } + // + // // Filter by start time only + // if (event.startTime != null && event.endTime == null) { + // final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); + // if (effectiveTime == null || effectiveTime < event.startTime!) { + // matchesCriteria = false; + // } + // } + // + // // Filter by end time only + // if (event.endTime != null && event.startTime == null) { + // final int? invalidTime = int.tryParse(item.invalidTime.toString()); + // if (invalidTime == null || invalidTime > event.endTime!) { + // matchesCriteria = false; + // } + // } + // + // // Filter by both start time and end time + // if (event.startTime != null && event.endTime != null) { + // final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); + // final int? invalidTime = int.tryParse(item.invalidTime.toString()); + // if (effectiveTime == null || invalidTime == null) { + // matchesCriteria = false; + // } else { + // final bool matchesStartTime = effectiveTime >= event.startTime!; + // final bool matchesEndTime = invalidTime <= event.endTime!; + // if (!matchesStartTime || !matchesEndTime) { + // matchesCriteria = false; + // } + // } + // } + // + // // Filter by selected tab index + // 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(); + // + // emit(TableLoaded(filteredData)); + // } catch (e) { + // emit(FailedState(e.toString())); + // } + // } + + + // Future _filterData(FilterDataEvent event, Emitter emit) async { + // emit(AccessLoaded()); + // try { + // filteredData = data.where((item) { + // bool matchesCriteria = true; + // if (event.passwordName != null && event.passwordName!.isNotEmpty) { + // final bool matchesName = item.passwordName != null && + // item.passwordName.contains(event.passwordName); + // if (!matchesName) { + // matchesCriteria = false; + // } + // } + // if (event.startTime != null || event.endTime != null) { + // final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); + // final int? invalidTime = int.tryParse(item.invalidTime.toString()); + // if (effectiveTime == null || invalidTime == null) { + // matchesCriteria = false; + // } else { + // final bool matchesStartTime = effectiveTime >= event.startTime!; + // final bool matchesEndTime = invalidTime <= event.endTime!; + // if (!matchesStartTime || !matchesEndTime) { + // matchesCriteria = false; + // } + // } + // } + // 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(); + // emit(TableLoaded(filteredData)); + // } catch (e) { + // emit(FailedState(e.toString())); + // } + // } + resetSearch(ResetSearch event, Emitter emit) async{ emit(AccessLoaded()); startTime = 'Start Time'; diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index d17e774b..80efcd3c 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -4,6 +4,7 @@ import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_event.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_state.dart'; import 'package:syncrow_web/pages/common/custom_table.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/visitor_password/view/visitor_password_dialog.dart'; @@ -101,27 +102,15 @@ class AccessManagementPage extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.end, textBaseline: TextBaseline.ideographic, children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text('Name', - style: Theme.of(context).textTheme.bodySmall!.copyWith( - color: Colors.black,fontSize: 13),), - const SizedBox(height: 5,), - Container( - height:43, - width: size.width * 0.15, - decoration: containerDecoration, - child: TextFormField( - controller: accessBloc.passwordName, - style: const TextStyle(color: Colors.black), - decoration: textBoxDecoration()! - .copyWith(hintText: 'Please enter'), - ) - ), - ], + Container( + width: size.width * 0.15, + child: CustomWebTextField( + controller: accessBloc.passwordName, + isRequired: true, + textFieldName: 'Name', + description: '', ), + ), const SizedBox( width: 15, ), diff --git a/lib/pages/common/custom_dialog.dart b/lib/pages/common/custom_dialog.dart index 3b667811..7b3e7192 100644 --- a/lib/pages/common/custom_dialog.dart +++ b/lib/pages/common/custom_dialog.dart @@ -7,6 +7,7 @@ Future showCustomDialog({ required String message, String? title, String? iconPath, + Widget? widget, double? dialogHeight, double? iconHeight, double? iconWidth, @@ -53,6 +54,8 @@ Future showCustomDialog({ textAlign: TextAlign.center, ), ), + if(widget!=null) + Expanded(child:widget) ], ), ), diff --git a/lib/pages/common/custom_web_textfield.dart b/lib/pages/common/custom_web_textfield.dart index 363a1994..e58f51b4 100644 --- a/lib/pages/common/custom_web_textfield.dart +++ b/lib/pages/common/custom_web_textfield.dart @@ -73,7 +73,7 @@ class CustomWebTextField extends StatelessWidget { decoration: textBoxDecoration()! .copyWith( errorStyle: const TextStyle(height: 0), // Hide the error text space - + hintStyle: TextStyle(color: ColorsManager.grayColor), hintText: 'Please enter'), ), ), diff --git a/lib/pages/common/date_time_widget.dart b/lib/pages/common/date_time_widget.dart index d8fbfe51..7945ce33 100644 --- a/lib/pages/common/date_time_widget.dart +++ b/lib/pages/common/date_time_widget.dart @@ -49,7 +49,7 @@ class DateTimeWebWidget extends StatelessWidget { ), const SizedBox(height: 8,), Container( - height:size.height * 0.055 , + height:50 , padding: EdgeInsets.only(top: 10,bottom: 10,right: 30,left: 10), decoration: containerDecoration, child: FittedBox( @@ -69,7 +69,6 @@ class DateTimeWebWidget extends StatelessWidget { SizedBox(width: 30,), const Icon(Icons.arrow_right_alt), SizedBox(width: 30,), - InkWell( onTap:endTime, child: FittedBox( diff --git a/lib/pages/home/view/home_card.dart b/lib/pages/home/view/home_card.dart index ce152c1c..747ecd59 100644 --- a/lib/pages/home/view/home_card.dart +++ b/lib/pages/home/view/home_card.dart @@ -18,16 +18,25 @@ class HomeCard extends StatelessWidget { }); @override Widget build(BuildContext context) { - bool evenNumbers = index % 2 == 0; + // bool evenNumbers = index % 2 == 0; return InkWell( onTap: active ? onTap : null, child: Container( padding: const EdgeInsets.only(left: 10,right: 10,bottom: 10), decoration: BoxDecoration( - color: evenNumbers && active? - ColorsManager.blueColor.withOpacity(0.8) : - (active ?ColorsManager.blueColor - : ColorsManager.blueColor.withOpacity(0.2)), + color: index==0&&active? + ColorsManager.blue1.withOpacity(0.9): + index==1&&active? + ColorsManager.blue2.withOpacity(0.9) : + index==2&&active? + ColorsManager.blue3: + index==4&&active==false? + ColorsManager.blue4.withOpacity(0.2): + index==7&&active==false? + ColorsManager.blue4.withOpacity(0.2): + ColorsManager.blueColor.withOpacity(0.2), + // (active ?ColorsManager.blueColor + // : ColorsManager.blueColor.withOpacity(0.2)), borderRadius: BorderRadius.circular(30), ), child: Column( diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index 2a3e486f..8ee44298 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -1,4 +1,5 @@ import 'dart:math'; +import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:intl/intl.dart'; @@ -7,6 +8,7 @@ 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'; +import 'package:syncrow_web/pages/visitor_password/model/failed_operation.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'; @@ -62,7 +64,7 @@ class VisitorPasswordBloc String startTimeAccess = 'Start Time'; String endTimeAccess = 'End Time'; - + PasswordStatus? passwordStatus; selectAccessType( SelectPasswordType event, Emitter emit) { accessTypeSelected = event.type; @@ -197,26 +199,23 @@ class VisitorPasswordBloc try { emit(LoadingInitialState()); generate7DigitNumber(); - bool res = await AccessMangApi().postOnlineOneTime( + var res = await AccessMangApi().postOnlineOneTime( email: event.email, password: passwordController, devicesUuid: selectedDevices, passwordName: event.passwordName, effectiveTime: effectiveTimeTimeStamp.toString(), invalidTime: expirationTimeTimeStamp.toString()); - if (res == true) { + if(res['statusCode']==201){ + passwordStatus= PasswordStatus.fromJson(res['data']); 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'); + } on DioException catch (e){ + final errorData = e.response!.data; + String errorMessage = errorData['message']; + print('errorMessage==$errorData'); + emit(FailedState(errorMessage.toString())); } } @@ -228,13 +227,12 @@ class VisitorPasswordBloc emit(LoadingInitialState()); await generate7DigitNumber(); - bool res = await AccessMangApi().postOnlineMultipleTime( + var res = await AccessMangApi().postOnlineMultipleTime( scheduleList: [ if (repeat) Schedule( effectiveTime: getTimeFromDateTimeString(expirationTime), - invalidTime: - getTimeFromDateTimeString(effectiveTime).toString(), + invalidTime: getTimeFromDateTimeString(effectiveTime).toString(), workingDay: selectedDays, ), ], @@ -244,47 +242,42 @@ class VisitorPasswordBloc email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName); - if (res == true) { + if(res['statusCode']==201){ + passwordStatus= PasswordStatus.fromJson(res['data']); 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'); + } on DioException catch (e){ + final errorData = e.response!.data; + String errorMessage = errorData['message']; + print('errorMessage==$errorData'); + emit(FailedState(errorMessage.toString())); } } //offline password - Future postOfflineOneTimePassword(OfflineOneTimePasswordEvent event, + Future postOfflineOneTimePassword( + OfflineOneTimePasswordEvent event, Emitter emit) async { try { emit(LoadingInitialState()); await generate7DigitNumber(); - bool res = await AccessMangApi().postOffLineOneTime( + var res = await AccessMangApi().postOffLineOneTime( email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName); - if (res == true) { + if(res['statusCode']==201){ + passwordStatus= PasswordStatus.fromJson(res['data']); 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'); + } on DioException catch (e){ + final errorData = e.response!.data; + String errorMessage = errorData['message']; + print('errorMessage==$errorData'); + emit(FailedState(errorMessage.toString())); } } @@ -294,27 +287,24 @@ class VisitorPasswordBloc try { emit(LoadingInitialState()); await generate7DigitNumber(); - bool res = await AccessMangApi().postOffLineMultipleTime( + var res = await AccessMangApi().postOffLineMultipleTime( email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName, invalidTime: expirationTimeTimeStamp.toString(), effectiveTime: effectiveTimeTimeStamp.toString(), ); - if (res == true) { + if(res['statusCode']==201){ + passwordStatus= PasswordStatus.fromJson(res['data']); 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'); } + } on DioException catch (e){ + final errorData = e.response!.data; + String errorMessage = errorData['message']; + print('errorMessage==$errorData'); + emit(FailedState(errorMessage.toString())); + } } void selectDevice( @@ -476,13 +466,15 @@ class VisitorPasswordBloc String? message, String? title, dynamic actions, + Widget? widgeta, }) { return showCustomDialog( context: context!, message: message!, iconPath: Assets.deviceNoteIcon, title: title, - dialogHeight: 150, + widget: widgeta, + dialogHeight: MediaQuery.of(context).size.height*0.3, actions: actions ?? [ TextButton( @@ -494,4 +486,31 @@ class VisitorPasswordBloc ], ); } + + // + // Future stateAndDeviseDialog({ + // 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/model/failed_operation.dart b/lib/pages/visitor_password/model/failed_operation.dart new file mode 100644 index 00000000..223f9ac5 --- /dev/null +++ b/lib/pages/visitor_password/model/failed_operation.dart @@ -0,0 +1,124 @@ +class FailedOperation { + final bool success; + final dynamic deviceUuid; + final dynamic error; + + FailedOperation({ + required this.success, + required this.deviceUuid, + required this.error, + }); + + factory FailedOperation.fromJson(Map json) { + return FailedOperation( + success: json['success'], + deviceUuid: json['deviceUuid'], + error: json['error'], + ); + } + + Map toJson() { + return { + 'success': success, + 'deviceUuid': deviceUuid, + 'error': error, + }; + } +} + + + +class SuccessOperation { + final bool success; + // final Result result; + final String deviceUuid; + + SuccessOperation({ + required this.success, + // required this.result, + required this.deviceUuid, + }); + + factory SuccessOperation.fromJson(Map json) { + return SuccessOperation( + success: json['success'], + // result: Result.fromJson(json['result']), + deviceUuid: json['deviceUuid'], + ); + } + + Map toJson() { + return { + 'success': success, + // 'result': result.toJson(), + 'deviceUuid': deviceUuid, + }; + } +} + +// class Result { +// final dynamic effectiveTime; +// final dynamic invalidTime; +// final dynamic offlineTempPassword; +// final dynamic offlineTempPasswordId; +// final dynamic offlineTempPasswordName; +// +// Result({ +// required this.effectiveTime, +// required this.invalidTime, +// required this.offlineTempPassword, +// required this.offlineTempPasswordId, +// required this.offlineTempPasswordName, +// }); +// +// factory Result.fromJson(Map json) { +// return Result( +// effectiveTime: json['effective_time'], +// invalidTime: json['invalid_time'], +// offlineTempPassword: json['offline_temp_password'].toString(), +// offlineTempPasswordId: json['offline_temp_password_id'], +// offlineTempPasswordName: json['offline_temp_password_name'], +// ); +// } +// +// Map toJson() { +// return { +// 'effective_time': effectiveTime, +// 'invalid_time': invalidTime, +// 'offline_temp_password': offlineTempPassword, +// 'offline_temp_password_id': offlineTempPasswordId, +// 'offline_temp_password_name': offlineTempPasswordName, +// }; +// } +// } + + + +class PasswordStatus { + final List successOperations; + final List failedOperations; + + PasswordStatus({ + required this.successOperations, + required this.failedOperations, + }); + + factory PasswordStatus.fromJson(Map json) { + return PasswordStatus( + successOperations: (json['successOperations'] as List) + .map((i) => SuccessOperation.fromJson(i)) + .toList(), + failedOperations: (json['failedOperations'] as List) + .map((i) => FailedOperation.fromJson(i)) + .toList(), + ); + } + + Map toJson() { + return { + 'successOperations': successOperations.map((e) => e.toJson()).toList(), + 'failedOperations': failedOperations.map((e) => e.toJson()).toList(), + }; + } +} + diff --git a/lib/pages/visitor_password/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index ff3d5a04..e3a9a291 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -32,6 +32,56 @@ class VisitorPasswordDialog extends StatelessWidget { context: context, message: 'Password Created Successfully', title: 'Send Success', + widgeta:Column( + children: [ + if(visitorBloc.passwordStatus!.failedOperations.isNotEmpty) + Column( + children: [ + const Text('Failed Devises'), + SizedBox( + width: 200, + height: 50, + child: ListView.builder( + scrollDirection: Axis.horizontal, + + shrinkWrap: true, + itemCount:visitorBloc.passwordStatus!.failedOperations.length , + itemBuilder: (context, index) { + return Container( + margin: EdgeInsets.all(5), + + decoration: containerDecoration, + height: 45, + child: Center(child: Text(visitorBloc.passwordStatus!.failedOperations[index].deviceUuid)), + ); + },), + ), + ], + ), + if(visitorBloc.passwordStatus!.successOperations.isNotEmpty) + Column( + children: [ + const Text('Success Devises'), + SizedBox( + width: 200, + height: 50, + child: ListView.builder( + scrollDirection: Axis.horizontal, + shrinkWrap: true, + itemCount:visitorBloc.passwordStatus!.successOperations.length , + itemBuilder: (context, index) { + return Container( + margin: EdgeInsets.all(5), + decoration: containerDecoration, + height: 45, + child: Center(child: Text(visitorBloc.passwordStatus!.successOperations[index].deviceUuid)), + ); + },), + ), + ], + ), + ], + ) ); } else if (state is FailedState) { visitorBloc.stateDialog( @@ -110,68 +160,92 @@ class VisitorPasswordDialog extends StatelessWidget { ), Row( - children: [ - Flexible( - child: RadioListTile( - contentPadding: EdgeInsets.zero, - 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)); - } - }, - ), - ), - Flexible( - child: RadioListTile( - contentPadding: EdgeInsets.zero, - - 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)); - } - }, - ), - ), - Flexible( - child: RadioListTile( - contentPadding: EdgeInsets.zero, - - 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 = ''; - } - }, - ), - ), + children: [ + Expanded( + flex: 2, + child: Row( + children: [ + SizedBox( + width: size.width*0.12, + child: RadioListTile( + contentPadding: EdgeInsets.zero, + 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.12, + child: RadioListTile( + contentPadding: EdgeInsets.zero, + 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.12, + child: RadioListTile( + contentPadding: EdgeInsets.zero, + 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 = ''; + } + }, + ), + ), + ], + )), + const Spacer(flex: 2,), ], ), + if(visitorBloc.accessTypeSelected == 'Online Password') 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), + ), + if(visitorBloc.accessTypeSelected == 'Offline Password') + Text( + 'Unaffected by the online status of the device, you can select online or offline device, and the system randomly generates a digital password', style: Theme.of(context).textTheme.bodySmall!.copyWith( fontWeight: FontWeight.w400, color: ColorsManager.grayColor,fontSize: 9),), + + if(visitorBloc.accessTypeSelected == 'Dynamic Password') + Text( + 'Quick and short-acting password, only valid within 5 minutes after creation, 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, ) @@ -179,7 +253,7 @@ class VisitorPasswordDialog extends StatelessWidget { ), visitorBloc.accessTypeSelected == 'Dynamic Password' ? const SizedBox() - : Column( + : Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( @@ -193,7 +267,8 @@ class VisitorPasswordDialog extends StatelessWidget { ), Row( children: [ - Flexible( + SizedBox( + width: size.width*0.12, child: RadioListTile( contentPadding: EdgeInsets.zero, title: Text('One-Time', @@ -205,13 +280,13 @@ class VisitorPasswordDialog extends StatelessWidget { : visitorBloc.usageFrequencySelected, onChanged: (String? value) { if (value != null) { - context.read() - .add(SelectUsageFrequency(value)); + context.read().add(SelectUsageFrequency(value)); } }, ), ), - Flexible( + SizedBox( + width: size.width*0.12, child: RadioListTile( contentPadding: EdgeInsets.zero, title: Text('Periodic', @@ -230,10 +305,35 @@ class VisitorPasswordDialog extends StatelessWidget { ), ], ), + + //One-Time + if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Online Password') Text('Within the validity period, each device can be unlocked only once.', style: Theme.of(context).textTheme.bodySmall!.copyWith( color: ColorsManager.grayColor,fontSize: 9), - ) + ), + if (visitorBloc.usageFrequencySelected == 'One-Time' && + visitorBloc.accessTypeSelected == 'Offline Password') + Text('Within the validity period, there is no limit to the number of times each device can be unlocked.', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor,fontSize: 9), + ), + + // Periodic + if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password') + Text('Within the validity period, there is no limit to the number of times each device can be unlocked, and it should be used at least once within 24 hours after the entry into force.', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor,fontSize: 9), + ), + + if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Online Password') + Text('Within the validity period, there is no limit to the number of times each device can be unlocked.', + style: Theme.of(context).textTheme.bodySmall!.copyWith( + color: ColorsManager.grayColor,fontSize: 9), + ), ], ), const SizedBox( @@ -247,19 +347,37 @@ class VisitorPasswordDialog extends StatelessWidget { title: 'Access Period', size: size, endTime: () { - visitorBloc.add(SelectTimeVisitorPassword( - context: context, - isStart: false, - isRepeat: false)); + if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password'){ + visitorBloc.add(SelectTimeEvent( + context: context, + isEffective: false)); + }else{ + visitorBloc.add(SelectTimeVisitorPassword( + context: context, + isStart: false, + isRepeat: false)); + } }, startTime: () { - visitorBloc.add(SelectTimeVisitorPassword( - context: context, - isStart: true, - isRepeat: false)); + if (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password'){ + visitorBloc.add(SelectTimeEvent(context: context, isEffective: true)); + }else{ + visitorBloc.add(SelectTimeVisitorPassword( + context: context, + isStart: true, + isRepeat: false)); + } }, - firstString: visitorBloc.startTimeAccess.toString(), - secondString: visitorBloc.endTimeAccess.toString(), + + firstString: + (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password')? + visitorBloc.effectiveTime:visitorBloc.startTimeAccess.toString(), + secondString: (visitorBloc.usageFrequencySelected == 'Periodic' && + visitorBloc.accessTypeSelected == 'Offline Password')? + visitorBloc.expirationTime:visitorBloc.endTimeAccess.toString(), icon: Assets.calendarIcon ), const SizedBox( @@ -367,12 +485,26 @@ class VisitorPasswordDialog extends StatelessWidget { onPressed: () { if (visitorBloc.forgetFormKey.currentState!.validate()) { if(visitorBloc.selectedDevices.isNotEmpty){ - if(visitorBloc.effectiveTimeTimeStamp!=null&&visitorBloc.expirationTimeTimeStamp!=null) { + if(visitorBloc.usageFrequencySelected == 'One-Time' && visitorBloc.accessTypeSelected == 'Offline Password'){ setPasswordFunction(context, size, visitorBloc); - } - else{ - visitorBloc.stateDialog(context: - context,message: 'Please select Access Period to continue',title: 'Access Period'); + }else{ + if(visitorBloc.effectiveTimeTimeStamp!=null&&visitorBloc.expirationTimeTimeStamp!=null) { + if(isRepeat==true){ + if(visitorBloc.expirationTime!='End Time'&&visitorBloc.effectiveTime!='Start Time'&&visitorBloc.selectedDays.isNotEmpty){ + setPasswordFunction(context, size, visitorBloc); + } + else{ + visitorBloc.stateDialog(context: + context,message: 'Please select days and fill start time and end time to continue',title: 'Access Period'); + } + }else{ + setPasswordFunction(context, size, visitorBloc); + } + } + else{ + visitorBloc.stateDialog(context: + context,message: 'Please select Access Period to continue',title: 'Access Period'); + } } }else{ visitorBloc.stateDialog(context: @@ -380,6 +512,57 @@ class VisitorPasswordDialog extends StatelessWidget { } } }, + + // onPressed: () { + // if (visitorBloc.forgetFormKey.currentState!.validate()) { + // if (visitorBloc.selectedDevices.isNotEmpty) { + // switch (visitorBloc.usageFrequencySelected) { + // case 'One-Time': + // if (visitorBloc.accessTypeSelected == 'Offline Password') { + // setPasswordFunction(context, size, visitorBloc); + // } else { + // visitorBloc.stateDialog( + // context: context, + // message: 'Invalid combination of Access Type and Usage Frequency.', + // title: 'Error', + // ); + // } + // break; + // default: + // if (visitorBloc.effectiveTimeTimeStamp != null && visitorBloc.expirationTimeTimeStamp != null) { + // if (isRepeat) { + // if (visitorBloc.expirationTime != 'End Time' && + // visitorBloc.effectiveTime != 'Start Time' && + // visitorBloc.selectedDays.isNotEmpty) { + // setPasswordFunction(context, size, visitorBloc); + // } else { + // visitorBloc.stateDialog( + // context: context, + // message: 'Please select days and fill start time and end time to continue', + // title: 'Access Period', + // ); + // } + // } else { + // setPasswordFunction(context, size, visitorBloc); + // } + // } else { + // visitorBloc.stateDialog( + // context: context, + // message: 'Please select Access Period to continue', + // title: 'Access Period', + // ); + // } + // break; + // } + // } 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, diff --git a/lib/services/access_mang_api.dart b/lib/services/access_mang_api.dart index 6a2cf40d..703ecd25 100644 --- a/lib/services/access_mang_api.dart +++ b/lib/services/access_mang_api.dart @@ -3,6 +3,7 @@ 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/failed_operation.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'; @@ -49,14 +50,13 @@ class AccessMangApi{ } } - Future postOnlineOneTime({ + Future postOnlineOneTime({ String? email, String? passwordName, String? password, String? effectiveTime, String? invalidTime, List? devicesUuid}) async { - try { final response = await HTTPService().post( path: ApiEndpoints.sendOnlineOneTime, body: jsonEncode({ @@ -69,19 +69,11 @@ class AccessMangApi{ }), showServerMessage: true, expectedResponseModel: (json) { - if(json['statusCode'].toString()=='201'){ - return true; - }else{ - return false; - } + return json; }, ); return response; - } on DioException catch (e) { - debugPrint('Error: ${e.message}'); - debugPrint('Error fetching ${e.response!.statusMessage}'); - return false; - } + } Future postOnlineMultipleTime({ @@ -92,7 +84,6 @@ class AccessMangApi{ String? passwordName, List? scheduleList, List? devicesUuid}) async { - try { Map body = { "email": email, "devicesUuid": devicesUuid, @@ -109,25 +100,16 @@ class AccessMangApi{ body: jsonEncode(body), showServerMessage: true, expectedResponseModel: (json) { - if(json['data']['successOperations'][0]['success'].toString()=='true'){ - return true; - }else{ - return false; - } + return json; }, ); return response; - } on DioException catch (e){ - debugPrint('Error fetching ${e.type.name}'); - debugPrint('Error fetching ${e.response!.statusMessage}'); - return false; - } + } // OffLine One Time Password Future postOffLineOneTime({String? email,String? passwordName,List? devicesUuid}) async { - try { final response = await HTTPService().post( path: ApiEndpoints.sendOffLineOneTime, body: jsonEncode({ @@ -136,20 +118,12 @@ class AccessMangApi{ "devicesUuid": devicesUuid }), showServerMessage: true, - expectedResponseModel: (json) { - if (json['data']['successOperations'][0]['success'].toString() == - 'true') { - return true; - } else { - return false; - } - } + expectedResponseModel: (json) { + return json; + }, ); return response; - } catch (e) { - debugPrint('Error fetching $e'); - return []; - } + } Future postOffLineMultipleTime({ @@ -158,32 +132,31 @@ class AccessMangApi{ String? effectiveTime, String? invalidTime, List? devicesUuid - }) async { - try { + print(jsonEncode({ + "email": email, + "devicesUuid": devicesUuid, + "passwordName": passwordName, + "effectiveTime": effectiveTime, + "invalidTime": invalidTime, + })); final response = await HTTPService().post( - path: ApiEndpoints.sendOffLineOneTime, + path: ApiEndpoints.sendOffLineMultipleTime, body: jsonEncode({ "email": email, - "devicesUuid":devicesUuid, + "devicesUuid": devicesUuid, "passwordName": passwordName, "effectiveTime": effectiveTime, - "invalidTime": invalidTime + "invalidTime": invalidTime, }), showServerMessage: true, - expectedResponseModel: (json) { - if (json['data']['successOperations'][0]['success'].toString() == - 'true') { - return true; - } else { - return false; - } - } + expectedResponseModel: (json) { + return json; + }, ); return response; - } catch (e) { - debugPrint('Error fetching $e'); - return []; - } + } -} \ No newline at end of file +} + + diff --git a/lib/services/auth_api.dart b/lib/services/auth_api.dart index 3bb8f7e7..3cd375f7 100644 --- a/lib/services/auth_api.dart +++ b/lib/services/auth_api.dart @@ -62,7 +62,8 @@ class AuthenticationAPI { debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}'); return 1; } - } else { + } + else { debugPrint('Error: ${e.message}'); return 1; } diff --git a/lib/utils/color_manager.dart b/lib/utils/color_manager.dart index 2ee12718..723c7f02 100644 --- a/lib/utils/color_manager.dart +++ b/lib/utils/color_manager.dart @@ -32,4 +32,9 @@ abstract class ColorsManager { static const Color blueColor = Color(0xFF0036E6); static const Color boxColor = Color(0xFFF5F6F7); static const Color boxDivider = Color(0xFFE0E0E0); + static const Color blue1 = Color(0xFF0036E6); + static const Color blue2 = Color(0xFF0026A2); + static const Color blue3 = Color(0xFF00165E); + static const Color blue4 = Color(0xFF001E7E); } +//0036E6 \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index 629c9fa0..b8984d5a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -260,18 +260,18 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" + sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a" url: "https://pub.dev" source: hosted - version: "10.0.5" + version: "10.0.4" leak_tracker_flutter_testing: dependency: transitive description: name: leak_tracker_flutter_testing - sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" + sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8" url: "https://pub.dev" source: hosted - version: "3.0.5" + version: "3.0.3" leak_tracker_testing: dependency: transitive description: @@ -300,18 +300,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.11.1" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 + sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136" url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "1.12.0" nested: dependency: transitive description: @@ -521,10 +521,10 @@ packages: dependency: transitive description: name: test_api - sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" + sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f" url: "https://pub.dev" source: hosted - version: "0.7.2" + version: "0.7.0" typed_data: dependency: transitive description: @@ -569,10 +569,10 @@ packages: dependency: transitive description: name: vm_service - sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" + sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec" url: "https://pub.dev" source: hosted - version: "14.2.5" + version: "14.2.1" web: dependency: transitive description: From e37ce1925b6f7253a77bd245aa9b2d86bf59bb76 Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 27 Aug 2024 11:27:31 +0300 Subject: [PATCH 2/3] fix bugs --- .../access_management/bloc/access_bloc.dart | 113 +----------------- .../view/access_management.dart | 5 +- lib/pages/common/custom_table.dart | 21 +++- lib/pages/common/custom_web_textfield.dart | 2 +- .../bloc/visitor_password_bloc.dart | 30 +---- .../view/visitor_password_dialog.dart | 79 +++++++----- lib/utils/color_manager.dart | 2 + 7 files changed, 77 insertions(+), 175 deletions(-) diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index febdb9d3..dd60237e 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -38,8 +38,9 @@ class AccessBloc extends Bloc { emit(FailedState(e.toString())); } } + void updateTabsCount() { - int toBeEffectiveCount = data.where((item) => item.passwordStatus.value== 'To Be Effective').length; + 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; tabs[1] = 'To Be Effective ($toBeEffectiveCount)'; @@ -48,7 +49,6 @@ class AccessBloc extends Bloc { } - int selectedIndex = 0; final List tabs = [ 'All', @@ -73,7 +73,6 @@ class AccessBloc extends Bloc { Future selectTime(SelectTime event, Emitter emit) async { emit(AccessLoaded()); - final DateTime? picked = await showDatePicker( context: event.context, initialDate: DateTime.now(), @@ -81,7 +80,6 @@ class AccessBloc extends Bloc { lastDate: DateTime(2101), ); if (picked != null) { - final selectedDateTime = DateTime( picked.year, picked.month, @@ -110,7 +108,6 @@ class AccessBloc extends Bloc { expirationTimeTimeStamp = selectedTimestamp; } } - } emit(ChangeTimeState()); } @@ -165,7 +162,7 @@ class AccessBloc extends Bloc { } // Filter by selected tab index - if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To Be Effective') { + if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To be effective') { matchesCriteria = false; } else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') { matchesCriteria = false; @@ -183,110 +180,6 @@ class AccessBloc extends Bloc { } - // Future _filterData(FilterDataEvent event, Emitter emit) async { - // emit(AccessLoaded()); - // try { - // filteredData = data.where((item) { - // bool matchesCriteria = true; - // - // // Filter by password name - // if (event.passwordName != null && event.passwordName!.isNotEmpty) { - // final bool matchesName = item.passwordName != null && - // item.passwordName.contains(event.passwordName); - // if (!matchesName) { - // matchesCriteria = false; - // } - // } - // - // // Filter by start time only - // if (event.startTime != null && event.endTime == null) { - // final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); - // if (effectiveTime == null || effectiveTime < event.startTime!) { - // matchesCriteria = false; - // } - // } - // - // // Filter by end time only - // if (event.endTime != null && event.startTime == null) { - // final int? invalidTime = int.tryParse(item.invalidTime.toString()); - // if (invalidTime == null || invalidTime > event.endTime!) { - // matchesCriteria = false; - // } - // } - // - // // Filter by both start time and end time - // if (event.startTime != null && event.endTime != null) { - // final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); - // final int? invalidTime = int.tryParse(item.invalidTime.toString()); - // if (effectiveTime == null || invalidTime == null) { - // matchesCriteria = false; - // } else { - // final bool matchesStartTime = effectiveTime >= event.startTime!; - // final bool matchesEndTime = invalidTime <= event.endTime!; - // if (!matchesStartTime || !matchesEndTime) { - // matchesCriteria = false; - // } - // } - // } - // - // // Filter by selected tab index - // 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(); - // - // emit(TableLoaded(filteredData)); - // } catch (e) { - // emit(FailedState(e.toString())); - // } - // } - - - // Future _filterData(FilterDataEvent event, Emitter emit) async { - // emit(AccessLoaded()); - // try { - // filteredData = data.where((item) { - // bool matchesCriteria = true; - // if (event.passwordName != null && event.passwordName!.isNotEmpty) { - // final bool matchesName = item.passwordName != null && - // item.passwordName.contains(event.passwordName); - // if (!matchesName) { - // matchesCriteria = false; - // } - // } - // if (event.startTime != null || event.endTime != null) { - // final int? effectiveTime = int.tryParse(item.effectiveTime.toString()); - // final int? invalidTime = int.tryParse(item.invalidTime.toString()); - // if (effectiveTime == null || invalidTime == null) { - // matchesCriteria = false; - // } else { - // final bool matchesStartTime = effectiveTime >= event.startTime!; - // final bool matchesEndTime = invalidTime <= event.endTime!; - // if (!matchesStartTime || !matchesEndTime) { - // matchesCriteria = false; - // } - // } - // } - // 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(); - // emit(TableLoaded(filteredData)); - // } catch (e) { - // emit(FailedState(e.toString())); - // } - // } resetSearch(ResetSearch event, Emitter emit) async{ emit(AccessLoaded()); diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 80efcd3c..6eea85e8 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -133,7 +133,6 @@ class AccessManagementPage extends StatelessWidget { ), SizedBox( - height:45, width: size.width * 0.06, child:Container( @@ -153,7 +152,6 @@ class AccessManagementPage extends StatelessWidget { width: 10, ), SizedBox( - height:45, width: size.width * 0.06, child: Container( decoration: containerDecoration, @@ -237,6 +235,7 @@ class AccessManagementPage extends StatelessWidget { 'Access Status' ], data: filteredData.map((item) { + return [ item.passwordName.toString(), item.passwordType.value, @@ -244,7 +243,7 @@ class AccessManagementPage extends StatelessWidget { item.deviceUuid.toString(), '', '', - item.passwordStatus.value + item.passwordStatus.value, ]; }).toList(), ) diff --git a/lib/pages/common/custom_table.dart b/lib/pages/common/custom_table.dart index 76e3b663..dc3c3afb 100644 --- a/lib/pages/common/custom_table.dart +++ b/lib/pages/common/custom_table.dart @@ -14,7 +14,6 @@ class DynamicTable extends StatefulWidget { final void Function(bool?)? selectAll; final void Function(int, bool?)? onRowCheckboxChanged; final List? initialSelectedIds; - const DynamicTable({ super.key, required this.headers, @@ -199,6 +198,20 @@ class _DynamicTableState extends State { } Widget _buildTableCell(String content,size) { + Color? statusColor; + switch (content) { + case 'Effective': + statusColor = ColorsManager.textGreen; + break; + case 'Expired': + statusColor = ColorsManager.red; + break; + case 'To be effective': + statusColor = ColorsManager.yaGreen; + break; + default: + statusColor = Colors.black; // Default color + } return Expanded( child: Container( height:size , @@ -213,7 +226,11 @@ class _DynamicTableState extends State { alignment: Alignment.centerLeft, child: Text( content, - style: const TextStyle(color: Colors.black, fontSize: 10,fontWeight: FontWeight.w400), + style: TextStyle( + color:statusColor, // Use the passed color or default to black + fontSize: 10, + fontWeight: FontWeight.w400 + ), ), ), ); diff --git a/lib/pages/common/custom_web_textfield.dart b/lib/pages/common/custom_web_textfield.dart index e58f51b4..a41bc662 100644 --- a/lib/pages/common/custom_web_textfield.dart +++ b/lib/pages/common/custom_web_textfield.dart @@ -73,7 +73,7 @@ class CustomWebTextField extends StatelessWidget { decoration: textBoxDecoration()! .copyWith( errorStyle: const TextStyle(height: 0), // Hide the error text space - hintStyle: TextStyle(color: ColorsManager.grayColor), + hintStyle: const TextStyle(color: ColorsManager.grayColor), hintText: 'Please enter'), ), ), diff --git a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart index 8ee44298..e1ee0edd 100644 --- a/lib/pages/visitor_password/bloc/visitor_password_bloc.dart +++ b/lib/pages/visitor_password/bloc/visitor_password_bloc.dart @@ -461,7 +461,7 @@ class VisitorPasswordBloc return null; } - Future stateDialog({ + Future stateDialog({ BuildContext? context, String? message, String? title, @@ -469,6 +469,7 @@ class VisitorPasswordBloc Widget? widgeta, }) { return showCustomDialog( + barrierDismissible: false, context: context!, message: message!, iconPath: Assets.deviceNoteIcon, @@ -479,7 +480,7 @@ class VisitorPasswordBloc [ TextButton( onPressed: () { - Navigator.of(context).pop(); + Navigator.of(context).pop(true); }, child: const Text('OK'), ), @@ -487,30 +488,5 @@ class VisitorPasswordBloc ); } - // - // Future stateAndDeviseDialog({ - // 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/view/visitor_password_dialog.dart b/lib/pages/visitor_password/view/visitor_password_dialog.dart index e3a9a291..1200ce0e 100644 --- a/lib/pages/visitor_password/view/visitor_password_dialog.dart +++ b/lib/pages/visitor_password/view/visitor_password_dialog.dart @@ -82,7 +82,9 @@ class VisitorPasswordDialog extends StatelessWidget { ), ], ) - ); + ).then((v){ + Navigator.of(context).pop(); + }); } else if (state is FailedState) { visitorBloc.stateDialog( context: context, @@ -423,7 +425,6 @@ class VisitorPasswordDialog extends StatelessWidget { ), ), ], - ), ), if (visitorBloc.usageFrequencySelected == 'Periodic' && @@ -485,8 +486,14 @@ class VisitorPasswordDialog extends StatelessWidget { onPressed: () { if (visitorBloc.forgetFormKey.currentState!.validate()) { if(visitorBloc.selectedDevices.isNotEmpty){ + if(visitorBloc.usageFrequencySelected == 'One-Time' && visitorBloc.accessTypeSelected == 'Offline Password'){ setPasswordFunction(context, size, visitorBloc); + } + else if(visitorBloc.accessTypeSelected == 'Dynamic Password'){ + print('objectobjectobjectobject'); + setPasswordFunction(context, size, visitorBloc); + }else{ if(visitorBloc.effectiveTimeTimeStamp!=null&&visitorBloc.expirationTimeTimeStamp!=null) { if(isRepeat==true){ @@ -668,37 +675,45 @@ class VisitorPasswordDialog extends StatelessWidget { 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(), - )); + if(visitorBloc.accessTypeSelected == 'Dynamic Password'){ + + }else{ + 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', diff --git a/lib/utils/color_manager.dart b/lib/utils/color_manager.dart index 723c7f02..8118ac97 100644 --- a/lib/utils/color_manager.dart +++ b/lib/utils/color_manager.dart @@ -36,5 +36,7 @@ abstract class ColorsManager { static const Color blue2 = Color(0xFF0026A2); static const Color blue3 = Color(0xFF00165E); static const Color blue4 = Color(0xFF001E7E); + static const Color textGreen = Color(0xFF008905); + static const Color yaGreen = Color(0xFFFFBF44); } //0036E6 \ No newline at end of file From bd2852231db0b731ee0db41554f5047acc89ad65 Mon Sep 17 00:00:00 2001 From: mohammad Date: Tue, 27 Aug 2024 17:03:52 +0300 Subject: [PATCH 3/3] fix bugs and fix send otp and sp-392 and sp-372 --- assets/images/grid.svg | 18 + devtools_options.yaml | 4 + ios/Podfile.lock | 36 ++ lib/main.dart | 33 +- .../access_management/bloc/access_bloc.dart | 2 +- .../model/password_model.dart | 2 +- .../view/access_management.dart | 446 +++++++++--------- lib/pages/auth/view/login_web_page.dart | 10 +- lib/pages/home/bloc/home_bloc.dart | 8 +- lib/pages/home/view/home_page.dart | 6 +- lib/pages/home/view/home_page_web.dart | 8 +- lib/pages/spaseManagementIcon.dart | 16 + .../visitor_password/model/device_model.dart | 2 +- .../view/add_device_dialog.dart | 2 +- lib/services/auth_api.dart | 5 +- lib/utils/app_routes.dart | 33 ++ .../constants/{const.dart => app_enum.dart} | 0 lib/utils/constants/assets.dart | 1 + lib/utils/constants/routes_const.dart | 6 + lib/utils/navigation_service.dart | 3 + pubspec.lock | 16 + pubspec.yaml | 2 + 22 files changed, 421 insertions(+), 238 deletions(-) create mode 100644 assets/images/grid.svg create mode 100644 devtools_options.yaml create mode 100644 ios/Podfile.lock create mode 100644 lib/pages/spaseManagementIcon.dart create mode 100644 lib/utils/app_routes.dart rename lib/utils/constants/{const.dart => app_enum.dart} (100%) create mode 100644 lib/utils/constants/routes_const.dart diff --git a/assets/images/grid.svg b/assets/images/grid.svg new file mode 100644 index 00000000..f3e41133 --- /dev/null +++ b/assets/images/grid.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/devtools_options.yaml b/devtools_options.yaml new file mode 100644 index 00000000..2bc8e05f --- /dev/null +++ b/devtools_options.yaml @@ -0,0 +1,4 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: + - provider: true \ No newline at end of file diff --git a/ios/Podfile.lock b/ios/Podfile.lock new file mode 100644 index 00000000..85fd7a99 --- /dev/null +++ b/ios/Podfile.lock @@ -0,0 +1,36 @@ +PODS: + - Flutter (1.0.0) + - flutter_secure_storage (6.0.0): + - Flutter + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter + - FlutterMacOS + +DEPENDENCIES: + - Flutter (from `Flutter`) + - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) + +EXTERNAL SOURCES: + Flutter: + :path: Flutter + flutter_secure_storage: + :path: ".symlinks/plugins/flutter_secure_storage/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" + +SPEC CHECKSUMS: + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 + flutter_secure_storage: d33dac7ae2ea08509be337e775f6b59f1ff45f12 + path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 + shared_preferences_foundation: fcdcbc04712aee1108ac7fda236f363274528f78 + +PODFILE CHECKSUM: 819463e6a0290f5a72f145ba7cde16e8b6ef0796 + +COCOAPODS: 1.15.2 diff --git a/lib/main.dart b/lib/main.dart index 9c68747d..a4f4fcb8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,30 +1,39 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/access_management/view/access_management.dart'; 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/spaseManagementIcon.dart'; import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart'; import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart'; +import 'package:go_router/go_router.dart'; import 'package:syncrow_web/services/locator.dart'; +import 'package:syncrow_web/utils/app_routes.dart'; import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/routes_const.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - initialSetup(); // Perform initial setup, e.g., dependency injection + initialSetup(); String checkToken = await AuthBloc.getTokenAndValidate(); + GoRouter router = GoRouter( + initialLocation: checkToken == 'Success' ? RoutesConst.home :RoutesConst.main , + routes: AppRoutes.getRoutes(), + ); runApp(MyApp( - isLoggedIn: checkToken, + router: router, )); } - class MyApp extends StatelessWidget { - final dynamic isLoggedIn; + final GoRouter router; const MyApp({ super.key, - required this.isLoggedIn, + required this.router, }); + @override Widget build(BuildContext context) { return MultiBlocProvider( @@ -33,7 +42,7 @@ class MyApp extends StatelessWidget { BlocProvider( create: (context) => VisitorPasswordBloc(),) ], - child: MaterialApp( + child: MaterialApp.router( debugShowCheckedModeBanner: false, // Hide debug banner scrollBehavior: const MaterialScrollBehavior().copyWith( dragDevices: { @@ -60,8 +69,16 @@ 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(), + + routeInformationProvider: router.routeInformationProvider, + routerDelegate: router.routerDelegate, + routeInformationParser: router.routeInformationParser, + )); } } + + + + + diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart index dd60237e..0ba74a52 100644 --- a/lib/pages/access_management/bloc/access_bloc.dart +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -5,7 +5,7 @@ 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/constants/app_enum.dart'; import 'package:syncrow_web/utils/snack_bar.dart'; class AccessBloc extends Bloc { diff --git a/lib/pages/access_management/model/password_model.dart b/lib/pages/access_management/model/password_model.dart index 584e9b7e..e16cc586 100644 --- a/lib/pages/access_management/model/password_model.dart +++ b/lib/pages/access_management/model/password_model.dart @@ -1,4 +1,4 @@ -import 'package:syncrow_web/utils/constants/const.dart'; +import 'package:syncrow_web/utils/constants/app_enum.dart'; class PasswordModel { final dynamic passwordId; diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart index 6eea85e8..2e939993 100644 --- a/lib/pages/access_management/view/access_management.dart +++ b/lib/pages/access_management/view/access_management.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:go_router/go_router.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_event.dart'; import 'package:syncrow_web/pages/access_management/bloc/access_state.dart'; @@ -7,10 +9,12 @@ import 'package:syncrow_web/pages/common/custom_table.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/home/view/home_page.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/constants/app_enum.dart'; +import 'package:syncrow_web/utils/constants/routes_const.dart'; import 'package:syncrow_web/utils/style.dart'; import 'package:syncrow_web/web_layout/web_scaffold.dart'; @@ -18,6 +22,7 @@ class AccessManagementPage extends StatelessWidget { const AccessManagementPage({super.key}); @override Widget build(BuildContext context) { + Size size = MediaQuery.of(context).size; return WebScaffold( enableMenuSideba: false, @@ -29,231 +34,252 @@ class AccessManagementPage extends StatelessWidget { ], ), appBarBody: [ - Text('Physical Access', - style: Theme.of(context).textTheme - .headlineMedium! - .copyWith(color: Colors.white), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text('Physical Access', + style: Theme.of(context).textTheme.headlineMedium! + .copyWith(color: Colors.white), + ), + Row( + children: [ + InkWell( + onTap: () { + context.go(RoutesConst.home); + }, + child: SvgPicture.asset( + height: 20, + width: 20, + Assets.grid, + ), + ), + const SizedBox(width: 10,) + + ], + ), + ], ), ], 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; - return state is AccessLoaded? - const Center(child: CircularProgressIndicator()): - Container( - padding: EdgeInsets.all(30), - height: size.height, - width: size.width, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - decoration: containerDecoration, - height: size.height * 0.05, - child: Flexible( - child: ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: BlocProvider.of(context).tabs.length, - shrinkWrap: true, - itemBuilder: (context, index) { - 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, + child: BlocConsumer(listener: (context, state) {}, + builder: (context, state) { + final accessBloc = BlocProvider.of(context); + final filteredData = accessBloc.filteredData; + return state is AccessLoaded? + const Center(child: CircularProgressIndicator()): + Container( + padding: EdgeInsets.all(30), + height: size.height, + width: size.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + decoration: containerDecoration, + height: size.height * 0.05, + child: Flexible( + child: ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: BlocProvider.of(context).tabs.length, + shrinkWrap: true, + itemBuilder: (context, index) { + 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, ), - 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, + 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, + ), ), ), ), - ), - ); - }, - ), - ), - ), - const SizedBox( - height: 20, - ), - Row( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.end, - textBaseline: TextBaseline.ideographic, children: [ - Container( - width: size.width * 0.15, - child: CustomWebTextField( - controller: accessBloc.passwordName, - isRequired: true, - textFieldName: 'Name', - description: '', - ), - ), - const SizedBox( - width: 15, - ), - DateTimeWebWidget( - icon: Assets.calendarIcon, - isRequired: false, - title: 'Access Time', - size: size, - endTime: () { - accessBloc.add(SelectTime(context: context, isStart: false)); - }, - startTime: () { - accessBloc.add(SelectTime(context: context, isStart: true)); - }, - firstString:BlocProvider.of(context).startTime , - secondString:BlocProvider.of(context).endTime , - ) , - const SizedBox( - width: 15, - ), - - SizedBox( - - width: size.width * 0.06, - 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( - width: size.width * 0.06, - 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), - ), ), ), ), - ], - ), - const SizedBox( - height: 20, - ), - Wrap( - children: [ - Container( - width: size.width * 0.15, - decoration: containerDecoration, - child: DefaultButton( - onPressed: () { - showDialog( - context: context, - barrierDismissible: false, - builder: (BuildContext context) { - return const VisitorPasswordDialog(); - }, - ).then((v){ - if(v!=null){ - accessBloc.add(FetchTableData()); - } - }); - }, - borderRadius: 8, - child: const Text('+ Create Visitor Password ')), + const SizedBox( + height: 20, + ), + Row( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + textBaseline: TextBaseline.ideographic, + children: [ + Container( + width: size.width * 0.15, + child: CustomWebTextField( + controller: accessBloc.passwordName, + isRequired: true, + textFieldName: 'Name', + description: '', + ), + ), + const SizedBox( + width: 15, + ), + DateTimeWebWidget( + icon: Assets.calendarIcon, + isRequired: false, + title: 'Access Time', + size: size, + endTime: () { + accessBloc.add(SelectTime(context: context, isStart: false)); + }, + startTime: () { + accessBloc.add(SelectTime(context: context, isStart: true)); + }, + firstString:BlocProvider.of(context).startTime , + secondString:BlocProvider.of(context).endTime , + ) , + const SizedBox( + width: 15, + ), + + SizedBox( + + width: size.width * 0.06, + 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( + width: size.width * 0.06, + 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), + ), + ), + ), + ), + ], ), const SizedBox( - width: 10, + height: 20, ), - Container( - width: size.width * 0.12, - decoration: containerDecoration, - child: DefaultButton( - borderRadius: 8, - backgroundColor: ColorsManager.whiteColors, - child: Text( - 'Admin Password', - style: Theme.of(context) - .textTheme - .bodySmall! - .copyWith(color: Colors.black), - ))) + Wrap( + children: [ + Container( + width: size.width * 0.15, + decoration: containerDecoration, + child: DefaultButton( + onPressed: () { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) { + return const VisitorPasswordDialog(); + }, + ).then((v){ + if(v!=null){ + accessBloc.add(FetchTableData()); + } + }); + }, + borderRadius: 8, + child: const Text('+ Create Visitor Password ')), + ), + const SizedBox( + width: 10, + ), + Container( + width: size.width * 0.12, + decoration: containerDecoration, + child: DefaultButton( + borderRadius: 8, + backgroundColor: ColorsManager.whiteColors, + child: Text( + 'Admin Password', + style: Theme.of(context) + .textTheme + .bodySmall! + .copyWith(color: Colors.black), + ))) + ], + ), + const SizedBox( + height: 20, + ), + Expanded( + child: DynamicTable( + isEmpty: filteredData.isEmpty , + withCheckBox: false, + size: size, + cellDecoration: containerDecoration, + headers: const [ + 'Name', + 'Access Type', + 'Access Period', + 'Accessible Device', + 'Authorizer', + 'Authorization Date & Time', + 'Access Status' + ], + data: filteredData.map((item) { + + return [ + 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 SizedBox( - height: 20, - ), - Expanded( - child: DynamicTable( - isEmpty: filteredData.isEmpty , - withCheckBox: false, - size: size, - cellDecoration: containerDecoration, - headers: const [ - 'Name', - 'Access Type', - 'Access Period', - 'Accessible Device', - 'Authorizer', - 'Authorization Date & Time', - 'Access Status' - ], - data: filteredData.map((item) { - - return [ - 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()), - ) - ], - ), - ); - }))); + ); + })) + ); } } - diff --git a/lib/pages/auth/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart index d8b22d38..9ce60a4c 100644 --- a/lib/pages/auth/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/widgets.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; +import 'package:go_router/go_router.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; @@ -13,7 +14,7 @@ import 'package:syncrow_web/pages/common/default_button.dart'; import 'package:syncrow_web/pages/common/first_layer.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; -import 'package:syncrow_web/pages/home/view/home_page.dart'; +import 'package:syncrow_web/utils/constants/routes_const.dart'; import 'package:syncrow_web/utils/style.dart'; class LoginWebPage extends StatefulWidget { @@ -33,13 +34,8 @@ class _LoginWebPageState extends State { child: BlocConsumer( listener: (context, state) { if (state is LoginSuccess) { - // Navigate to home screen after successful login - Navigator.pushReplacement( - context, - MaterialPageRoute(builder: (context) => HomePage()), - ); + context.pushReplacement(RoutesConst.home); } else if (state is LoginFailure) { - // Show error message ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(state.error), diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index ebcc6b4e..57913c1f 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -2,15 +2,18 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; +import 'package:go_router/go_router.dart'; import 'package:graphview/GraphView.dart'; import 'package:syncrow_web/pages/access_management/view/access_management.dart'; import 'package:syncrow_web/pages/auth/model/user_model.dart'; import 'package:syncrow_web/pages/home/bloc/home_event.dart'; import 'package:syncrow_web/pages/home/bloc/home_state.dart'; import 'package:syncrow_web/pages/home/home_model/home_item_model.dart'; +import 'package:syncrow_web/pages/spaseManagementIcon.dart'; import 'package:syncrow_web/services/home_api.dart'; import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:syncrow_web/utils/constants/routes_const.dart'; class HomeBloc extends Bloc { final Graph graph = Graph()..isTree = true; @@ -60,9 +63,7 @@ class HomeBloc extends Bloc { icon: Assets.accessIcon, active: true, onPress: (context) { - Navigator.of(context).push( - MaterialPageRoute(builder: (context) => AccessManagementPage()), - ); + context.go(RoutesConst.accessManagementPage); }, color: null, ), @@ -71,6 +72,7 @@ class HomeBloc extends Bloc { icon: Assets.spaseManagementIcon, active: true, onPress: (context) { + }, color: ColorsManager.primaryColor, ), diff --git a/lib/pages/home/view/home_page.dart b/lib/pages/home/view/home_page.dart index b4225ae2..3d23317c 100644 --- a/lib/pages/home/view/home_page.dart +++ b/lib/pages/home/view/home_page.dart @@ -8,9 +8,11 @@ class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { - return ResponsiveLayout( + return + + ResponsiveLayout( desktopBody: HomeWebPage(), mobileBody:HomeMobilePage() - ); + ); } } diff --git a/lib/pages/home/view/home_page_web.dart b/lib/pages/home/view/home_page_web.dart index 39a79a57..f542f6d3 100644 --- a/lib/pages/home/view/home_page_web.dart +++ b/lib/pages/home/view/home_page_web.dart @@ -12,7 +12,11 @@ class HomeWebPage extends StatelessWidget { @override Widget build(BuildContext context) { Size size = MediaQuery.of(context).size; - return WebScaffold( + return PopScope( + canPop: false, + onPopInvoked: (didPop) => false, + child: + WebScaffold( enableMenuSideba: false, appBarTitle: Row( children: [ @@ -74,6 +78,6 @@ class HomeWebPage extends StatelessWidget { ); }, ), - )); + ))); } } diff --git a/lib/pages/spaseManagementIcon.dart b/lib/pages/spaseManagementIcon.dart new file mode 100644 index 00000000..510b90b9 --- /dev/null +++ b/lib/pages/spaseManagementIcon.dart @@ -0,0 +1,16 @@ + + + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +class SpaseManagementicon extends StatelessWidget { + const SpaseManagementicon({super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container(), + ); + } +} diff --git a/lib/pages/visitor_password/model/device_model.dart b/lib/pages/visitor_password/model/device_model.dart index 2c3ce8d9..38ea0396 100644 --- a/lib/pages/visitor_password/model/device_model.dart +++ b/lib/pages/visitor_password/model/device_model.dart @@ -1,6 +1,6 @@ -import 'package:syncrow_web/utils/constants/const.dart'; +import 'package:syncrow_web/utils/constants/app_enum.dart'; class DeviceModel { dynamic productUuid; diff --git a/lib/pages/visitor_password/view/add_device_dialog.dart b/lib/pages/visitor_password/view/add_device_dialog.dart index e5e4853c..25bf56c4 100644 --- a/lib/pages/visitor_password/view/add_device_dialog.dart +++ b/lib/pages/visitor_password/view/add_device_dialog.dart @@ -9,7 +9,7 @@ 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/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/constants/app_enum.dart'; import 'package:syncrow_web/utils/style.dart'; class AddDeviceDialog extends StatelessWidget { diff --git a/lib/services/auth_api.dart b/lib/services/auth_api.dart index 3cd375f7..dc1064aa 100644 --- a/lib/services/auth_api.dart +++ b/lib/services/auth_api.dart @@ -43,10 +43,11 @@ class AuthenticationAPI { }, showServerMessage: true, expectedResponseModel: (json) { - return 30; + return json['data']['cooldown']; } ); - return 30; + + return response; } on DioException catch (e) { if (e.response != null) { if (e.response!.statusCode == 400) { diff --git a/lib/utils/app_routes.dart b/lib/utils/app_routes.dart new file mode 100644 index 00000000..7f979d74 --- /dev/null +++ b/lib/utils/app_routes.dart @@ -0,0 +1,33 @@ +import 'package:go_router/go_router.dart'; +import 'package:syncrow_web/pages/access_management/view/access_management.dart'; +import 'package:syncrow_web/pages/auth/view/login_page.dart'; +import 'package:syncrow_web/pages/home/view/home_page.dart'; +import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart'; +import 'package:syncrow_web/utils/constants/routes_const.dart'; + +class AppRoutes { + static List getRoutes() { + return [ + GoRoute( + path:RoutesConst.main, + builder: (context, state) => const LoginPage(), + ), + + GoRoute( + path: RoutesConst.home, + builder: (context, state) => const HomePage(), + ), + + GoRoute( + path: RoutesConst.visitorPassword, + builder: (context, state) => const VisitorPasswordDialog(), + ), + + GoRoute( + path: RoutesConst.accessManagementPage , + builder: (context, state) => const AccessManagementPage(), + ), + + ]; + } +} diff --git a/lib/utils/constants/const.dart b/lib/utils/constants/app_enum.dart similarity index 100% rename from lib/utils/constants/const.dart rename to lib/utils/constants/app_enum.dart diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index f4a2859e..18c3bb7b 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -27,4 +27,5 @@ class Assets { 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"; + static const String grid = "assets/images/grid.svg"; } diff --git a/lib/utils/constants/routes_const.dart b/lib/utils/constants/routes_const.dart new file mode 100644 index 00000000..b107b0fe --- /dev/null +++ b/lib/utils/constants/routes_const.dart @@ -0,0 +1,6 @@ +class RoutesConst { + static const String main = '/'; + static const String home = '/home'; + static const String visitorPassword = '/visitor-password'; + static const String accessManagementPage = '/access-management-page'; +} diff --git a/lib/utils/navigation_service.dart b/lib/utils/navigation_service.dart index c0b12167..c9d654e6 100644 --- a/lib/utils/navigation_service.dart +++ b/lib/utils/navigation_service.dart @@ -5,3 +5,6 @@ class NavigationService { static GlobalKey? snackbarKey = GlobalKey(); } + + + diff --git a/pubspec.lock b/pubspec.lock index b8984d5a..9a9cd6a8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -216,6 +216,14 @@ packages: url: "https://pub.dev" source: hosted version: "7.7.0" + go_router: + dependency: "direct main" + description: + name: go_router + sha256: "2ddb88e9ad56ae15ee144ed10e33886777eb5ca2509a914850a5faa7b52ff459" + url: "https://pub.dev" + source: hosted + version: "14.2.7" graphview: dependency: "direct main" description: @@ -288,6 +296,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + logging: + dependency: transitive + description: + name: logging + sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + url: "https://pub.dev" + source: hosted + version: "1.2.0" matcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index faaa7ddb..20118a0a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -44,7 +44,9 @@ dependencies: flutter_secure_storage: ^9.2.2 shared_preferences: ^2.3.0 data_table_2: ^2.5.15 + go_router: intl: ^0.19.0 + dev_dependencies: flutter_test: sdk: flutter