Success dialog and Failed dialog changes with VisitorPasswordDialog

This commit is contained in:
mohammad
2024-08-23 22:16:48 +03:00
parent f5a7441b3c
commit cf1a21e121
19 changed files with 792 additions and 785 deletions

View File

@ -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"
}
]

View File

@ -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<VisitorPasswordBloc>(
create: (context) => VisitorPasswordBloc(),)
],
child: MaterialApp(
debugShowCheckedModeBanner: false, // Hide debug banner

View File

@ -39,12 +39,9 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
}
}
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<AccessEvent, AccessState> {
int selectedIndex = 0;
final List<String> tabs = [
'All',
'To Be Effective (0)',
@ -76,7 +72,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async {
final DateTime? picked = await showDatePicker(
context: event.context,
initialDate: DateTime.now(),
@ -146,8 +141,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
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<AccessEvent, AccessState> {
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<AccessEvent, AccessState> {
}
}
}
// 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<AccessEvent, AccessState> {
} 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<AccessEvent, AccessState> {
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<AccessEvent, AccessState> {
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<AccessEvent, AccessState> {
filteredData = data;
}
add(FilterDataEvent(
selectedTabIndex: selectedIndex, // Pass the selected tab index
selectedTabIndex: selectedIndex,
passwordName: passwordName.text.toLowerCase(),
startTime: effectiveTimeTimeStamp,
endTime: expirationTimeTimeStamp

View File

@ -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<AccessBloc>(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<AccessBloc>(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),
),
],
),
),
),
],

View File

@ -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);
},
),
)

View File

@ -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<void> 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: <Widget>[
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),
),
),
],
);
},
);
}

View File

@ -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<DynamicTable> {
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<DynamicTable> {
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<DynamicTable> {
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<DynamicTable> {
}
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<DynamicTable> {
);
}
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<DynamicTable> {
);
}
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(

View File

@ -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'),
),
),
],

View File

@ -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<HourPickerDialog> {
@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<HourPickerDialog> {
SizedBox(width: 16.0),
DropdownButton<bool>(
value: _isPm,
items: [
items: const [
DropdownMenuItem(
value: false,
child: Text('AM'),
@ -67,14 +67,14 @@ class _HourPickerDialogState extends State<HourPickerDialog> {
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'),
),
],
);

View File

@ -66,7 +66,7 @@ class InfoDialog extends StatelessWidget {
onPressed: () {
Navigator.of(context).pop();
},
child: Text('OK'),
child: const Text('OK'),
),
],
);

View File

@ -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

View File

@ -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<VisitorPasswordEvent, VisitorPasswordState> {
VisitorPasswordBloc() : super(VisitorPasswordInitial()) {
@ -23,10 +24,8 @@ class VisitorPasswordBloc
on<ToggleDaySelectionEvent>(toggleDaySelection);
on<SelectDeviceEvent>(selectDevice);
on<UpdateFilteredDevicesEvent>(_onUpdateFilteredDevices);
on<OnlineOneTimePasswordEvent>(postOnlineOneTimePassword);
on<OnlineMultipleTimePasswordEvent>(postOnlineMultipleTimePassword);
on<OfflineMultipleTimePasswordEvent>(postOfflineMultipleTimePassword);
on<OfflineOneTimePasswordEvent>(postOfflineOneTimePassword);
on<SelectTimeEvent>(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<VisitorPasswordState> emit) {
accessTypeSelected = event.type;
@ -81,9 +76,9 @@ class VisitorPasswordBloc
}
Future<void> selectTimeVisitorPassword(
SelectTimeVisitorPassword event,
Emitter<VisitorPasswordState> emit,
) async {
SelectTimeVisitorPassword event,
Emitter<VisitorPasswordState> 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<void> postOnlineOneTimePassword(OnlineOneTimePasswordEvent event,
Emitter<VisitorPasswordState> 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<void> postOnlineMultipleTimePassword(
OnlineMultipleTimePasswordEvent event,
Emitter<VisitorPasswordState> 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<void> postOfflineOneTimePassword(OfflineOneTimePasswordEvent event,
Emitter<VisitorPasswordState> 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<VisitorPasswordState> 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<VisitorPasswordState> 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<void> selectTimeOfLinePassword(SelectTimeEvent event, Emitter<VisitorPasswordState> emit) async {
Future<void> selectTimeOfLinePassword(
SelectTimeEvent event, Emitter<VisitorPasswordState> 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<void> stateDialog({
BuildContext? context,
String? message,
String? title,
dynamic actions,
}) {
return showCustomDialog(
context: context!,
message: message!,
iconPath: Assets.deviceNoteIcon,
title: title,
dialogHeight: 150,
actions: actions ??
<Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('OK'),
),
],
);
}
}

View File

@ -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<Object> get props => [email!,passwordName!,];
List<Object> 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<Object> get props => [email!,passwordName!,invalidTime!,effectiveTime!];
List<Object> get props => [email!,passwordName!,invalidTime!,effectiveTime!,context!];
}

View File

@ -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;

View File

@ -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,

View File

@ -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<VisitorPasswordBloc, VisitorPasswordState>(
builder: (BuildContext context, VisitorPasswordState state) {
child: BlocListener<VisitorPasswordBloc, VisitorPasswordState>(
listener: (context, state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(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: <Widget>[
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 visitors 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<VisitorPasswordBloc, VisitorPasswordState>(
builder: (BuildContext context, VisitorPasswordState state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(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: <Widget>[
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 visitors email address.',
),
),
const Spacer(),
],
),
Row(
children: <Widget>[
SizedBox(
width: size.width * 0.15,
child: RadioListTile<String>(
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<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
}
},
),
),
SizedBox(
width: size.width * 0.15,
child: RadioListTile<String>(
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<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
}
},
),
),
SizedBox(
width: size.width * 0.15,
child: RadioListTile<String>(
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<VisitorPasswordBloc>()
.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: <Widget>[
SizedBox(
width: 200,
child: RadioListTile<String>(
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<VisitorPasswordBloc>()
.add(SelectUsageFrequency(value));
}
},
),
),
SizedBox(
width: 200,
child: RadioListTile<String>(
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<VisitorPasswordBloc>()
.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: <Widget>[
SizedBox(
width: size.width * 0.15,
child: RadioListTile<String>(
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<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
}
},
),
),
SizedBox(
width: size.width * 0.15,
child: RadioListTile<String>(
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<VisitorPasswordBloc>().add(SelectPasswordType(value));
}
},
),
),
SizedBox(
width: size.width * 0.15,
child: RadioListTile<String>(
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<VisitorPasswordBloc>()
.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: <Widget>[
SizedBox(
width: 200,
child: RadioListTile<String>(
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<VisitorPasswordBloc>()
.add(SelectUsageFrequency(value));
}
},
),
),
SizedBox(
width: 200,
child: RadioListTile<String>(
title: Text('Periodic',
style: text),
value: 'Periodic',
groupValue: (state is UsageFrequencySelected)
? state.selectedFrequency
: visitorBloc.usageFrequencySelected,
onChanged: (String? value) {
if (value != null) {
context.read<VisitorPasswordBloc>()
.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: <Widget>[
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<void> setPasswordFunction(
BuildContext context,
Size size,
VisitorPasswordBloc visitorBloc,
) {
return showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
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: <Widget>[
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: <Widget>[
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,
),
),
),
),
],
);
}
},
);
},
);
}
}

View File

@ -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<List<PasswordModel>> fetchVisitorPassword() async {
@ -17,7 +16,6 @@ class AccessMangApi{
showServerMessage: true,
expectedResponseModel: (json) {
List<dynamic> jsonData = json;
print('Password List: $json');
List<PasswordModel> passwordList = jsonData.map((jsonItem) {
return PasswordModel.fromJson(jsonItem);
}).toList();
@ -38,7 +36,6 @@ class AccessMangApi{
showServerMessage: true,
expectedResponseModel: (json) {
List<dynamic> jsonData = json;
print('fetchDevices List: $json');
List<DeviceModel> passwordList = jsonData.map((jsonItem) {
return DeviceModel.fromJson(jsonItem);
}).toList();
@ -60,18 +57,6 @@ class AccessMangApi{
String? invalidTime,
List<String>? 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<String>? 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<dynamic> 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<dynamic> 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) {

View File

@ -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<Token> 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}');

View File

@ -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<Widget>? appBarBody;
final Widget? scaffoldBody;
const WebScaffold({super.key,this.appBarTitle,this.appBarBody,this.scaffoldBody,this.enableMenuSideba=true});
@override
Widget build(BuildContext context) {
return Scaffold(