visitor password

This commit is contained in:
mohammad
2024-08-14 12:37:41 +03:00
parent 2d0f85bded
commit 6efcc6081d
9 changed files with 380 additions and 188 deletions

View File

@ -1,13 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.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/date_time_widget.dart';
import 'package:syncrow_web/pages/common/default_button.dart';
import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
import 'package:syncrow_web/web_layout/web_scaffold.dart';
@ -122,42 +121,19 @@ class AccessManagementPage extends StatelessWidget {
const SizedBox(
width: 15,
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
const Text('Access Time'),
Container(
width: size.width * 0.25,
padding: EdgeInsets.all(10),
decoration: containerDecoration,
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
accessBloc.add(SelectTime(context: context, isStart: true));
},
child: Text(BlocProvider.of<AccessBloc>(context).startTime)
),
const Icon(Icons.arrow_right_alt),
InkWell(
onTap: () {
accessBloc.add(SelectTime(context: context, isStart: false));
},
child: Text(BlocProvider.of<AccessBloc>(context).endTime)),
SvgPicture.asset(
Assets.calendarIcon,
),
],
),
],
)),
],
),
DateTimeWebWidget(
isRequired: false,
title: 'Access Time',
size: size,
endTime: () {
accessBloc.add(SelectTime(context: context, isStart: false));
},
startTime: () {
accessBloc.add(SelectTime(context: context, isStart: true));
},
firstString:BlocProvider.of<AccessBloc>(context).startTime ,
secondString:BlocProvider.of<AccessBloc>(context).endTime ,
) ,
const SizedBox(
width: 15,
),
@ -334,6 +310,7 @@ class AccessManagementPage extends StatelessWidget {
}
}
Widget _buildTableHeaderCell(String title) {
return Expanded(
child: Container(

View File

@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/style.dart';
class CustomWebTextField extends StatelessWidget {
const CustomWebTextField({
super.key,
required this.isRequired,
required this.textFieldName,
required this.controller,
this.description,
});
final bool isRequired;
final String textFieldName;
final String? description;
final TextEditingController? controller;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if(isRequired)
Row(
children: [
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
Text(textFieldName),
],
),
Text(
description??'', // ' The password will be sent to the visitors email address.',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontSize: 9,
fontWeight: FontWeight.w400,
color: ColorsManager.textGray),
),
],
),
const SizedBox(height: 7,),
Container(
decoration: containerDecoration,
child: TextFormField(
controller: controller,
style: const TextStyle(color: Colors.black),
decoration: textBoxDecoration()!
.copyWith(hintText: 'Please enter'),
),
),
],
);
}
}

View File

@ -0,0 +1,74 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/style.dart';
class DateTimeWebWidget extends StatelessWidget {
const DateTimeWebWidget({
super.key,
required this.size,
required this.isRequired,
required this.title,
required this.startTime,
required this.endTime,
required this.firstString,
required this.secondString,
});
final Size size;
final String title;
final bool isRequired;
final String firstString;
final String secondString;
final Function()? startTime;
final Function()? endTime;
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
if(isRequired)
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
Text(title??''),
],
),
SizedBox(height: 8,),
Container(
width: size.width * 0.25,
padding: EdgeInsets.all(10),
decoration: containerDecoration,
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: startTime,
child: Text(firstString)
),
const Icon(Icons.arrow_right_alt),
InkWell(
onTap:endTime,
child: Text(secondString)),
SvgPicture.asset(
Assets.calendarIcon,
),
],
),
],
)),
],
);
}
}

View File

@ -1,13 +1,108 @@
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/utils/color_manager.dart';
import 'package:syncrow_web/utils/snack_bar.dart';
// Define the BLoC
class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
VisitorPasswordBloc() : super(VisitorPasswordInitial()) {
on<SelectPasswordType>((event, emit) {
// Handle the event and emit the new state
emit(PasswordTypeSelected(event.type));
});
on<SelectUsageFrequency>(selectUsageFrequency);
on<SelectPasswordType>(selectAccessType);
on<SelectTimeVisitorPassword>(selectTimeVisitorPassword);
}
final TextEditingController userNameController = TextEditingController();
final TextEditingController emailController = TextEditingController();
String accessTypeSelected='';
String usageFrequencySelected='';
int? effectiveTimeTimeStamp;
int? expirationTimeTimeStamp;
String startTime = 'Start Time';
String endTime = 'End Time';
selectAccessType(SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
accessTypeSelected=event.type;
print(accessTypeSelected);
emit(PasswordTypeSelected(event.type));
}
selectUsageFrequency(SelectUsageFrequency event, Emitter<VisitorPasswordState> emit) {
usageFrequencySelected=event.usageType;
print(usageFrequencySelected);
emit(UsageFrequencySelected(event.usageType));
}
Future<void> selectTimeVisitorPassword(SelectTimeVisitorPassword event, Emitter<VisitorPasswordState> emit) async {
final DateTime? picked = await showDatePicker(
context: event.context,
initialDate: DateTime.now(),
firstDate: DateTime(2015, 8),
lastDate: DateTime(2101),
);
if (picked != null) {
final TimeOfDay? timePicked = await showTimePicker(
context: event.context,
initialTime: TimeOfDay.now(),
builder: (context, child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: const ColorScheme.light(
primary: ColorsManager.primaryColor,
onSurface: Colors.black,
),
buttonTheme: const ButtonThemeData(
colorScheme: ColorScheme.light(
primary: Colors.green,
),
),
),
child: child!,
);
},
);
if (timePicked != null) {
final selectedDateTime = DateTime(
picked.year,
picked.month,
picked.day,
timePicked.hour,
timePicked.minute,
);
final selectedTimestamp = DateTime(
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).millisecondsSinceEpoch ~/ 1000; // Divide by 1000 to remove milliseconds
if (event.isStart) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
} else {
startTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
} else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.');
} else {
endTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
}
}
}
// emit(AccessInitial());
// emit(TableLoaded(data));
}
}

View File

@ -1,13 +1,8 @@
import 'package:equatable/equatable.dart';
import 'package:flutter/cupertino.dart';
abstract class VisitorPasswordEvent extends Equatable {
const VisitorPasswordEvent(
);
const VisitorPasswordEvent();
@override
List<Object> get props => [];
@ -21,3 +16,21 @@ class SelectPasswordType extends VisitorPasswordEvent {
@override
List<Object> get props => [type];
}
class SelectUsageFrequency extends VisitorPasswordEvent {
final String usageType;
const SelectUsageFrequency(this.usageType);
@override
List<Object> get props => [usageType];
}
class SelectTimeVisitorPassword extends VisitorPasswordEvent {
final BuildContext context;
final bool isStart;
const SelectTimeVisitorPassword({ required this.context,required this.isStart});
@override
List<Object> get props => [context,isStart];
}

View File

@ -16,8 +16,17 @@ class VisitorPasswordInitial extends VisitorPasswordState {}
class PasswordTypeSelected extends VisitorPasswordState {
final String selectedType;
PasswordTypeSelected(this.selectedType);
const PasswordTypeSelected(this.selectedType);
@override
List<Object> get props => [selectedType];
}
class UsageFrequencySelected extends VisitorPasswordState {
final String selectedFrequency;
const UsageFrequencySelected(this.selectedFrequency);
@override
List<Object> get props => [selectedFrequency];
}

View File

@ -1,86 +1,54 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/common/custom_web_textfield.dart';
import 'package:syncrow_web/pages/common/date_time_widget.dart';
import 'package:syncrow_web/pages/common/default_button.dart';
import 'package:syncrow_web/pages/visitor_password/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/style.dart';
class VisitorPasswordDialog extends StatelessWidget {
const VisitorPasswordDialog({super.key});
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return BlocProvider(
create: (context) => VisitorPasswordBloc(),
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
builder: (context, state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
return AlertDialog(
title: const Text('Create visitor password'),
content: SingleChildScrollView(
child: ListBody(
children: <Widget>[
Row(
Row(
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
const Text('User Name'),
],
),
Container(
width: size.width * 0.15,
decoration: containerDecoration,
child: TextFormField(
style: TextStyle(color: Colors.black),
decoration: textBoxDecoration()!
.copyWith(hintText: 'Please enter'),
),
),
],
Expanded(
flex: 2,
child: CustomWebTextField(
controller:visitorBloc.userNameController ,
isRequired: true,
textFieldName: 'User Name',
description: '',
),
),
SizedBox(width: size.width * 0.05), // Add spacing between columns
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
const Text('Email Address'),
],
),
Container(
width: size.width * 0.15,
decoration: containerDecoration,
child: TextFormField(
style: TextStyle(color: Colors.black),
decoration: textBoxDecoration()!
.copyWith(hintText: 'Please enter'),
),
),
],
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,
@ -101,25 +69,22 @@ class VisitorPasswordDialog extends StatelessWidget {
Row(
children: <Widget>[
SizedBox(
width: 200,
width: size.width*0.15,
child: RadioListTile<String>(
title: Text('Offline Password'),
title: const Text('Offline Password'),
value: 'Offline Password',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: 'Offline Password',
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
context.read<VisitorPasswordBloc>().add(SelectPasswordType(value));
}
},
),
),
SizedBox(
width: 200,
width: size.width*0.15,
child: RadioListTile<String>(
title: Text('Online Password'),
value: 'Online Password',
@ -136,10 +101,9 @@ class VisitorPasswordDialog extends StatelessWidget {
),
),
SizedBox(
width: 200,
width: size.width*0.15,
child: RadioListTile<String>(
title: Text('Dynamic Password'),
title: const Text('Dynamic Password'),
value: 'Dynamic Password',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
@ -180,32 +144,29 @@ class VisitorPasswordDialog extends StatelessWidget {
child: RadioListTile<String>(
title: const Text('One-Time'),
value: 'One-Time',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
groupValue: (state is UsageFrequencySelected)
? state.selectedFrequency
: 'One-Time',
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
context.read<VisitorPasswordBloc>()
.add(SelectUsageFrequency(value));
}
},
),
),
SizedBox(
width: 200,
child: RadioListTile<String>(
title: Text('Periodic'),
title: const Text('Periodic'),
value: 'Periodic',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: 'Periodic',
groupValue: (state is UsageFrequencySelected)
? state.selectedFrequency
: 'Periodic1',
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
context.read<VisitorPasswordBloc>()
.add(SelectUsageFrequency(value));
}
},
),
@ -214,73 +175,69 @@ class VisitorPasswordDialog extends StatelessWidget {
)
],
),
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:BlocProvider.of<VisitorPasswordBloc>(context).startTime ,
secondString:BlocProvider.of<VisitorPasswordBloc>(context).endTime ,
) ,
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
const Text('Access Period'),
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
),
const Text('Access Devices'),
],
),
Row(
children: <Widget>[
SizedBox(
width: 200,
child: RadioListTile<String>(
title: const Text('One-Time'),
value: 'One-Time',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: 'One-Time',
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
}
},
),
),
SizedBox(
width: 200,
const Text('Within the validity period, each device can be unlocked only once.'),
Container(
decoration: containerDecoration,
width: size.width*0.2,
child: const DefaultButton(
borderRadius: 8,
child:Text('+ Add Device'),)),
child: RadioListTile<String>(
title: Text('Periodic'),
value: 'Periodic',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: 'Periodic',
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
}
},
),
),
],
)
],
),
)
],
),
),
actionsAlignment: MainAxisAlignment.center,
actions: <Widget>[
TextButton(
child: const Text('Approve'),
onPressed: () {
Navigator.of(context).pop();
},
),
Container(
decoration: containerDecoration,
width: size.width*0.2,
child: DefaultButton(
borderRadius: 8,
onPressed:() {},
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'),)),
],
);
},
@ -288,3 +245,4 @@ class VisitorPasswordDialog extends StatelessWidget {
);
}
}