create visitor password

This commit is contained in:
mohammad
2024-08-18 17:08:36 +03:00
parent e610f7335d
commit 869a10f92c
21 changed files with 932 additions and 368 deletions

View File

@ -171,11 +171,10 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
}
DateTime timestampToDateTime(dynamic timestamp) {
return DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
String timestampToDate(dynamic timestamp) {
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}";
}
}

View File

@ -1,3 +1,5 @@
import 'package:syncrow_web/utils/constants/const.dart';
class PasswordModel {
final dynamic passwordId;
final dynamic invalidTime;
@ -6,7 +8,7 @@ class PasswordModel {
final dynamic createdTime;
final dynamic passwodName; // New field
final dynamic passwordStatus;
final dynamic passwordType;
final AccessType passwordType;
final dynamic deviceUuid;
PasswordModel({
@ -17,7 +19,7 @@ class PasswordModel {
this.createdTime,
this.passwodName, // New field
this.passwordStatus,
this.passwordType,
required this.passwordType,
this.deviceUuid,
});
@ -30,7 +32,7 @@ class PasswordModel {
createdTime: json['createdTime'],
passwodName: json['passwodName']??'No name', // New field
passwordStatus: json['passwordStatus'],
passwordType: json['passwordType'],
passwordType:AccessTypeExtension.fromString(json['passwordType']) ,
deviceUuid: json['deviceUuid'],
);
}

View File

@ -3,10 +3,12 @@ import 'package:flutter_bloc/flutter_bloc.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';
import 'package:syncrow_web/pages/common/custom_table.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';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/const.dart';
import 'package:syncrow_web/utils/style.dart';
import 'package:syncrow_web/web_layout/web_scaffold.dart';
@ -51,68 +53,69 @@ class AccessManagementPage extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
height: size.height * 0.05,
width:size.width * 0.26 ,
decoration: containerDecoration,
child: Center(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: BlocProvider.of<AccessBloc>(context).tabs.length,
itemBuilder: (context, index) {
final isSelected = index ==
BlocProvider.of<AccessBloc>(context).selectedIndex;
return InkWell(
onTap: () {
BlocProvider.of<AccessBloc>(context).add(TabChangedEvent(index));
},
child: Container(
decoration: BoxDecoration(
color: ColorsManager.boxColor,
border: Border.all(
color: isSelected ? Colors.blue : Colors.transparent,
width: 2.0,),
borderRadius: index == 0
? const BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10))
: index == 3
? const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10))
: null),
padding: const EdgeInsets.only(left: 10,right: 10),
child: Center(
child: Text(
BlocProvider.of<AccessBloc>(context).tabs[index],
style: TextStyle(
color: isSelected
? Colors.blue
: Colors.black,
height: size.height * 0.05,
child: Flexible(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: BlocProvider.of<AccessBloc>(context).tabs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final isSelected = index ==
BlocProvider.of<AccessBloc>(context).selectedIndex;
return InkWell(
onTap: () {
BlocProvider.of<AccessBloc>(context).add(TabChangedEvent(index));
},
child: Container(
decoration: BoxDecoration(
color: ColorsManager.boxColor,
border: Border.all(
color: isSelected ? Colors.blue : Colors.transparent,
width: 2.0,),
borderRadius: index == 0
? const BorderRadius.only(
topLeft: Radius.circular(10),
bottomLeft: Radius.circular(10))
: index == 3
? const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10))
: null),
padding: const EdgeInsets.only(left: 10,right: 10),
child: Center(
child: Text(
BlocProvider.of<AccessBloc>(context).tabs[index],
style: TextStyle(
color: isSelected
? Colors.blue
: Colors.black,
),
),
),
),
),
);
},
);
},
),
),
),
),
const SizedBox(
height: 20,
),
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text('Password Name'),
const Text('Name'),
Container(
width: size.width * 0.15,
decoration: containerDecoration,
child: TextFormField(
controller: accessBloc.passwordName,
style: TextStyle(color: Colors.black),
style: const TextStyle(color: Colors.black),
decoration: textBoxDecoration()!
.copyWith(hintText: 'Please enter'),
)),
@ -206,7 +209,7 @@ class AccessManagementPage extends StatelessWidget {
);
},
borderRadius: 8,
child: Text('+ Create Visitor Password ')),
child: const Text('+ Create Visitor Password ')),
),
const SizedBox(
width: 10,
@ -230,120 +233,110 @@ class AccessManagementPage extends StatelessWidget {
height: 20,
),
Expanded(
child: state is TableLoaded
? TableWidget(size, state,accessBloc)
: const Center(child: CircularProgressIndicator()))
child: state is TableLoaded
? DynamicTable(
size: size,
cellDecoration: containerDecoration,
headers: const [
'Name',
'Access Type',
'Access Period',
'Device Id',
'Authorizer',
'Authorization Date & Time',
'Access Status'
],
data: state.data.map((item) {
return [
item.passwodName.toString(),
item.passwordType.value,
('${accessBloc.timestampToDate(item.effectiveTime)} - ${accessBloc.timestampToDate(item.invalidTime)}'),
item.deviceUuid.toString(),
'',
'',
''
];
}).toList(),
)
: const Center(child: CircularProgressIndicator()),
)
],
),
);
})));
}
Container TableWidget(Size size, TableLoaded state,AccessBloc accessBloc) {
return Container(
decoration: containerDecoration,
width: size.width,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
width: size.width,
height: size.height,
child: Column(
children: [
Container(
color: ColorsManager.boxColor,
child: Row(
children: [
_buildTableHeaderCell('Password name'),
_buildTableHeaderCell(' Password Type'),
_buildTableHeaderCell('Start Time'),
_buildTableHeaderCell('End Time'),
_buildTableHeaderCell('Device Id'),
// _buildTableHeaderCell('Authorization Source'),
// _buildTableHeaderCell('Authorizer'),
_buildTableHeaderCell('Password Created'),
// _buildTableHeaderCell('Access Status'),
_buildTableHeaderCell('Password Status'),
],
),
),
Expanded(
child: Container(
width: size.width,
color: ColorsManager.whiteColors,
child: ListView(
shrinkWrap: true,
children: [
Column(
children: state.data.map((item) {
return Row(
children: [
_buildTableCell(item.passwodName),
_buildTableCell(item.passwordType),
_buildTableCell(accessBloc.timestampToDateTime(item.effectiveTime).toString()),
_buildTableCell(accessBloc.timestampToDateTime(item.invalidTime).toString()),
_buildTableCell(item.deviceUuid.toString()),
// _buildTableCell(item.authorizationSource),
// _buildTableCell(item.authorizer),
_buildTableCell(item.passwordCreated!=null?accessBloc.timestampToDateTime(item.passwordCreated).toString():'no data'),
// _buildTableCell(item.accessStatus),
_buildTableCell(item.passwordStatus.toString()),
],
);
}).toList(),
),
],
),
),
),
],
),
),
],
),
),
);
}
// Container TableWidget(Size size, TableLoaded state,AccessBloc accessBloc) {
// return Container(
// decoration: containerDecoration,
// width: size.width,
// child: Padding(
// padding: const EdgeInsets.all(10.0),
// child: ListView(
// scrollDirection: Axis.horizontal,
// children: [
// Container(
// width: size.width,
// height: size.height,
// child: Column(
// children: [
// Container(
// color: ColorsManager.boxColor,
// child: Row(
// children: [
// _buildTableHeaderCell('Password name'),
// _buildTableHeaderCell(' Password Type'),
// _buildTableHeaderCell('Start Time'),
// _buildTableHeaderCell('End Time'),
// _buildTableHeaderCell('Device Id'),
// // _buildTableHeaderCell('Authorization Source'),
// // _buildTableHeaderCell('Authorizer'),
// _buildTableHeaderCell('Password Created'),
// // _buildTableHeaderCell('Access Status'),
// _buildTableHeaderCell('Password Status'),
// ],
// ),
// ),
// Expanded(
// child: Container(
// width: size.width,
// color: ColorsManager.whiteColors,
// child: ListView(
// shrinkWrap: true,
// children: [
// Column(
// children: state.data.map((item) {
// return Row(
// children: [
// _buildTableCell(item.passwodName),
// _buildTableCell(item.passwordType),
//
// _buildTableCell(accessBloc.timestampToDateTime(item.effectiveTime).toString()),
// _buildTableCell(accessBloc.timestampToDateTime(item.invalidTime).toString()),
// _buildTableCell(item.deviceUuid.toString()),
// // _buildTableCell(item.authorizationSource),
// // _buildTableCell(item.authorizer),
// _buildTableCell(item.passwordCreated!=null?accessBloc.timestampToDateTime(item.passwordCreated).toString():'no data'),
// // _buildTableCell(item.accessStatus),
// _buildTableCell(item.passwordStatus.toString()),
// ],
// );
// }).toList(),
// ),
// ],
// ),
// ),
// ),
// ],
// ),
// ),
// ],
// ),
// ),
// );
// }
}
Widget _buildTableHeaderCell(String title) {
return Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border.symmetric(
vertical: BorderSide(color: ColorsManager.boxDivider))),
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(title, style: TextStyle(fontWeight: FontWeight.bold)),
),
),
);
}
Widget _buildTableCell(String content) {
return Expanded(
child: Container(
height: 80,
padding: const EdgeInsets.all(20.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide( // <--- right side
color: ColorsManager.boxDivider,
width: 1.0,
),
)
),
alignment: Alignment.centerLeft,
child: Text(
content,
style: TextStyle(color: Colors.black, fontSize: 12),
),
),
);
}

View File

@ -0,0 +1,103 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class DynamicTable extends StatelessWidget {
final List<String> headers;
final List<List<dynamic>> data;
final BoxDecoration? headerDecoration;
final BoxDecoration? cellDecoration;
final Size size;
const DynamicTable({
Key? key,
required this.headers,
required this.data,
required this.size,
this.headerDecoration,
this.cellDecoration,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Container(
decoration: cellDecoration,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
width:size.width,
child: Column(
children: [
Container(
decoration: headerDecoration ??
BoxDecoration(color: Colors.grey[200]),
child: Row(
children: headers.map((header) =>
_buildTableHeaderCell(header)).toList(),
),
),
Expanded(
child: Container(
color: Colors.white,
child: ListView(
shrinkWrap: true,
children: data.map((row) {
return Row(
children: row.map((cell) =>
_buildTableCell(cell.toString())).toList(),
);
}).toList(),
),
),
),
],
),
),
],
),
),
);
}
}
Widget _buildTableHeaderCell(String title) {
return Expanded(
child: Container(
decoration: const BoxDecoration(
border: Border.symmetric(
vertical: BorderSide(color: ColorsManager.boxDivider))),
alignment: Alignment.centerLeft,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(title, style: TextStyle(fontWeight: FontWeight.bold)),
),
),
);
}
Widget _buildTableCell(String content) {
return Expanded(
child: Container(
height: 80,
padding: const EdgeInsets.all(20.0),
decoration: const BoxDecoration(
border: Border(
bottom: BorderSide( // <--- right side
color: ColorsManager.boxDivider,
width: 1.0,
),
)
),
alignment: Alignment.centerLeft,
child: Text(
content,
style: TextStyle(color: Colors.black, fontSize: 12),
),
),
);
}

View File

@ -29,8 +29,7 @@ class CustomWebTextField extends StatelessWidget {
if(isRequired)
Row(
children: [
Text(
'* ',
Text('* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
@ -39,6 +38,7 @@ class CustomWebTextField extends StatelessWidget {
Text(textFieldName),
],
),
const SizedBox(width: 10,),
Text(
description??'', // ' The password will be sent to the visitors email address.',
style: Theme.of(context)
@ -53,7 +53,17 @@ class CustomWebTextField extends StatelessWidget {
),
const SizedBox(height: 7,),
Container(
decoration: containerDecoration,
height: MediaQuery.of(context).size.height*0.05,
decoration: containerDecoration.copyWith(
color: const Color(0xFFF5F6F7),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius:2,
blurRadius: 3,
offset: Offset(1, 1), // changes position of shadow
), ]
),
child: TextFormField(
controller: controller,
style: const TextStyle(color: Colors.black),

View File

@ -2,6 +2,8 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_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';
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
import 'package:syncrow_web/services/access_mang_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/snack_bar.dart';
@ -9,15 +11,29 @@ import 'package:syncrow_web/utils/snack_bar.dart';
class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
VisitorPasswordBloc() : super(VisitorPasswordInitial()) {
on<SelectUsageFrequency>(selectUsageFrequency);
on<FetchDevice>(_onFetchDevice);
on<SelectPasswordType>(selectAccessType);
on<SelectTimeVisitorPassword>(selectTimeVisitorPassword);
on<ToggleRepeatEvent>(toggleRepeat);
on<ToggleDaySelectionEvent>(toggleDaySelection);
}
final TextEditingController userNameController = TextEditingController();
final TextEditingController emailController = TextEditingController();
final TextEditingController deviceNameController = TextEditingController();
final TextEditingController deviceIdController = TextEditingController();
final TextEditingController unitNameController = TextEditingController();
final TextEditingController virtualAddressController = TextEditingController();
List<DeviceModel> data=[];
String accessTypeSelected='Offline Password';
String usageFrequencySelected='One-Time';
@ -136,6 +152,17 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
}
emit(ChangeTimeState());
}
//Add Accessible Device
Future<void> _onFetchDevice(
FetchDevice event, Emitter<VisitorPasswordState> emit) async {
try {
emit(DeviceLoaded());
data = await AccessMangApi().fetchDevices();
emit(TableLoaded(data));
} catch (e) {
emit(FailedState(e.toString()));
}
}
}

View File

@ -47,3 +47,4 @@ class ToggleDaySelectionEvent extends VisitorPasswordEvent {
class ToggleRepeatEvent extends VisitorPasswordEvent {}
class FetchDevice extends VisitorPasswordEvent {}

View File

@ -1,6 +1,7 @@
import 'package:equatable/equatable.dart';
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
abstract class VisitorPasswordState extends Equatable {
const VisitorPasswordState();
@ -42,3 +43,20 @@ class IsRepeatState extends VisitorPasswordState {
class LoadingInitialState extends VisitorPasswordState {}
class ChangeTimeState extends VisitorPasswordState {}
class DeviceLoaded extends VisitorPasswordState {}
class FailedState extends VisitorPasswordState {
final String message;
FailedState(this.message);
@override
List<Object> get props => [message];
}
class TableLoaded extends VisitorPasswordState {
final List<DeviceModel> data;
const TableLoaded(this.data);
@override
List<Object> get props => [data];
}

View File

@ -0,0 +1,99 @@
class DeviceModel {
dynamic productUuid;
dynamic productType;
dynamic activeTime;
dynamic category;
dynamic categoryName;
dynamic createTime;
dynamic gatewayId;
dynamic icon;
dynamic ip;
dynamic lat;
dynamic localKey;
dynamic lon;
dynamic model;
dynamic name;
dynamic online;
dynamic ownerId;
dynamic sub;
dynamic timeZone;
dynamic updateTime;
dynamic uuid;
DeviceModel({
required this.productUuid,
required this.productType,
required this.activeTime,
required this.category,
required this.categoryName,
required this.createTime,
required this.gatewayId,
required this.icon,
required this.ip,
required this.lat,
required this.localKey,
required this.lon,
required this.model,
required this.name,
required this.online,
required this.ownerId,
required this.sub,
required this.timeZone,
required this.updateTime,
required this.uuid,
});
// Deserialize from JSON
factory DeviceModel.fromJson(Map<String, dynamic> json) {
return DeviceModel(
productUuid: json['productUuid'] ,
productType: json['productType'],
activeTime: json['activeTime'],
category: json['category'] ,
categoryName: json['categoryName'] ,
createTime: json['createTime'] ,
gatewayId: json['gatewayId'],
icon: json['icon'],
ip: json['ip'] ,
lat: json['lat'] ,
localKey: json['localKey'] ,
lon: json['lon'] ,
model: json['model'] ,
name: json['name'],
online: json['online'],
ownerId: json['ownerId'] ,
sub: json['sub'],
timeZone: json['timeZone'],
updateTime: json['updateTime'] ,
uuid: json['uuid'],
);
}
// Serialize to JSON
Map<String, dynamic> toJson() {
return {
'productUuid': productUuid,
'productType': productType,
'activeTime': activeTime,
'category': category,
'categoryName': categoryName,
'createTime': createTime,
'gatewayId': gatewayId,
'icon': icon,
'ip': ip,
'lat': lat,
'localKey': localKey,
'lon': lon,
'model': model,
'name': name,
'online': online,
'ownerId': ownerId,
'sub': sub,
'timeZone': timeZone,
'updateTime': updateTime,
'uuid': uuid,
};
}
}

View File

@ -0,0 +1,210 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/pages/common/custom_web_textfield.dart';
import 'package:syncrow_web/pages/common/default_button.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
import '../../common/custom_table.dart';
class AddDeviceDialog extends StatelessWidget {
const AddDeviceDialog({super.key});
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return BlocProvider(
create: (context) => VisitorPasswordBloc()..add(FetchDevice()),
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
builder: (BuildContext context, VisitorPasswordState state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
return AlertDialog(
backgroundColor: Colors.white,
title: const Text('Add Accessible Device'),
content: Container(
height: MediaQuery.of(context).size.height/1.7,
width: MediaQuery.of(context).size.width/2,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
Container(
width: size.width,
padding: EdgeInsets.all(15),
decoration:containerDecoration.copyWith(
color: ColorsManager.worningColor,
border: Border.all(color: Color(0xffFFD22F)),
boxShadow: []
),
child: Row(
children: [
SizedBox(
child: SvgPicture.asset(
Assets.deviceNoteIcon,
height: 15,
width: 15,
),
),
SizedBox(width: 10,),
Text('Only online accessible devices can be added'),
],
)
),
SizedBox(height: 20,),
Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
flex: 2,
child: CustomWebTextField(
controller: visitorBloc.deviceNameController,
isRequired: true,
textFieldName: 'Device Name',
description: '',
),
),
const SizedBox(width: 10),
Expanded(
flex: 2,
child: CustomWebTextField(
controller: visitorBloc.deviceNameController,
isRequired: true,
textFieldName: 'Device ID',
description: '',
),
),
const SizedBox(width: 10),
Expanded(
flex: 2,
child: CustomWebTextField(
controller: visitorBloc.unitNameController,
isRequired: true,
textFieldName: 'Unit Name',
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: () {
// Your search function here
},
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),
),
),
),
),
),
],
),
],
),
SizedBox(height: 20),
Container(
child: Expanded(
child: state is TableLoaded
? Container(
decoration: containerDecoration,
child: DynamicTable(
size: size*0.5,
headers: ['Device Name', 'Device ID', 'Access Type', 'Unit Name', 'Status'],
data: state.data.map((item) {
return [
item.name.toString(),
item.uuid.toString(),
item.productType.toString(),
'',
item.online.toString(),
// item.categoryName.toString(),
// accessBloc.timestampToDateTime(item.effectiveTime).toString(),
// accessBloc.timestampToDateTime(item.invalidTime).toString(),
// item.deviceUuid.toString(),
// item.passwordCreated != null ? accessBloc.timestampToDateTime(item.passwordCreated).toString() : 'no data',
// item.passwordStatus.toString(),
];
}).toList(),
),
)
// TableWidget(size: size, headers: ['Device Name', 'Device ID', 'Access Type', 'Unit Name', 'Status', 'Virtual Address',], data: [], bloc: bloc)
: const Center(child: CircularProgressIndicator())),
)
],
),
),
),
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.bodyMedium!,
),
),
),
Container(
decoration: containerDecoration,
width: size.width * 0.2,
child: const DefaultButton(
borderRadius: 8,
child: Text('Ok'),
),
),
],
);
},
),
); }
}

View File

@ -7,8 +7,8 @@ import 'package:syncrow_web/pages/common/default_button.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_bloc.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart';
import 'package:syncrow_web/pages/visitor_password/view/add_device_dialog.dart';
import 'package:syncrow_web/pages/visitor_password/view/repeat_widget.dart';
import 'package:syncrow_web/utils/snack_bar.dart';
import 'package:syncrow_web/utils/style.dart';
class VisitorPasswordDialog extends StatelessWidget {
@ -24,216 +24,242 @@ class VisitorPasswordDialog extends StatelessWidget {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
bool isRepeat = state is IsRepeatState ? state.repeat : visitorBloc.repeat;
return AlertDialog(
backgroundColor: Colors.white,
title: const Text('Create visitor password'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Row(
children: [
Expanded(
flex: 2,
child: CustomWebTextField(
controller: visitorBloc.userNameController,
isRequired: true,
textFieldName: 'User Name',
description: '',
),
),
const Spacer(),
Expanded(
flex: 2,
child: CustomWebTextField(
controller: visitorBloc.emailController,
isRequired: true,
textFieldName: 'Email Address',
description: 'The password will be sent to the visitors email address.',
),
),
],
),
SizedBox(height: size.height * 0.02), // Add spacing
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
child: Padding(
padding: const EdgeInsets.all(10.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(
controller: visitorBloc.userNameController,
isRequired: true,
textFieldName: 'Name',
description: '',
),
),
const Text('Access Type'),
const Spacer(),
Expanded(
flex: 2,
child: CustomWebTextField(
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: const Text('Offline Password'),
value: 'Offline Password',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
context.read<VisitorPasswordBloc>().add(SelectPasswordType(value));
}
},
),
SizedBox(height: 20,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
),
SizedBox(
width: size.width * 0.15,
child: RadioListTile<String>(
title: const Text('Online Password'),
value: 'Online Password',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
context.read<VisitorPasswordBloc>().add(SelectPasswordType(value));
}
},
const Text('Access Type'),
],
),
Row(
children: <Widget>[
SizedBox(
width: size.width * 0.15,
child: RadioListTile<String>(
title: const Text('Offline Password'),
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: const Text('Dynamic Password'),
value: 'Dynamic 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: const Text('Online Password'),
value: 'Online Password',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
context.read<VisitorPasswordBloc>().add(SelectPasswordType(value));
}
},
),
),
),
],
),
],
),
visitorBloc.accessTypeSelected=='Dynamic Password' ?
SizedBox():
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
const Text('Usage Frequency'),
],
),
Row(
children: <Widget>[
SizedBox(
width: 200,
child: RadioListTile<String>(
title: const Text('One-Time'),
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: size.width * 0.15,
child: RadioListTile<String>(
title: const Text('Dynamic Password'),
value: 'Dynamic Password',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
context.read<VisitorPasswordBloc>().add(SelectPasswordType(value));
}
},
),
),
),
SizedBox(
width: 200,
child: RadioListTile<String>(
title: const Text('Periodic'),
value: 'Periodic',
groupValue: (state is UsageFrequencySelected)
? state.selectedFrequency
: visitorBloc.usageFrequencySelected,
onChanged: (String? value) {
if (value != null) {
context.read<VisitorPasswordBloc>().add(SelectUsageFrequency(value));
}
},
],
),
const Text('Only currently online devices can be selected. It is recommended to use when the device network is stable, and the system randomly generates a digital password'),
SizedBox(height: 20,)
],
),
visitorBloc.accessTypeSelected=='Dynamic Password' ?
SizedBox():
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
),
],
),
],
),
visitorBloc.accessTypeSelected=='Dynamic Password' ?
SizedBox():
const Text('Usage Frequency'),
],
),
Row(
children: <Widget>[
SizedBox(
width: 200,
child: RadioListTile<String>(
title: const Text('One-Time'),
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: const Text('Periodic'),
value: 'Periodic',
groupValue: (state is UsageFrequencySelected)
? state.selectedFrequency
: visitorBloc.usageFrequencySelected,
onChanged: (String? value) {
if (value != null) {
context.read<VisitorPasswordBloc>().add(SelectUsageFrequency(value));
}
},
),
),
],
),
DateTimeWebWidget(
isRequired: true,
title: 'Access Period',
size: size,
endTime: () {
visitorBloc.add(SelectTimeVisitorPassword(context: context, isStart: false));
},
startTime: () {
visitorBloc.add(SelectTimeVisitorPassword(context: context, isStart: true));
},
firstString: visitorBloc.startTime,
secondString: visitorBloc.endTime,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
const Text('Access Devices'),
],
),
const Text('Within the validity period, each device can be unlocked only once.'),
visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Offline Password'?
SizedBox(
width: 100,
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const Text('Repeat'),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: visitorBloc.repeat,
onChanged: (value) {
visitorBloc.add(ToggleRepeatEvent());
},
applyTheme: true,
Text('Within the validity period, each device can be unlocked only once.')
],
),
const SizedBox(height: 20,),
visitorBloc.accessTypeSelected=='Dynamic Password' ?
SizedBox():
DateTimeWebWidget(
isRequired: true,
title: 'Access Period',
size: size,
endTime: () {
visitorBloc.add(SelectTimeVisitorPassword(context: context, isStart: false));
},
startTime: () {
visitorBloc.add(SelectTimeVisitorPassword(context: context, isStart: true));
},
firstString: visitorBloc.startTime,
secondString: visitorBloc.endTime,
),
const SizedBox(height: 20,),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
const Text('Access Devices'),
],
),
const Text('Within the validity period, each device can be unlocked only once.'),
const SizedBox(height: 20,),
visitorBloc.usageFrequencySelected=='Periodic'&&visitorBloc.accessTypeSelected=='Offline Password'?
SizedBox(
width: 100,
child: ListTile(
contentPadding: EdgeInsets.zero,
leading: const Text('Repeat'),
trailing: Transform.scale(
scale: .8,
child: CupertinoSwitch(
value: visitorBloc.repeat,
onChanged: (value) {
visitorBloc.add(ToggleRepeatEvent());
},
applyTheme: true,
),
),
),
),
):const SizedBox(),
isRepeat ? const RepeatWidget() : const SizedBox(),
Container(
decoration: containerDecoration,
width: size.width * 0.2,
child: const DefaultButton(
borderRadius: 8,
child: Text('+ Add Device'),
),
),
],
),
):const SizedBox(),
isRepeat ? const RepeatWidget() : const SizedBox(),
Container(
decoration: containerDecoration,
width: size.width * 0.1,
child: DefaultButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return const AddDeviceDialog();
],
},
);
},
borderRadius: 8,
child: Text('+ Add Device'),
),
),
],
),
],
),
),
),
actionsAlignment: MainAxisAlignment.center,