mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
create visitor password
This commit is contained in:
@ -5,6 +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/services/locator.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
@ -40,6 +41,7 @@ class MyApp extends StatelessWidget {
|
||||
PointerDeviceKind.unknown,
|
||||
},
|
||||
),
|
||||
|
||||
theme: ThemeData(
|
||||
textTheme: const TextTheme(
|
||||
bodySmall: TextStyle(fontSize: 13, color: ColorsManager.whiteColors, fontWeight: FontWeight.bold),
|
||||
@ -53,10 +55,11 @@ class MyApp extends StatelessWidget {
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
|
||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), // Set up color scheme
|
||||
useMaterial3: true, // Enable Material 3
|
||||
),
|
||||
// home: VisitorPasswordDialog()
|
||||
// home: AddDeviceDialog()
|
||||
home:isLoggedIn == 'Success' ? const HomePage() : const LoginPage(),
|
||||
));
|
||||
}
|
||||
|
@ -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')}";
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -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'],
|
||||
);
|
||||
}
|
||||
|
@ -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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
103
lib/pages/common/custom_table.dart
Normal file
103
lib/pages/common/custom_table.dart
Normal 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),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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 visitor’s 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),
|
||||
|
@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -47,3 +47,4 @@ class ToggleDaySelectionEvent extends VisitorPasswordEvent {
|
||||
|
||||
|
||||
class ToggleRepeatEvent extends VisitorPasswordEvent {}
|
||||
class FetchDevice extends VisitorPasswordEvent {}
|
||||
|
@ -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];
|
||||
}
|
99
lib/pages/visitor_password/model/device_model.dart
Normal file
99
lib/pages/visitor_password/model/device_model.dart
Normal 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,
|
||||
};
|
||||
}
|
||||
}
|
210
lib/pages/visitor_password/view/add_device_dialog.dart
Normal file
210
lib/pages/visitor_password/view/add_device_dialog.dart
Normal 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'),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
); }
|
||||
}
|
@ -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 visitor’s 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 visitor’s 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,
|
||||
|
@ -6,6 +6,8 @@ import 'package:syncrow_web/pages/access_management/model/password_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{
|
||||
|
||||
|
||||
@ -31,6 +33,27 @@ class AccessMangApi{
|
||||
}
|
||||
}
|
||||
|
||||
Future fetchDevices() async {
|
||||
try {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.getDevices,
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
List<dynamic> jsonData = json;
|
||||
print('fetchDevices List: $json');
|
||||
List<DeviceModel> passwordList = jsonData.map((jsonItem) {
|
||||
return DeviceModel.fromJson(jsonItem);
|
||||
}).toList();
|
||||
return passwordList;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
} catch (e) {
|
||||
debugPrint('Error fetching $e');
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -46,8 +46,10 @@ class AuthenticationAPI {
|
||||
},
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
print('object==$json');
|
||||
return 30;
|
||||
}
|
||||
|
||||
);
|
||||
return 30;
|
||||
} on DioException catch (e) {
|
||||
|
@ -18,6 +18,7 @@ abstract class ColorsManager {
|
||||
static const Color dozeColor = Color(0xFFFEC258);
|
||||
static const Color relaxColor = Color(0xFFFBD288);
|
||||
static const Color readingColor = Color(0xFFF7D69C);
|
||||
static const Color worningColor = Color(0xFFFFF3C8);
|
||||
static const Color energizingColor = Color(0xFFEDEDED);
|
||||
static const Color dividerColor = Color(0xFFEBEBEB);
|
||||
static const Color slidingBlueColor = Color(0x99023DFE);
|
||||
|
@ -10,5 +10,6 @@ abstract class ApiEndpoints {
|
||||
static const String verifyOtp = '$baseUrl/authentication/user/verify-otp';
|
||||
static const String getRegion = '$baseUrl/region';
|
||||
static const String visitorPassword = '$baseUrl/visitor-password';
|
||||
static const String getDevices = '$baseUrl/visitor-password/devices';
|
||||
static const String getUser = '$baseUrl/user/{userUuid}';
|
||||
}
|
||||
|
@ -24,4 +24,5 @@ class Assets {
|
||||
static const String integrationsIcon = "assets/images/Integrations_icon.svg";
|
||||
static const String assetIcon = "assets/images/asset_icon.svg";
|
||||
static const String calendarIcon = "assets/images/calendar_icon.svg";
|
||||
static const String deviceNoteIcon = "assets/images/device_note.svg";
|
||||
}
|
||||
|
44
lib/utils/constants/const.dart
Normal file
44
lib/utils/constants/const.dart
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
|
||||
|
||||
enum AccessType {
|
||||
onlineOnetime,
|
||||
onlineMultiple,
|
||||
offlineOnetime,
|
||||
offlineMultiple,
|
||||
}
|
||||
|
||||
extension AccessTypeExtension on AccessType {
|
||||
String get value {
|
||||
switch (this) {
|
||||
case AccessType.onlineOnetime:
|
||||
return "Online Password";
|
||||
case AccessType.onlineMultiple:
|
||||
return "online Multiple Password";
|
||||
case AccessType.offlineOnetime:
|
||||
return "Offline Onetime Password";
|
||||
case AccessType.offlineMultiple:
|
||||
return "Offline Multiple Password";
|
||||
}
|
||||
}
|
||||
|
||||
static AccessType fromString(String value) {
|
||||
switch (value) {
|
||||
case "ONLINE_ONETIME":
|
||||
return AccessType.onlineOnetime;
|
||||
case "ONLINE_MULTIPLE":
|
||||
return AccessType.onlineMultiple;
|
||||
case "OFFLINE_ONETIME":
|
||||
return AccessType.offlineOnetime;
|
||||
case "OFFLINE_MULTIPLE":
|
||||
return AccessType.offlineMultiple;
|
||||
default:
|
||||
throw ArgumentError("Invalid access type: $value");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,5 +0,0 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,7 +6,7 @@ InputDecoration? textBoxDecoration({bool suffixIcon = false}) => InputDecoration
|
||||
suffixIcon:suffixIcon? const Icon(Icons.search):null,
|
||||
hintText: 'Search',
|
||||
filled: true, // Enable background filling
|
||||
fillColor: Colors.grey.shade200, // Set the background color
|
||||
fillColor: const Color(0xffF5F6F7), // Set the background color
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(8), // Add border radius
|
||||
borderSide: BorderSide.none, // Remove the underline
|
||||
@ -30,16 +30,17 @@ InputDecoration? textBoxDecoration({bool suffixIcon = false}) => InputDecoration
|
||||
);
|
||||
|
||||
|
||||
|
||||
Decoration containerDecoration = BoxDecoration(
|
||||
BoxDecoration containerDecoration = BoxDecoration(
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Colors.grey.withOpacity(0.5),
|
||||
spreadRadius: 5,
|
||||
blurRadius: 8,
|
||||
offset: Offset(0,
|
||||
offset: const Offset(0,
|
||||
3), // changes position of shadow
|
||||
),
|
||||
],
|
||||
color: ColorsManager.boxColor,
|
||||
borderRadius: BorderRadius.all(Radius.circular(10)));
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)));
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user