Merge pull request #9 from SyncrowIOT/fix_bugs

Fix bugs and login Enhancements
This commit is contained in:
Abdullah
2024-09-03 12:20:54 +03:00
committed by GitHub
17 changed files with 539 additions and 451 deletions

View File

@ -107,26 +107,28 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async {
emit(AccessLoaded());
try {
// Convert search text to lower case for case-insensitive search
final searchText = event.passwordName?.toLowerCase() ?? '';
filteredData = data.where((item) {
bool matchesCriteria = true;
// Convert timestamp to DateTime and extract date component
DateTime effectiveDate =
DateTime.fromMillisecondsSinceEpoch(int.parse(item.effectiveTime.toString()) * 1000)
.toUtc()
.toLocal();
DateTime.fromMillisecondsSinceEpoch(int.parse(item.effectiveTime.toString()) * 1000)
.toUtc()
.toLocal();
DateTime invalidDate =
DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000)
.toUtc()
.toLocal();
DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000)
.toUtc()
.toLocal();
DateTime effectiveDateOnly =
DateTime(effectiveDate.year, effectiveDate.month, effectiveDate.day);
DateTime(effectiveDate.year, effectiveDate.month, effectiveDate.day);
DateTime invalidDateOnly = DateTime(invalidDate.year, invalidDate.month, invalidDate.day);
// Filter by password name
if (event.passwordName != null && event.passwordName!.isNotEmpty) {
final bool matchesName =
item.passwordName != null && item.passwordName.contains(event.passwordName);
// Filter by password name, making the search case-insensitive
if (searchText.isNotEmpty) {
final bool matchesName = item.passwordName.toString().toLowerCase().contains(searchText);
if (!matchesName) {
matchesCriteria = false;
}
@ -135,7 +137,7 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
// Filter by start date only
if (event.startTime != null && event.endTime == null) {
DateTime startDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day);
if (effectiveDateOnly.isBefore(startDateOnly)) {
matchesCriteria = false;
@ -145,7 +147,7 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
// Filter by end date only
if (event.endTime != null && event.startTime == null) {
DateTime endDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day);
if (invalidDateOnly.isAfter(endDateOnly)) {
matchesCriteria = false;
@ -155,9 +157,9 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
// Filter by both start date and end date
if (event.startTime != null && event.endTime != null) {
DateTime startDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
DateTime endDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day);
endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day);
if (effectiveDateOnly.isBefore(startDateOnly) || invalidDateOnly.isAfter(endDateOnly)) {
@ -183,6 +185,8 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
}
}
resetSearch(ResetSearch event, Emitter<AccessState> emit) async {
emit(AccessLoaded());
startTime = 'Start Time';

View File

@ -30,7 +30,7 @@ class PasswordModel {
effectiveTime: json['effectiveTime'],
passwordCreated: json['passwordCreated'],
createdTime: json['createdTime'],
passwordName: json['passwordName'] ?? 'No name', // New field
passwordName: json['passwordName']??'No Name',
passwordStatus: AccessStatusExtension.fromString(json['passwordStatus']),
passwordType: AccessTypeExtension.fromString(json['passwordType']),
deviceUuid: json['deviceUuid'],

View File

@ -27,8 +27,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
final isLargeScreen = isLargeScreenSize(context);
final isSmallScreen = isSmallScreenSize(context);
final isHalfMediumScreen = isHafMediumScreenSize(context);
final padding =
isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
final padding = isLargeScreen ? const EdgeInsets.all(30) : const EdgeInsets.all(15);
return WebScaffold(
enableMenuSideba: false,
@ -38,17 +37,23 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
style: Theme.of(context).textTheme.headlineLarge,
),
),
centerBody: Text(
'Physical Access',
style: Theme.of(context)
.textTheme
.headlineMedium!
.copyWith(color: Colors.white),
centerBody: Wrap(
children: [
Padding(
padding: EdgeInsets.only(left: MediaQuery.of(context).size.width * 0.09),
child: Align(
alignment: Alignment.bottomLeft,
child: Text(
'Physical Access',
style: Theme.of(context).textTheme.headlineMedium!.copyWith(color: Colors.white),
),
),
),
],
),
rightBody: const NavigateHomeGridView(),
scaffoldBody: BlocProvider(
create: (BuildContext context) =>
AccessBloc()..add(FetchTableData()),
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
child: BlocConsumer<AccessBloc, AccessState>(
listener: (context, state) {},
builder: (context, state) {
@ -83,6 +88,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
Expanded(
child: DynamicTable(
uuidIndex: 1,
withSelectAll: true,
isEmpty: filteredData.isEmpty,
withCheckBox: false,
size: MediaQuery.of(context).size,
@ -98,7 +104,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
],
data: filteredData.map((item) {
return [
item.passwordName.toString(),
item.passwordName,
item.passwordType.value,
('${accessBloc.timestampToDate(item.effectiveTime)} - ${accessBloc.timestampToDate(item.invalidTime)}'),
item.deviceUuid.toString(),
@ -114,8 +120,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
})));
}
Wrap _buildVisitorAdminPasswords(
BuildContext context, AccessBloc accessBloc) {
Wrap _buildVisitorAdminPasswords(BuildContext context, AccessBloc accessBloc) {
return Wrap(
spacing: 10,
runSpacing: 10,
@ -141,8 +146,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
borderRadius: 8,
child: Text(
'+ Create Visitor Password ',
style: context.textTheme.titleSmall!
.copyWith(color: Colors.white, fontSize: 12),
style: context.textTheme.titleSmall!.copyWith(color: Colors.white, fontSize: 12),
)),
),
Container(
@ -154,8 +158,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
backgroundColor: ColorsManager.whiteColors,
child: Text(
'Admin Password',
style: context.textTheme.titleSmall!
.copyWith(color: Colors.black, fontSize: 12),
style: context.textTheme.titleSmall!.copyWith(color: Colors.black, fontSize: 12),
)),
),
],
@ -172,15 +175,14 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
width: 250,
child: CustomWebTextField(
controller: accessBloc.passwordName,
height: 38,
isRequired: true,
height: 43,
isRequired: false,
textFieldName: 'Name',
description: '',
),
),
const SizedBox(width: 15),
SizedBox(
height: 70,
child: DateTimeWebWidget(
icon: Assets.calendarIcon,
isRequired: false,
@ -200,8 +202,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
SearchResetButtons(
onSearch: () {
accessBloc.add(FilterDataEvent(
selectedTabIndex:
BlocProvider.of<AccessBloc>(context).selectedIndex,
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));
@ -246,8 +247,7 @@ class AccessManagementPage extends StatelessWidget with HelperResponsiveLayout {
SearchResetButtons(
onSearch: () {
accessBloc.add(FilterDataEvent(
selectedTabIndex:
BlocProvider.of<AccessBloc>(context).selectedIndex,
selectedTabIndex: BlocProvider.of<AccessBloc>(context).selectedIndex,
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));

View File

@ -1,4 +1,5 @@
import 'dart:async';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
@ -81,21 +82,25 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
_timer?.cancel();
emit(const TimerState(isButtonEnabled: true, remainingTime: 0));
emit(SuccessForgetState());
} else if (response == "You entered wrong otp") {
forgetValidate = 'Wrong one time password.';
emit(AuthInitialState());
} else if (response == "OTP expired") {
forgetValidate = 'One time password has been expired.';
emit(AuthInitialState());
}
} catch (failure) {
// forgetValidate='Invalid Credentials!';
emit(AuthInitialState());
// emit(FailureForgetState(error: failure.toString()));
}
on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
if(errorMessage=='this email is not registered'){
validate='Invalid Credentials!';
emit(AuthInitialState());
}else if (errorMessage == "You entered wrong otp") {
forgetValidate = 'Wrong one time password.';
emit(AuthInitialState());
} else if (errorMessage == "OTP expired") {
forgetValidate = 'One time password has been expired.';
emit(AuthInitialState());
}
}
}
//925207
String? validateCode(String? value) {
if (value == null || value.isEmpty) {
return 'Code is required';
@ -178,15 +183,15 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
emit(LoginInitial());
}
checkOtpCode(
ChangePasswordEvent event,
Emitter<AuthState> emit,
) async {
emit(LoadingForgetState());
await AuthenticationAPI.verifyOtp(
email: forgetEmailController.text, otpCode: forgetOtp.text);
emit(SuccessForgetState());
}
// checkOtpCode(
// ChangePasswordEvent event,
// Emitter<AuthState> emit,
// ) async {
// emit(LoadingForgetState());
// await AuthenticationAPI.verifyOtp(
// email: forgetEmailController.text, otpCode: forgetOtp.text);
// emit(SuccessForgetState());
// }
void _passwordVisible(PasswordVisibleEvent event, Emitter<AuthState> emit) {
emit(AuthLoading());

View File

@ -49,9 +49,13 @@ class UpdateTimerEvent extends AuthEvent {
const UpdateTimerEvent({required this.remainingTime, required this.isButtonEnabled});
}
class ChangePasswordEvent extends AuthEvent {}
class ChangePasswordEvent extends AuthEvent {
class SendOtpEvent extends AuthEvent {}
}
class SendOtpEvent extends AuthEvent {
}
class PasswordVisibleEvent extends AuthEvent {
final bool? newValue;

View File

@ -1,3 +1,4 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
@ -148,44 +149,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
),
const SizedBox(height: 10),
SizedBox(
child: DropdownButtonFormField<String>(
validator: forgetBloc.validateRegion,
icon: const Icon(
Icons.keyboard_arrow_down_outlined,
),
decoration:
textBoxDecoration()!.copyWith(
hintText: null,
),
hint: SizedBox(
width: size.width * 0.12,
child: const Align(
alignment: Alignment.centerLeft,
child: Text(
'Select your region/country',
textAlign: TextAlign.center,
overflow: TextOverflow.ellipsis,
),
),
),
isDense: true,
style: const TextStyle(
color: Colors.black),
items: forgetBloc.regionList!
.map((RegionModel region) {
return DropdownMenuItem<String>(
value: region.id,
child: SizedBox(
width: size.width * 0.06,
child: Text(region.name)),
);
}).toList(),
onChanged: (String? value) {
forgetBloc.add(SelectRegionEvent(
val: value!,
));
},
),
child: _buildDropdownField(context, forgetBloc, size)
)
],
),
@ -208,11 +172,12 @@ class ForgetPasswordWebPage extends StatelessWidget {
SizedBox(
child: TextFormField(
validator: forgetBloc.validateEmail,
controller:
forgetBloc.forgetEmailController,
decoration: textBoxDecoration()!
.copyWith(
hintText: 'Enter your email'),
hintText: 'Enter your email',
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.w400)),
style: const TextStyle(
color: Colors.black),
),
@ -244,13 +209,15 @@ class ForgetPasswordWebPage extends StatelessWidget {
decoration:
textBoxDecoration()!.copyWith(
hintText: 'Enter Code',
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.w400),
suffixIcon: SizedBox(
width: 100,
child: Center(
child: InkWell(
onTap: state is TimerState &&
!state
.isButtonEnabled &&
!state.isButtonEnabled &&
state.remainingTime !=
1
? null
@ -261,10 +228,8 @@ class ForgetPasswordWebPage extends StatelessWidget {
child: Text(
'Get Code ${state is TimerState && !state.isButtonEnabled && state.remainingTime != 1 ? "(${forgetBloc.formattedTime(state.remainingTime)}) " : ""}',
style: TextStyle(
color: state
is TimerState &&
!state
.isButtonEnabled
color: state is TimerState &&
!state.isButtonEnabled
? Colors.grey
: ColorsManager
.btnColor,
@ -278,8 +243,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
color: Colors.black),
),
),
if (forgetBloc.forgetValidate !=
'') // Check if there is a validation message
if (forgetBloc.forgetValidate != '') // Check if there is a validation message
Padding(
padding:
const EdgeInsets.only(top: 8.0),
@ -311,18 +275,16 @@ class ForgetPasswordWebPage extends StatelessWidget {
const SizedBox(height: 10),
SizedBox(
child: TextFormField(
validator:
forgetBloc.passwordValidator,
keyboardType:
TextInputType.visiblePassword,
controller: forgetBloc
.forgetPasswordController,
decoration:
textBoxDecoration()!.copyWith(
validator: forgetBloc.passwordValidator,
keyboardType: TextInputType.visiblePassword,
controller: forgetBloc.forgetPasswordController,
decoration: textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters',
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.w400),
),
style: const TextStyle(
color: Colors.black),
style: const TextStyle(color: Colors.black),
),
),
],
@ -346,8 +308,7 @@ class ForgetPasswordWebPage extends StatelessWidget {
if (forgetBloc
.forgetFormKey.currentState!
.validate()) {
forgetBloc
.add(ChangePasswordEvent());
forgetBloc.add(ChangePasswordEvent());
}
},
),
@ -355,12 +316,14 @@ class ForgetPasswordWebPage extends StatelessWidget {
],
),
const SizedBox(height: 10.0),
SizedBox(
child: Text(
forgetBloc.validate,
style: const TextStyle(
fontWeight: FontWeight.w700,
color: ColorsManager.red),
Center(
child: SizedBox(
child: Text(
forgetBloc.validate,
style: const TextStyle(
fontWeight: FontWeight.w700,
color: ColorsManager.red),
),
),
),
SizedBox(
@ -410,4 +373,109 @@ class ForgetPasswordWebPage extends StatelessWidget {
),
));
}
Widget _buildDropdownField(
BuildContext context, AuthBloc loginBloc, Size size) {
final TextEditingController textEditingController = TextEditingController();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Country/Region",
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
const SizedBox(height: 10),
Container(
height: 50,
decoration: const BoxDecoration(
color: ColorsManager.boxColor,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
width: size.width * 0.9,
child: DropdownButtonHideUnderline(
child: DropdownButton2<String>(
style: TextStyle(color: Colors.black),
isExpanded: true,
hint: Text(
'Select your region/country',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.w400,
),
overflow: TextOverflow.ellipsis,
),
items: loginBloc.regionList!.map((RegionModel region) {
return DropdownMenuItem<String>(
value: region.id, // Use region.id as the value
child: Text(
region.name,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
);
}).toList(),
value: loginBloc.regionList!.any(
(region) => region.id == loginBloc.regionUuid,)
? loginBloc.regionUuid
: null,
onChanged: (String? value) {
if (value != null) {
loginBloc.add(SelectRegionEvent(
val: value,
));
}
},
buttonStyleData: const ButtonStyleData(
padding: EdgeInsets.symmetric(horizontal: 16),
height: 40,
width: double.infinity,
),
dropdownStyleData: DropdownStyleData(
maxHeight: size.height * 0.70,
),
menuItemStyleData: const MenuItemStyleData(
height: 40,
),
dropdownSearchData: DropdownSearchData(
searchController: textEditingController,
searchInnerWidgetHeight: 50,
searchInnerWidget: Container(
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: TextFormField(
style: const TextStyle(color: Colors.black),
controller: textEditingController,
decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(height: 0),
contentPadding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 10,
),
),
),
),
searchMatchFn: (item, searchValue) {
// Use the item's child text (region name) for searching.
final regionName = (item.child as Text).data?.toLowerCase() ?? '';
final search = searchValue.toLowerCase().trim();
// Debugging print statement to ensure values are captured correctly.
// Return true if the region name contains the search term.
return regionName.contains(search);
},
),
onMenuStateChange: (isOpen) {
if (!isOpen) {
textEditingController.clear();
}
},
),
),
),
],
);
}
}

View File

@ -1,3 +1,4 @@
import 'package:dropdown_button2/dropdown_button2.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -23,7 +24,8 @@ class LoginWebPage extends StatefulWidget {
State<LoginWebPage> createState() => _LoginWebPageState();
}
class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout {
class _LoginWebPageState extends State<LoginWebPage>
with HelperResponsiveLayout {
@override
Widget build(BuildContext context) {
return Scaffold(
@ -58,7 +60,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
_scrollController = ScrollController();
void _scrollToCenter() {
final double middlePosition = _scrollController.position.maxScrollExtent / 2;
final double middlePosition =
_scrollController.position.maxScrollExtent / 2;
_scrollController.animateTo(
middlePosition,
duration: const Duration(seconds: 1),
@ -120,7 +123,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
const Spacer(),
Expanded(
flex: 2,
child: _buildLoginFormFields(context, loginBloc, size),
child: _buildLoginFormFields(
context, loginBloc, size),
),
const Spacer(),
],
@ -131,12 +135,14 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
),
),
),
if (state is AuthLoading) const Center(child: CircularProgressIndicator())
if (state is AuthLoading)
const Center(child: CircularProgressIndicator())
],
);
}
Widget _buildLoginFormFields(BuildContext context, AuthBloc loginBloc, Size size) {
Widget _buildLoginFormFields(
BuildContext context, AuthBloc loginBloc, Size size) {
return Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1),
@ -146,8 +152,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
child: Form(
key: loginBloc.loginFormKey,
child: Padding(
padding:
EdgeInsets.symmetric(horizontal: size.width * 0.02, vertical: size.width * 0.003),
padding: EdgeInsets.symmetric(
horizontal: size.width * 0.02, vertical: size.width * 0.003),
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
@ -175,88 +181,112 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
);
}
Widget _buildDropdownField(BuildContext context, AuthBloc loginBloc, Size size) {
Widget _buildDropdownField(
BuildContext context, AuthBloc loginBloc, Size size) {
final TextEditingController textEditingController = TextEditingController();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Country/Region",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(fontSize: 14, fontWeight: FontWeight.w400),
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontSize: 14,
fontWeight: FontWeight.w400,
),
),
const SizedBox(height: 10),
SizedBox(
width: size.width * 0.8,
child: LayoutBuilder(
builder: (context, constraints) {
return DropdownButtonFormField<String>(
value: loginBloc.regionList!.any((region) => region.id == loginBloc.regionUuid)
? loginBloc.regionUuid
: null,
validator: loginBloc.validateRegion,
icon: const Icon(
Icons.keyboard_arrow_down_outlined,
size: 20,
Container(
height: 50,
decoration: const BoxDecoration(
color: ColorsManager.boxColor,
borderRadius: BorderRadius.all(Radius.circular(8)),
),
width: size.width * 0.9,
child: DropdownButtonHideUnderline(
child: DropdownButton2<String>(
style: TextStyle(color: Colors.black),
isExpanded: true,
hint: Text(
'Select your region/country',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.w400,
),
decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(height: 0),
contentPadding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 10,
overflow: TextOverflow.ellipsis,
),
items: loginBloc.regionList!.map((RegionModel region) {
return DropdownMenuItem<String>(
value: region.id, // Use region.id as the value
child: Text(
region.name,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
hint: Text(
'Select your region/country',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400),
overflow: TextOverflow.ellipsis,
),
isDense: true,
style: const TextStyle(color: Colors.black),
items: loginBloc.regionList!.map((RegionModel region) {
return DropdownMenuItem<String>(
value: region.id,
child: Container(
constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40),
child: Text(
region.name,
overflow: TextOverflow.ellipsis,
maxLines: 1,
);
}).toList(),
value: loginBloc.regionList!.any(
(region) => region.id == loginBloc.regionUuid,)
? loginBloc.regionUuid
: null,
onChanged: (String? value) {
if (value != null) {
loginBloc.add(CheckEnableEvent());
loginBloc.add(SelectRegionEvent(val: value));
}
},
buttonStyleData: const ButtonStyleData(
padding: EdgeInsets.symmetric(horizontal: 16),
height: 40,
width: double.infinity,
),
dropdownStyleData: DropdownStyleData(
maxHeight: size.height * 0.70,
),
menuItemStyleData: const MenuItemStyleData(
height: 40,
),
dropdownSearchData: DropdownSearchData(
searchController: textEditingController,
searchInnerWidgetHeight: 50,
searchInnerWidget: Container(
height: 50,
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: TextFormField(
style: const TextStyle(color: Colors.black),
controller: textEditingController,
decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(height: 0),
contentPadding: const EdgeInsets.symmetric(
vertical: 12,
horizontal: 10,
),
),
);
}).toList(),
onChanged: (String? value) {
loginBloc.add(CheckEnableEvent());
loginBloc.add(SelectRegionEvent(val: value!));
),
),
searchMatchFn: (item, searchValue) {
// Use the item's child text (region name) for searching.
final regionName = (item.child as Text).data?.toLowerCase() ?? '';
final search = searchValue.toLowerCase().trim();
// Debugging print statement to ensure values are captured correctly.
// Return true if the region name contains the search term.
return regionName.contains(search);
},
dropdownColor: Colors.white,
menuMaxHeight: size.height * 0.45,
selectedItemBuilder: (context) {
return loginBloc.regionList!.map<Widget>((region) {
return Container(
constraints: BoxConstraints(maxWidth: constraints.maxWidth - 40),
child: Text(
region.name,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
);
}).toList();
},
);
},
),
onMenuStateChange: (isOpen) {
if (!isOpen) {
textEditingController.clear();
}
},
),
),
),
],
);
}
Widget _buildEmailField(BuildContext context, AuthBloc loginBloc) {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
@ -280,10 +310,9 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(height: 0),
hintText: 'Enter your email address',
hintStyle: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400)),
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.w400)),
style: const TextStyle(color: Colors.black),
),
),
@ -315,17 +344,18 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
controller: loginBloc.loginPasswordController,
decoration: textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters',
hintStyle: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: ColorsManager.grayColor, fontWeight: FontWeight.w400),
hintStyle: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, fontWeight: FontWeight.w400),
suffixIcon: IconButton(
onPressed: () {
loginBloc.add(PasswordVisibleEvent(newValue: loginBloc.obscureText));
loginBloc.add(
PasswordVisibleEvent(newValue: loginBloc.obscureText));
},
icon: SizedBox(
child: SvgPicture.asset(
loginBloc.obscureText ? Assets.visiblePassword : Assets.invisiblePassword,
loginBloc.obscureText
? Assets.visiblePassword
: Assets.invisiblePassword,
height: 15,
width: 15,
),
@ -353,10 +383,10 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
},
child: Text(
"Forgot Password?",
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black, fontSize: 14, fontWeight: FontWeight.w400),
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w400),
),
),
],
@ -419,7 +449,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
);
}
Widget _buildSignInButton(BuildContext context, AuthBloc loginBloc, Size size) {
Widget _buildSignInButton(
BuildContext context, AuthBloc loginBloc, Size size) {
return Row(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
@ -460,7 +491,8 @@ class _LoginWebPageState extends State<LoginWebPage> with HelperResponsiveLayout
SizedBox(
child: Text(
loginBloc.validate,
style: const TextStyle(fontWeight: FontWeight.w700, color: ColorsManager.red),
style: const TextStyle(
fontWeight: FontWeight.w700, color: ColorsManager.red),
),
)
],

View File

@ -5,11 +5,13 @@ import 'package:syncrow_web/utils/constants/assets.dart';
class DynamicTable extends StatefulWidget {
final List<String> headers;
final String? tableName;
final List<List<dynamic>> data;
final BoxDecoration? headerDecoration;
final BoxDecoration? cellDecoration;
final Size size;
final bool withCheckBox;
final bool withSelectAll;
final bool isEmpty;
final void Function(bool?)? selectAll;
final void Function(int, bool, dynamic)? onRowSelected;
@ -20,8 +22,10 @@ class DynamicTable extends StatefulWidget {
required this.headers,
required this.data,
required this.size,
this.tableName,
required this.isEmpty,
required this.withCheckBox,
required this.withSelectAll,
this.headerDecoration,
this.cellDecoration,
this.selectAll,
@ -36,6 +40,7 @@ class DynamicTable extends StatefulWidget {
class _DynamicTableState extends State<DynamicTable> {
late List<bool> _selected;
bool _selectAll = false;
@override
void initState() {
@ -71,6 +76,17 @@ class _DynamicTableState extends State<DynamicTable> {
});
}
void _toggleSelectAll(bool? value) {
setState(() {
_selectAll = value ?? false;
_selected = List<bool>.filled(widget.data.length, _selectAll);
if (widget.selectAll != null) {
widget.selectAll!(_selectAll);
}
});
}
@override
Widget build(BuildContext context) {
return Container(
@ -108,7 +124,8 @@ class _DynamicTableState extends State<DynamicTable> {
height: 15,
),
Text(
'No Devices',
// no password
widget.tableName=='AccessManagement'? 'No Password ' : 'No Devices',
style: Theme.of(context)
.textTheme
.bodySmall!
@ -162,7 +179,7 @@ class _DynamicTableState extends State<DynamicTable> {
),
child: Checkbox(
value: _selected.every((element) => element == true),
onChanged: null,
onChanged:widget.withSelectAll?_toggleSelectAll:null,
),
);
}

View File

@ -32,21 +32,19 @@ class CustomWebTextField extends StatelessWidget {
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
if (isRequired)
Row(
children: [
Text(
'* ',
if (isRequired)
Text('* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.textTheme.bodyMedium!
.copyWith(color: Colors.red),
),
Text(
textFieldName,
style: Theme.of(context)
.textTheme
.bodySmall!
.textTheme.bodySmall!
.copyWith(color: Colors.black, fontSize: 13),
),
],
@ -70,15 +68,17 @@ class CustomWebTextField extends StatelessWidget {
),
Container(
height: height ?? 35,
decoration: containerDecoration
.copyWith(color: const Color(0xFFF5F6F7), boxShadow: [
decoration: containerDecoration.copyWith(
color: const Color(0xFFF5F6F7),
boxShadow: [
BoxShadow(
color: Colors.grey.withOpacity(0.3),
spreadRadius: 2,
blurRadius: 3,
offset: const Offset(1, 1), // changes position of shadow
),
]),
]
),
child: TextFormField(
validator: validator,
controller: controller,

View File

@ -55,71 +55,68 @@ class DeviceManagementBody extends StatelessWidget with HelperResponsiveLayout {
'Low Battery ($lowBatteryCount)',
];
return CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Container(
padding: isLargeScreenSize(context)
? const EdgeInsets.all(30)
: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FilterWidget(
size: MediaQuery.of(context).size,
tabs: tabs,
selectedIndex: selectedIndex,
onTabChanged: (index) {
context
.read<DeviceManagementBloc>()
.add(SelectedFilterChanged(index));
},
),
const SizedBox(height: 20),
const DeviceSearchFilters(),
const SizedBox(height: 12),
Container(
height: 45,
width: 100,
decoration: containerDecoration,
child: Center(
child: DefaultButton(
onPressed: isControlButtonEnabled
? () {
final selectedDevice = context
.read<DeviceManagementBloc>()
.selectedDevices
.first;
showDialog(
context: context,
builder: (context) => DeviceControlDialog(
device: selectedDevice),
);
}
: null,
borderRadius: 9,
child: Text(
'Control',
style: TextStyle(
fontSize: 12,
color: isControlButtonEnabled
? Colors.white
: Colors.grey,
),
return Column(
children: [
Container(
padding: isLargeScreenSize(context)
? const EdgeInsets.all(30)
: const EdgeInsets.all(15),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FilterWidget(
size: MediaQuery.of(context).size,
tabs: tabs,
selectedIndex: selectedIndex,
onTabChanged: (index) {
context.read<DeviceManagementBloc>()
.add(SelectedFilterChanged(index));
},
),
const SizedBox(height: 20),
const DeviceSearchFilters(),
const SizedBox(height: 12),
Container(
height: 45,
width: 100,
decoration: containerDecoration,
child: Center(
child: DefaultButton(
onPressed: isControlButtonEnabled
? () {
final selectedDevice = context
.read<DeviceManagementBloc>()
.selectedDevices.first;
showDialog(
context: context,
builder: (context) => DeviceControlDialog(
device: selectedDevice),
);
}
: null,
borderRadius: 9,
child: Text(
'Control',
style: TextStyle(
fontSize: 12,
color: isControlButtonEnabled
? Colors.white
: Colors.grey,
),
),
),
),
],
),
),
],
),
),
SliverFillRemaining(
Expanded(
child: Padding(
padding: isLargeScreenSize(context)
? const EdgeInsets.all(30)
: const EdgeInsets.all(15),
child: DynamicTable(
withSelectAll: false,
cellDecoration: containerDecoration,
onRowSelected: (index, isSelected, row) {
final selectedDevice = devicesToShow[index];

View File

@ -219,8 +219,8 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
scheduleList: [
if (repeat)
Schedule(
effectiveTime: getTimeFromDateTimeString(expirationTime),
invalidTime: getTimeFromDateTimeString(effectiveTime).toString(),
effectiveTime: getTimeFromDateTimeString(effectiveTime),
invalidTime: getTimeFromDateTimeString(expirationTime).toString(),
workingDay: selectedDays,
),
],
@ -448,6 +448,7 @@ class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordStat
<Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop(true);
},
child: const Text('OK'),

View File

@ -35,12 +35,12 @@ class AddDeviceDialog extends StatelessWidget {
backgroundColor: Colors.white,
title: Text(
'Add Accessible Device',
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 24,
color: Colors.black),
style: Theme.of(context)
.textTheme
.headlineLarge!
.copyWith(fontWeight: FontWeight.w400, fontSize: 24, color: Colors.black),
),
content: Container(
content: SizedBox(
height: MediaQuery.of(context).size.height / 1.7,
width: MediaQuery.of(context).size.width / 2,
child: Padding(
@ -68,17 +68,14 @@ class AddDeviceDialog extends StatelessWidget {
),
Text(
'Only online accessible devices can be added',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontWeight: FontWeight.w400,
fontSize: 12,
color: ColorsManager.grayColor),
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 12,
color: ColorsManager.grayColor),
),
],
)),
SizedBox(
const SizedBox(
height: 20,
),
const SizedBox(
@ -93,7 +90,7 @@ class AddDeviceDialog extends StatelessWidget {
flex: 4,
child: CustomWebTextField(
controller: visitorBloc.deviceNameController,
isRequired: true,
isRequired: false,
textFieldName: 'Device Name',
description: '',
),
@ -103,7 +100,7 @@ class AddDeviceDialog extends StatelessWidget {
flex: 4,
child: CustomWebTextField(
controller: visitorBloc.deviceIdController,
isRequired: true,
isRequired: false,
textFieldName: 'Device ID',
description: '',
),
@ -113,7 +110,7 @@ class AddDeviceDialog extends StatelessWidget {
flex: 4,
child: CustomWebTextField(
controller: visitorBloc.unitNameController,
isRequired: true,
isRequired: false,
textFieldName: 'Unit Name',
description: '',
),
@ -155,8 +152,7 @@ class AddDeviceDialog extends StatelessWidget {
visitorBloc.deviceNameController.clear();
visitorBloc.deviceIdController.clear();
visitorBloc.unitNameController.clear();
visitorBloc.add(
FetchDevice()); // Reset to original list
visitorBloc.add(FetchDevice()); // Reset to original list
},
),
),
@ -168,14 +164,15 @@ class AddDeviceDialog extends StatelessWidget {
flex: 3,
child: state is TableLoaded
? DynamicTable(
uuidIndex: 1,
withSelectAll: true,
initialSelectedIds: selectedDeviceIds,
cellDecoration: containerDecoration,
isEmpty: visitorBloc.data.isEmpty,
selectAll: (p0) {
visitorBloc.selectedDeviceIds.clear();
for (var item in state.data) {
visitorBloc
.add(SelectDeviceEvent(item.uuid));
visitorBloc.add(SelectDeviceEvent(item.uuid));
}
},
onRowSelected: (index, isSelected, row) {
@ -184,7 +181,6 @@ class AddDeviceDialog extends StatelessWidget {
},
withCheckBox: true,
size: size * 0.5,
uuidIndex: 1,
headers: const [
'Device Name',
'Device ID',

View File

@ -87,7 +87,8 @@ class VisitorPasswordDialog extends StatelessWidget {
],
))
.then((v) {
Navigator.of(context).pop();
Navigator.of(context).pop(true);
});
} else if (state is FailedState) {
visitorBloc.stateDialog(
@ -211,28 +212,28 @@ class VisitorPasswordDialog extends StatelessWidget {
},
),
),
SizedBox(
width: size.width * 0.12,
child: RadioListTile<String>(
contentPadding: EdgeInsets.zero,
title: Text(
'Dynamic Password',
style: text,
),
value: 'Dynamic Password',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
visitorBloc.usageFrequencySelected = '';
}
},
),
),
// SizedBox(
// width: size.width * 0.12,
// child: RadioListTile<String>(
// contentPadding: EdgeInsets.zero,
// title: Text(
// 'Dynamic Password',
// style: text,
// ),
// value: 'Dynamic Password',
// groupValue: (state is PasswordTypeSelected)
// ? state.selectedType
// : visitorBloc.accessTypeSelected,
// onChanged: (String? value) {
// if (value != null) {
// context
// .read<VisitorPasswordBloc>()
// .add(SelectPasswordType(value));
// visitorBloc.usageFrequencySelected = '';
// }
// },
// ),
// ),
],
)),
const Spacer(
@ -256,14 +257,14 @@ class VisitorPasswordDialog extends StatelessWidget {
color: ColorsManager.grayColor,
fontSize: 9),
),
if (visitorBloc.accessTypeSelected == 'Dynamic Password')
Text(
'Quick and short-acting password, only valid within 5 minutes after creation, the system randomly generates a digital password.',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontWeight: FontWeight.w400,
color: ColorsManager.grayColor,
fontSize: 9),
),
// if (visitorBloc.accessTypeSelected == 'Dynamic Password')
// Text(
// 'Quick and short-acting password, only valid within 5 minutes after creation, the system randomly generates a digital password.',
// style: Theme.of(context).textTheme.bodySmall!.copyWith(
// fontWeight: FontWeight.w400,
// color: ColorsManager.grayColor,
// fontSize: 9),
// ),
const SizedBox(
height: 20,
)
@ -323,8 +324,7 @@ class VisitorPasswordDialog extends StatelessWidget {
: visitorBloc.usageFrequencySelected,
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
context.read<VisitorPasswordBloc>()
.add(SelectUsageFrequency(value));
}
},
@ -344,7 +344,7 @@ class VisitorPasswordDialog extends StatelessWidget {
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.accessTypeSelected == 'Offline Password')
Text(
'Within the validity period, there is no limit to the number of times each device can be unlocked.',
'Within the validity period, each device can be unlocked only once, and the maximum validity period is 6 hours',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, fontSize: 9),
),
@ -380,11 +380,9 @@ class VisitorPasswordDialog extends StatelessWidget {
endTime: () {
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
visitorBloc.add(
SelectTimeEvent(context: context, isEffective: false));
visitorBloc.add(SelectTimeEvent(context: context, isEffective: false));
} else {
visitorBloc.add(SelectTimeVisitorPassword(
context: context, isStart: false, isRepeat: false));
visitorBloc.add(SelectTimeVisitorPassword(context: context, isStart: false, isRepeat: false));
}
},
startTime: () {
@ -398,13 +396,11 @@ class VisitorPasswordDialog extends StatelessWidget {
}
},
firstString: (visitorBloc.usageFrequencySelected ==
'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password')
'Periodic' && visitorBloc.accessTypeSelected == 'Offline Password')
? visitorBloc.effectiveTime
: visitorBloc.startTimeAccess.toString(),
secondString: (visitorBloc.usageFrequencySelected ==
'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password')
'Periodic' && visitorBloc.accessTypeSelected == 'Offline Password')
? visitorBloc.expirationTime
: visitorBloc.endTimeAccess.toString(),
icon: Assets.calendarIcon),
@ -528,9 +524,20 @@ class VisitorPasswordDialog extends StatelessWidget {
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
setPasswordFunction(context, size, visitorBloc);
} else if (visitorBloc.accessTypeSelected == 'Dynamic Password') {
setPasswordFunction(context, size, visitorBloc);
} else {
} else if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
if (visitorBloc.expirationTime != 'End Time' &&
visitorBloc.effectiveTime != 'Start Time' ) {
setPasswordFunction(context, size, visitorBloc);
}else{
visitorBloc.stateDialog(
context: context,
message: 'Please select Access Period to continue',
title: 'Access Period');
}
} else if(
visitorBloc.endTimeAccess.toString()!='End Time'
&&visitorBloc.startTimeAccess.toString()!='Start Time') {
if (visitorBloc.effectiveTimeTimeStamp != null &&
visitorBloc.expirationTimeTimeStamp != null) {
if (isRepeat == true) {
@ -554,6 +561,11 @@ class VisitorPasswordDialog extends StatelessWidget {
message: 'Please select Access Period to continue',
title: 'Access Period');
}
}else{
visitorBloc.stateDialog(
context: context,
message: 'Please select Access Period to continue',
title: 'Access Period');
}
} else {
visitorBloc.stateDialog(
@ -563,57 +575,6 @@ class VisitorPasswordDialog extends StatelessWidget {
}
}
},
// onPressed: () {
// if (visitorBloc.forgetFormKey.currentState!.validate()) {
// if (visitorBloc.selectedDevices.isNotEmpty) {
// switch (visitorBloc.usageFrequencySelected) {
// case 'One-Time':
// if (visitorBloc.accessTypeSelected == 'Offline Password') {
// setPasswordFunction(context, size, visitorBloc);
// } else {
// visitorBloc.stateDialog(
// context: context,
// message: 'Invalid combination of Access Type and Usage Frequency.',
// title: 'Error',
// );
// }
// break;
// default:
// if (visitorBloc.effectiveTimeTimeStamp != null && visitorBloc.expirationTimeTimeStamp != null) {
// if (isRepeat) {
// if (visitorBloc.expirationTime != 'End Time' &&
// visitorBloc.effectiveTime != 'Start Time' &&
// visitorBloc.selectedDays.isNotEmpty) {
// setPasswordFunction(context, size, visitorBloc);
// } else {
// visitorBloc.stateDialog(
// context: context,
// message: 'Please select days and fill start time and end time to continue',
// title: 'Access Period',
// );
// }
// } else {
// setPasswordFunction(context, size, visitorBloc);
// }
// } else {
// visitorBloc.stateDialog(
// context: context,
// message: 'Please select Access Period to continue',
// title: 'Access Period',
// );
// }
// break;
// }
// } else {
// visitorBloc.stateDialog(
// context: context,
// message: 'Please select devices to continue',
// title: 'Select Devices',
// );
// }
// }
// },
borderRadius: 8,
child: Text(
'Ok',
@ -723,39 +684,39 @@ class VisitorPasswordDialog extends StatelessWidget {
borderRadius: 8,
onPressed: () {
Navigator.pop(context);
if (visitorBloc.accessTypeSelected == 'Dynamic Password') {
} else {
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.accessTypeSelected == 'Online Password') {
visitorBloc.add(OnlineOneTimePasswordEvent(
context: context,
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
));
} else if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Online Password') {
visitorBloc.add(OnlineMultipleTimePasswordEvent(
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(),
invalidTime: visitorBloc.expirationTimeTimeStamp.toString(),
));
} else if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
visitorBloc.add(OfflineOneTimePasswordEvent(
context: context,
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
));
} else if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
visitorBloc.add(OfflineMultipleTimePasswordEvent(
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(),
invalidTime: visitorBloc.expirationTimeTimeStamp.toString(),
));
}
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.accessTypeSelected == 'Online Password') {
visitorBloc.add(OnlineOneTimePasswordEvent(
context: context,
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
));
}
else if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Online Password') {
visitorBloc.add(OnlineMultipleTimePasswordEvent(
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(),
invalidTime: visitorBloc.expirationTimeTimeStamp.toString(),
));
}
else if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
visitorBloc.add(OfflineOneTimePasswordEvent(
context: context,
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
));
}
else if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
visitorBloc.add(OfflineMultipleTimePasswordEvent(
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(),
invalidTime: visitorBloc.expirationTimeTimeStamp.toString(),
));
}
},
child: Text(

View File

@ -22,7 +22,6 @@ class AccessMangApi {
);
return response;
} catch (e) {
debugPrint('Error fetching visitor passwords: $e');
return [];
}
}
@ -42,7 +41,6 @@ class AccessMangApi {
);
return response;
} catch (e) {
debugPrint('Error fetching $e');
return [];
}
}

View File

@ -25,7 +25,8 @@ class AuthenticationAPI {
path: ApiEndpoints.forgetPassword,
body: {"email": email, "password": password},
showServerMessage: true,
expectedResponseModel: (json) {});
expectedResponseModel: (json) {
});
return response;
}
@ -52,21 +53,17 @@ class AuthenticationAPI {
return cooldown;
}
} else {
debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
return 1;
}
} else {
debugPrint('Error: ${e.message}');
return 1;
}
} catch (e) {
debugPrint('Unexpected Error: $e');
return 1;
}
}
static Future verifyOtp({required String email, required String otpCode}) async {
try {
final response = await HTTPService().post(
path: ApiEndpoints.verifyOtp,
body: {"email": email, "type": "PASSWORD", "otpCode": otpCode},
@ -79,17 +76,7 @@ class AuthenticationAPI {
}
});
return response;
} on DioException catch (e) {
if (e.response != null) {
if (e.response!.statusCode == 400) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
return errorMessage;
}
} else {
debugPrint('Error: ${e.message}');
}
}
}
static Future<List<RegionModel>> fetchRegion() async {

View File

@ -89,6 +89,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.1"
dropdown_button2:
dependency: "direct main"
description:
name: dropdown_button2
sha256: b0fe8d49a030315e9eef6c7ac84ca964250155a6224d491c1365061bc974a9e1
url: "https://pub.dev"
source: hosted
version: "2.3.9"
dropdown_search:
dependency: "direct main"
description:
name: dropdown_search
sha256: "55106e8290acaa97ed15bea1fdad82c3cf0c248dd410e651f5a8ac6870f783ab"
url: "https://pub.dev"
source: hosted
version: "5.0.6"
equatable:
dependency: "direct main"
description:

View File

@ -43,9 +43,11 @@ dependencies:
get_it: ^7.6.7
flutter_secure_storage: ^9.2.2
shared_preferences: ^2.3.0
dropdown_button2: ^2.3.9
data_table_2: ^2.5.15
go_router:
intl: ^0.19.0
dropdown_search: ^5.0.6
dev_dependencies:
flutter_test: