merged with dev and access_bugs and solved conflicts

This commit is contained in:
Abdullah Alassaf
2024-08-28 14:50:47 +03:00
30 changed files with 1326 additions and 1207 deletions

View File

@ -2,28 +2,34 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
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/bloc/visitor_password_bloc.dart';
import 'package:go_router/go_router.dart';
import 'package:syncrow_web/services/locator.dart';
import 'package:syncrow_web/utils/app_routes.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
initialSetup(); // Perform initial setup, e.g., dependency injection
initialSetup();
String checkToken = await AuthBloc.getTokenAndValidate();
GoRouter router = GoRouter(
initialLocation: checkToken == 'Success' ? RoutesConst.home : RoutesConst.auth,
routes: AppRoutes.getRoutes(),
);
runApp(MyApp(
isLoggedIn: checkToken,
router: router,
));
}
class MyApp extends StatelessWidget {
final dynamic isLoggedIn;
final GoRouter router;
const MyApp({
super.key,
required this.isLoggedIn,
required this.router,
});
@override
Widget build(BuildContext context) {
return MultiBlocProvider(
@ -33,7 +39,7 @@ class MyApp extends StatelessWidget {
create: (context) => VisitorPasswordBloc(),
)
],
child: MaterialApp(
child: MaterialApp.router(
debugShowCheckedModeBanner: false, // Hide debug banner
scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {
@ -48,9 +54,7 @@ class MyApp extends StatelessWidget {
fontFamily: 'Aftika',
textTheme: const TextTheme(
bodySmall: TextStyle(
fontSize: 13,
color: ColorsManager.whiteColors,
fontWeight: FontWeight.bold),
fontSize: 13, color: ColorsManager.whiteColors, fontWeight: FontWeight.bold),
bodyMedium: TextStyle(color: Colors.black87, fontSize: 14),
bodyLarge: TextStyle(fontSize: 16, color: Colors.white),
headlineSmall: TextStyle(color: Colors.black87, fontSize: 18),
@ -61,47 +65,10 @@ class MyApp extends StatelessWidget {
fontWeight: FontWeight.bold,
),
),
colorScheme: ColorScheme.fromSeed(
seedColor: ColorsManager.blueColor,
primary: ColorsManager.blueColor, // Checked state color
onSurface: Colors.grey.shade400, // Unchecked state color
),
switchTheme: SwitchThemeData(
thumbColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return ColorsManager
.blueColor; // Color of the switch knob when selected
}
return ColorsManager
.whiteColors; // Color of the switch knob when not selected
}),
trackColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return ColorsManager.blueColor
.withOpacity(0.5); // Track color when selected
}
return ColorsManager
.whiteColors; // Track color when not selected
}),
),
checkboxTheme: CheckboxThemeData(
fillColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return ColorsManager.blueColor; // Checked state color
}
return Colors.grey.shade200; // Unchecked state color
}),
checkColor: MaterialStateProperty.all(
Colors.white), // The color of the checkmark
side:
BorderSide(color: ColorsManager.whiteColors), // Border color
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(4), // Border radius
),
),
useMaterial3: true, // Enable Material 3
),
home: isLoggedIn == 'Success' ? const HomePage() : const LoginPage(),
routeInformationProvider: router.routeInformationProvider,
routerDelegate: router.routerDelegate,
routeInformationParser: router.routeInformationParser,
));
}
}

View File

@ -5,7 +5,7 @@ import 'package:syncrow_web/pages/access_management/bloc/access_state.dart';
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
import 'package:syncrow_web/services/access_mang_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/const.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/snack_bar.dart';
class AccessBloc extends Bloc<AccessEvent, AccessState> {
@ -26,8 +26,7 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
List<PasswordModel> filteredData = [];
List<PasswordModel> data = [];
Future<void> _onFetchTableData(
FetchTableData event, Emitter<AccessState> emit) async {
Future<void> _onFetchTableData(FetchTableData event, Emitter<AccessState> emit) async {
try {
emit(AccessLoaded());
data = await AccessMangApi().fetchVisitorPassword();
@ -40,28 +39,19 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
}
void updateTabsCount() {
int toBeEffectiveCount = data
.where((item) => item.passwordStatus.value == 'To Be Effective')
.length;
int effectiveCount =
data.where((item) => item.passwordStatus.value == 'Effective').length;
int expiredCount =
data.where((item) => item.passwordStatus.value == 'Expired').length;
int toBeEffectiveCount =
data.where((item) => item.passwordStatus.value == 'To be effective').length;
int effectiveCount = data.where((item) => item.passwordStatus.value == 'Effective').length;
int expiredCount = data.where((item) => item.passwordStatus.value == 'Expired').length;
tabs[1] = 'To Be Effective ($toBeEffectiveCount)';
tabs[2] = 'Effective ($effectiveCount)';
tabs[3] = 'Expired ($expiredCount)';
}
int selectedIndex = 0;
final List<String> tabs = [
'All',
'To Be Effective (0)',
'Effective (0)',
'Expired'
];
final List<String> tabs = ['All', 'To Be Effective (0)', 'Effective (0)', 'Expired'];
Future selectFilterTap(
TabChangedEvent event, Emitter<AccessState> emit) async {
Future selectFilterTap(TabChangedEvent event, Emitter<AccessState> emit) async {
try {
emit(AccessLoaded());
selectedIndex = event.selectedIndex;
@ -75,7 +65,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async {
emit(AccessLoaded());
final DateTime? picked = await showDatePicker(
context: event.context,
initialDate: DateTime.now(),
@ -83,111 +72,112 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
lastDate: DateTime(2101),
);
if (picked != null) {
final TimeOfDay? timePicked = await showTimePicker(
context: event.context,
initialTime: TimeOfDay.now(),
builder: (context, child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: const ColorScheme.light(
primary: ColorsManager.primaryColor,
onSurface: Colors.black,
),
buttonTheme: const ButtonThemeData(
colorScheme: ColorScheme.light(
primary: Colors.green,
),
),
),
child: child!,
);
},
final selectedDateTime = DateTime(
picked.year,
picked.month,
picked.day,
);
if (timePicked != null) {
final selectedDateTime = DateTime(
picked.year,
picked.month,
picked.day,
timePicked.hour,
timePicked.minute,
);
final selectedTimestamp = DateTime(
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isStart) {
if (expirationTimeTimeStamp != null &&
selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
} else {
startTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
final selectedTimestamp = DateTime(
selectedDateTime.year,
selectedDateTime.month,
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isStart) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
} else {
if (effectiveTimeTimeStamp != null &&
selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else {
endTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
startTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
} else {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.');
} else {
endTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
}
}
emit(ChangeTimeState());
}
Future<void> _filterData(
FilterDataEvent event, Emitter<AccessState> emit) async {
Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async {
emit(AccessLoaded());
try {
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 invalidDate =
DateTime.fromMillisecondsSinceEpoch(int.parse(item.invalidTime.toString()) * 1000)
.toUtc()
.toLocal();
DateTime effectiveDateOnly =
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);
final bool matchesName =
item.passwordName != null && item.passwordName.contains(event.passwordName);
if (!matchesName) {
matchesCriteria = false;
}
}
if (event.startTime != null && event.endTime != null) {
final int? effectiveTime =
int.tryParse(item.effectiveTime.toString());
final int? invalidTime = int.tryParse(item.invalidTime.toString());
if (effectiveTime == null || invalidTime == null) {
// Filter by start date only
if (event.startTime != null && event.endTime == null) {
DateTime startDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day);
if (effectiveDateOnly.isBefore(startDateOnly)) {
matchesCriteria = false;
} else {
final bool matchesStartTime = effectiveTime >= event.startTime!;
final bool matchesEndTime = invalidTime <= event.endTime!;
if (!matchesStartTime || !matchesEndTime) {
matchesCriteria = false;
}
}
}
if (event.selectedTabIndex == 1 &&
item.passwordStatus.value != 'To Be Effective') {
// Filter by end date only
if (event.endTime != null && event.startTime == null) {
DateTime endDateOnly =
DateTime.fromMillisecondsSinceEpoch(event.endTime! * 1000).toUtc().toLocal();
endDateOnly = DateTime(endDateOnly.year, endDateOnly.month, endDateOnly.day);
if (invalidDateOnly.isAfter(endDateOnly)) {
matchesCriteria = false;
}
}
// 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 endDateOnly =
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)) {
matchesCriteria = false;
}
}
// Filter by selected tab index
if (event.selectedTabIndex == 1 && item.passwordStatus.value != 'To be effective') {
matchesCriteria = false;
} else if (event.selectedTabIndex == 2 &&
item.passwordStatus.value != 'Effective') {
} else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') {
matchesCriteria = false;
} else if (event.selectedTabIndex == 3 &&
item.passwordStatus.value != 'Expired') {
} else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') {
matchesCriteria = false;
}
return matchesCriteria;
}).toList();
emit(TableLoaded(filteredData));
} catch (e) {
emit(FailedState(e.toString()));
@ -206,13 +196,11 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
}
String timestampToDate(dynamic timestamp) {
DateTime dateTime =
DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}";
}
Future<void> onTabChanged(
TabChangedEvent event, Emitter<AccessState> emit) async {
Future<void> onTabChanged(TabChangedEvent event, Emitter<AccessState> emit) async {
try {
emit(AccessLoaded());
selectedIndex = event.selectedIndex;
@ -221,19 +209,14 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
filteredData = data;
break;
case 1: // To Be Effective
filteredData = data
.where((item) => item.passwordStatus.value == "To Be Effective")
.toList();
filteredData =
data.where((item) => item.passwordStatus.value == "To Be Effective").toList();
break;
case 2: // Effective
filteredData = data
.where((item) => item.passwordStatus.value == "Effective")
.toList();
filteredData = data.where((item) => item.passwordStatus.value == "Effective").toList();
break;
case 3: // Expired
filteredData = data
.where((item) => item.passwordStatus.value == "Expired")
.toList();
filteredData = data.where((item) => item.passwordStatus.value == "Expired").toList();
break;
default:
filteredData = data;

View File

@ -1,4 +1,4 @@
import 'package:syncrow_web/utils/constants/const.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
class PasswordModel {
final dynamic passwordId;

View File

@ -1,293 +1,287 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.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/buttons/default_button.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/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/text_field/custom_web_textfield.dart';
import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/constants/const.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
import 'package:syncrow_web/utils/style.dart';
import 'package:syncrow_web/web_layout/web_scaffold.dart';
class AccessManagementPage extends StatelessWidget {
const AccessManagementPage({super.key});
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return WebScaffold(
enableMenuSideba: false,
appBarTitle: Row(
children: [
Text(
'Access Management',
style: Theme.of(context).textTheme.headlineLarge,
)
],
),
appBarBody: [
Text(
'Physical Access',
style: Theme.of(context)
.textTheme
.headlineMedium!
.copyWith(color: Colors.white),
enableMenuSideba: false,
appBarTitle: Row(
children: [
Text(
'Access Management',
style: Theme.of(context).textTheme.headlineLarge,
)
],
),
],
scaffoldBody: BlocProvider(
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
child: BlocConsumer<AccessBloc, AccessState>(
listener: (context, state) {},
builder: (context, state) {
final accessBloc = BlocProvider.of<AccessBloc>(context);
final filteredData = accessBloc.filteredData;
return state is AccessLoaded
? const Center(child: CircularProgressIndicator())
: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.all(30),
appBarBody: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Physical Access',
style: Theme.of(context).textTheme.headlineMedium!.copyWith(color: Colors.white),
),
Row(
children: [
InkWell(
onTap: () {
context.go(RoutesConst.home);
},
child: SvgPicture.asset(
height: 20,
width: 20,
Assets.grid,
),
),
const SizedBox(
width: 10,
)
],
),
],
),
],
scaffoldBody: BlocProvider(
create: (BuildContext context) => AccessBloc()..add(FetchTableData()),
child: BlocConsumer<AccessBloc, AccessState>(
listener: (context, state) {},
builder: (context, state) {
final accessBloc = BlocProvider.of<AccessBloc>(context);
final filteredData = accessBloc.filteredData;
return state is AccessLoaded
? const Center(child: CircularProgressIndicator())
: Container(
padding: EdgeInsets.all(30),
height: size.height,
width: size.width,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTabSelector(context, accessBloc, size),
const SizedBox(height: 20),
_buildSearchFilters(context, accessBloc, size),
const SizedBox(height: 20),
_buildActionButtons(context, accessBloc, size),
const SizedBox(height: 20),
Container(
decoration: containerDecoration,
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(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
textBaseline: TextBaseline.ideographic,
children: [
Container(
width: size.width * 0.15,
child: CustomWebTextField(
controller: accessBloc.passwordName,
isRequired: true,
textFieldName: 'Name',
description: '',
),
),
const SizedBox(
width: 15,
),
DateTimeWebWidget(
icon: Assets.calendarIcon,
isRequired: false,
title: 'Access Time',
size: size,
endTime: () {
accessBloc.add(SelectTime(context: context, isStart: false));
},
startTime: () {
accessBloc.add(SelectTime(context: context, isStart: true));
},
firstString: BlocProvider.of<AccessBloc>(context).startTime,
secondString: BlocProvider.of<AccessBloc>(context).endTime,
),
const SizedBox(
width: 15,
),
SizedBox(
width: size.width * 0.06,
child: Container(
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
accessBloc.add(FilterDataEvent(
selectedTabIndex: BlocProvider.of<AccessBloc>(
context)
.selectedIndex, // Pass the selected tab index
passwordName:
accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp));
},
borderRadius: 9,
child: const Text('Search'))),
),
const SizedBox(
width: 10,
),
SizedBox(
width: size.width * 0.06,
child: Container(
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
accessBloc.add(ResetSearch());
},
backgroundColor: ColorsManager.whiteColors,
borderRadius: 9,
child: Text(
'Reset',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black),
),
),
),
),
],
),
const SizedBox(
height: 20,
),
Wrap(
children: [
Container(
width: size.width * 0.15,
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return const VisitorPasswordDialog();
},
).then((v) {
if (v != null) {
accessBloc.add(FetchTableData());
}
});
},
borderRadius: 8,
child: const Text('+ Create Visitor Password ')),
),
const SizedBox(
width: 10,
),
Container(
width: size.width * 0.12,
decoration: containerDecoration,
child: DefaultButton(
borderRadius: 8,
backgroundColor: ColorsManager.whiteColors,
child: Text(
'Admin Password',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black),
)))
],
),
const SizedBox(
height: 20,
),
Expanded(
child: DynamicTable(
isEmpty: filteredData.isEmpty,
withCheckBox: false,
size: size,
cellDecoration: containerDecoration,
headers: const [
'Name',
'Access Type',
'Access Period',
'Accessible Device',
'Authorizer',
'Authorization Date & Time',
'Access Status'
],
data: filteredData.map((item) {
return [
item.passwordName.toString(),
item.passwordType.value,
('${accessBloc.timestampToDate(item.effectiveTime)} - ${accessBloc.timestampToDate(item.invalidTime)}'),
item.deviceUuid.toString(),
'',
'',
item.passwordStatus.value,
];
}).toList(),
)
// : const Center(child: CircularProgressIndicator()),
)
],
),
),
),
SliverFillRemaining(
child: DynamicTable(
isEmpty: filteredData.isEmpty,
withCheckBox: false,
size: size,
cellDecoration: containerDecoration,
headers: const [
'Name',
'Access Type',
'Access Period',
'Accessible Device',
'Authorizer',
'Authorization Date & Time',
'Access Status'
],
data: filteredData.map((item) {
return [
item.passwordName.toString(),
item.passwordType.value,
('${accessBloc.timestampToDate(item.effectiveTime)} - ${accessBloc.timestampToDate(item.invalidTime)}'),
item.deviceUuid.toString(),
'',
'',
item.passwordStatus.value
];
}).toList(),
),
),
],
);
},
),
),
);
}
Widget _buildTabSelector(
BuildContext context, AccessBloc accessBloc, Size size) {
return Container(
decoration: containerDecoration,
height: size.height * 0.05,
child: Flexible(
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: accessBloc.tabs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
final isSelected = index == accessBloc.selectedIndex;
return InkWell(
onTap: () {
accessBloc.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 == accessBloc.tabs.length - 1
? const BorderRadius.only(
topRight: Radius.circular(10),
bottomRight: Radius.circular(10))
: null,
),
padding: const EdgeInsets.only(left: 10, right: 10),
child: Center(
child: Text(
accessBloc.tabs[index],
style: TextStyle(
color: isSelected ? Colors.blue : Colors.black,
),
),
),
),
);
},
),
),
);
}
Widget _buildSearchFilters(
BuildContext context, AccessBloc accessBloc, Size size) {
return Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.end,
textBaseline: TextBaseline.ideographic,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
'Name',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black, fontSize: 13),
),
const SizedBox(height: 5),
Container(
height: 43,
width: size.width * 0.15,
decoration: containerDecoration,
child: TextFormField(
controller: accessBloc.passwordName,
style: const TextStyle(color: Colors.black),
decoration:
textBoxDecoration()!.copyWith(hintText: 'Please enter'),
),
),
],
),
const SizedBox(width: 15),
DateTimeWebWidget(
icon: Assets.calendarIcon,
isRequired: false,
title: 'Access Time',
size: size,
endTime: () {
accessBloc.add(SelectTime(context: context, isStart: false));
},
startTime: () {
accessBloc.add(SelectTime(context: context, isStart: true));
},
firstString: accessBloc.startTime,
secondString: accessBloc.endTime,
),
const SizedBox(width: 15),
SizedBox(
height: 45,
width: size.width * 0.06,
child: Container(
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
accessBloc.add(FilterDataEvent(
selectedTabIndex:
accessBloc.selectedIndex, // Pass the selected tab index
passwordName: accessBloc.passwordName.text.toLowerCase(),
startTime: accessBloc.effectiveTimeTimeStamp,
endTime: accessBloc.expirationTimeTimeStamp,
));
},
borderRadius: 9,
child: const Text('Search'),
),
),
),
const SizedBox(width: 10),
SizedBox(
height: 45,
width: size.width * 0.06,
child: Container(
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
accessBloc.add(ResetSearch());
},
backgroundColor: ColorsManager.whiteColors,
borderRadius: 9,
child: Text(
'Reset',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black),
),
),
),
),
],
);
}
Widget _buildActionButtons(
BuildContext context, AccessBloc accessBloc, Size size) {
return Wrap(
children: [
Container(
width: size.width * 0.15,
decoration: containerDecoration,
child: DefaultButton(
onPressed: () {
showDialog(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
return const VisitorPasswordDialog();
},
).then((v) {
if (v != null) {
accessBloc.add(FetchTableData());
}
});
},
borderRadius: 8,
child: const Text('+ Create Visitor Password '),
),
),
const SizedBox(width: 10),
Container(
width: size.width * 0.12,
decoration: containerDecoration,
child: DefaultButton(
borderRadius: 8,
backgroundColor: ColorsManager.whiteColors,
child: Text(
'Admin Password',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black),
),
),
)
],
);
);
})));
}
}

View File

@ -1,9 +1,8 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/svg.dart';
import 'package:go_router/go_router.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_event.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_state.dart';
@ -13,7 +12,7 @@ import 'package:syncrow_web/pages/common/buttons/default_button.dart';
import 'package:syncrow_web/pages/common/first_layer.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/pages/home/view/home_page.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
import 'package:syncrow_web/utils/style.dart';
class LoginWebPage extends StatefulWidget {
@ -32,13 +31,8 @@ class _LoginWebPageState extends State<LoginWebPage> {
child: BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) {
if (state is LoginSuccess) {
// Navigate to home screen after successful login
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => HomePage()),
);
context.go(RoutesConst.home);
} else if (state is LoginFailure) {
// Show error message
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(state.error),
@ -60,8 +54,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
late ScrollController _scrollController;
_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),
@ -105,11 +98,9 @@ class _LoginWebPageState extends State<LoginWebPage> {
child: Container(
decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1),
borderRadius: const BorderRadius.all(
Radius.circular(30)),
borderRadius: const BorderRadius.all(Radius.circular(30)),
border: Border.all(
color: ColorsManager.graysColor
.withOpacity(0.2))),
color: ColorsManager.graysColor.withOpacity(0.2))),
child: Form(
key: loginBloc.loginFormKey,
child: Padding(
@ -117,22 +108,16 @@ class _LoginWebPageState extends State<LoginWebPage> {
horizontal: size.width * 0.02,
vertical: size.width * 0.003),
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
const SizedBox(height: 40),
Text('Login',
style: Theme.of(context)
.textTheme
.headlineLarge),
style: Theme.of(context).textTheme.headlineLarge),
SizedBox(height: size.height * 0.03),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Country/Region",
@ -140,81 +125,57 @@ class _LoginWebPageState extends State<LoginWebPage> {
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
fontSize: 14, fontWeight: FontWeight.w400),
),
const SizedBox(
height: 10,
),
SizedBox(
child: DropdownButtonFormField<
String>(
child: DropdownButtonFormField<String>(
padding: EdgeInsets.zero,
value: loginBloc.regionList!
.any((region) =>
region.id ==
loginBloc
.regionUuid)
value: loginBloc.regionList!.any((region) =>
region.id == loginBloc.regionUuid)
? loginBloc.regionUuid
: null,
validator:
loginBloc.validateRegion,
validator: loginBloc.validateRegion,
icon: const Icon(
Icons
.keyboard_arrow_down_outlined,
Icons.keyboard_arrow_down_outlined,
),
decoration: textBoxDecoration()!
.copyWith(
errorStyle: const TextStyle(
height: 0),
decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(height: 0),
hintText: null,
),
hint: SizedBox(
width: size.width * 0.12,
child: Align(
alignment:
Alignment.centerLeft,
alignment: Alignment.centerLeft,
child: Text(
'Select your region/country',
textAlign:
TextAlign.center,
textAlign: TextAlign.center,
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color:
ColorsManager
.grayColor,
fontWeight:
FontWeight
.w400),
overflow:
TextOverflow.ellipsis,
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>(
style: const TextStyle(color: Colors.black),
items:
loginBloc.regionList!.map((RegionModel region) {
return DropdownMenuItem<String>(
value: region.id,
child: SizedBox(
width:
size.width * 0.08,
child:
Text(region.name)),
width: size.width * 0.08,
child: Text(region.name)),
);
}).toList(),
onChanged: (String? value) {
loginBloc
.add(CheckEnableEvent());
loginBloc.add(
SelectRegionEvent(
val: value!));
loginBloc.add(CheckEnableEvent());
loginBloc.add(SelectRegionEvent(val: value!));
},
),
)
@ -222,10 +183,8 @@ class _LoginWebPageState extends State<LoginWebPage> {
),
const SizedBox(height: 20.0),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Email",
@ -233,9 +192,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
fontSize: 14, fontWeight: FontWeight.w400),
),
const SizedBox(
height: 10,
@ -243,43 +200,30 @@ class _LoginWebPageState extends State<LoginWebPage> {
SizedBox(
child: TextFormField(
onChanged: (value) {
loginBloc
.add(CheckEnableEvent());
loginBloc.add(CheckEnableEvent());
// print(loginBloc.checkEnable());
},
validator: loginBloc
.loginValidateEmail,
controller: loginBloc
.loginEmailController,
decoration: textBoxDecoration()!
.copyWith(
errorStyle: const TextStyle(
height:
0), // Hide the error text space
hintText:
'Enter your email address',
hintStyle: Theme.of(
context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager
.grayColor,
fontWeight:
FontWeight
.w400)),
style: const TextStyle(
color: Colors.black),
validator: loginBloc.loginValidateEmail,
controller: loginBloc.loginEmailController,
decoration: textBoxDecoration()!.copyWith(
errorStyle: const TextStyle(
height: 0), // Hide the error text space
hintText: 'Enter your email address',
hintStyle: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor,
fontWeight: FontWeight.w400)),
style: const TextStyle(color: Colors.black),
),
),
],
),
const SizedBox(height: 20.0),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: [
Text(
"Password",
@ -287,9 +231,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
.textTheme
.bodySmall!
.copyWith(
fontSize: 14,
fontWeight:
FontWeight.w400),
fontSize: 14, fontWeight: FontWeight.w400),
),
const SizedBox(
height: 10,
@ -297,54 +239,39 @@ class _LoginWebPageState extends State<LoginWebPage> {
SizedBox(
child: TextFormField(
onChanged: (value) {
loginBloc
.add(CheckEnableEvent());
loginBloc.add(CheckEnableEvent());
},
validator:
loginBloc.validatePassword,
obscureText:
loginBloc.obscureText,
keyboardType: TextInputType
.visiblePassword,
controller: loginBloc
.loginPasswordController,
decoration: textBoxDecoration()!
.copyWith(
hintText:
'At least 8 characters',
validator: loginBloc.validatePassword,
obscureText: loginBloc.obscureText,
keyboardType: TextInputType.visiblePassword,
controller: loginBloc.loginPasswordController,
decoration: textBoxDecoration()!.copyWith(
hintText: 'At least 8 characters',
hintStyle: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager
.grayColor,
fontWeight:
FontWeight.w400),
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,
? Assets.visiblePassword
: Assets.invisiblePassword,
height: 15,
width: 15,
),
),
),
errorStyle: const TextStyle(
height:
0), // Hide the error text space
height: 0), // Hide the error text space
),
style: const TextStyle(
color: Colors.black),
style: const TextStyle(color: Colors.black),
),
),
],
@ -354,13 +281,11 @@ class _LoginWebPageState extends State<LoginWebPage> {
),
SizedBox(
child: Row(
mainAxisAlignment:
MainAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: () {
Navigator.of(context)
.push(MaterialPageRoute(
Navigator.of(context).push(MaterialPageRoute(
builder: (context) =>
const ForgetPasswordPage(),
));
@ -373,8 +298,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
.copyWith(
color: Colors.black,
fontSize: 14,
fontWeight:
FontWeight.w400),
fontWeight: FontWeight.w400),
),
),
],
@ -386,18 +310,16 @@ class _LoginWebPageState extends State<LoginWebPage> {
Row(
children: [
Transform.scale(
scale:
1.2, // Adjust the scale as needed
scale: 1.2, // Adjust the scale as needed
child: Checkbox(
fillColor: MaterialStateProperty
.all<Color>(Colors.white),
fillColor:
MaterialStateProperty.all<Color>(Colors.white),
activeColor: Colors.white,
value: loginBloc.isChecked,
checkColor: Colors.black,
shape: const CircleBorder(),
onChanged: (bool? newValue) {
loginBloc.add(CheckBoxEvent(
newValue: newValue));
loginBloc.add(CheckBoxEvent(newValue: newValue));
},
),
),
@ -406,45 +328,36 @@ class _LoginWebPageState extends State<LoginWebPage> {
child: RichText(
text: TextSpan(
text: 'Agree to ',
style: const TextStyle(
color: Colors.white),
style: const TextStyle(color: Colors.white),
children: [
TextSpan(
text:
'(Terms of Service)',
text: '(Terms of Service)',
style: const TextStyle(
color: Colors.black,
),
recognizer:
TapGestureRecognizer()
..onTap = () {
loginBloc.launchURL(
'https://example.com/terms');
},
recognizer: TapGestureRecognizer()
..onTap = () {
loginBloc.launchURL(
'https://example.com/terms');
},
),
TextSpan(
text:
' (Legal Statement)',
style: const TextStyle(
color: Colors.black),
recognizer:
TapGestureRecognizer()
..onTap = () {
loginBloc.launchURL(
'https://example.com/legal');
},
text: ' (Legal Statement)',
style: const TextStyle(color: Colors.black),
recognizer: TapGestureRecognizer()
..onTap = () {
loginBloc.launchURL(
'https://example.com/legal');
},
),
TextSpan(
text:
' (Privacy Statement)',
style: const TextStyle(
color: Colors.black),
recognizer:
TapGestureRecognizer()
..onTap = () {
loginBloc.launchURL(
'https://example.com/privacy');
},
text: ' (Privacy Statement)',
style: const TextStyle(color: Colors.black),
recognizer: TapGestureRecognizer()
..onTap = () {
loginBloc.launchURL(
'https://example.com/privacy');
},
),
],
),
@ -454,49 +367,35 @@ class _LoginWebPageState extends State<LoginWebPage> {
),
const SizedBox(height: 20.0),
Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
width: size.width * 0.2,
child: DefaultButton(
enabled:
loginBloc.checkValidate,
enabled: loginBloc.checkValidate,
child: Text('Sign in',
style: Theme.of(context)
.textTheme
.labelLarge!
.copyWith(
fontSize: 14,
color: loginBloc
.checkValidate
? ColorsManager
.whiteColors
: ColorsManager
.whiteColors
.withOpacity(
0.2),
color: loginBloc.checkValidate
? ColorsManager.whiteColors
: ColorsManager.whiteColors
.withOpacity(0.2),
)),
onPressed: () {
if (loginBloc.loginFormKey
.currentState!
if (loginBloc.loginFormKey.currentState!
.validate()) {
loginBloc
.add(LoginButtonPressed(
regionUuid:
loginBloc.regionUuid,
username: loginBloc
.loginEmailController
.text,
password: loginBloc
.loginPasswordController
.text,
loginBloc.add(LoginButtonPressed(
regionUuid: loginBloc.regionUuid,
username: loginBloc.loginEmailController.text,
password:
loginBloc.loginPasswordController.text,
));
} else {
loginBloc.add(
ChangeValidateEvent());
loginBloc.add(ChangeValidateEvent());
}
},
),
@ -505,10 +404,8 @@ class _LoginWebPageState extends State<LoginWebPage> {
),
const SizedBox(height: 15.0),
Row(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment:
MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
SizedBox(
child: Text(
@ -533,8 +430,7 @@ class _LoginWebPageState extends State<LoginWebPage> {
),
),
),
if (state is AuthLoading)
const Center(child: CircularProgressIndicator())
if (state is AuthLoading) const Center(child: CircularProgressIndicator())
],
);
}

View File

@ -7,6 +7,7 @@ Future<void> showCustomDialog({
required String message,
String? title,
String? iconPath,
Widget? widget,
double? dialogHeight,
double? iconHeight,
double? iconWidth,
@ -54,6 +55,8 @@ Future<void> showCustomDialog({
textAlign: TextAlign.center,
),
),
if(widget!=null)
Expanded(child:widget)
],
),
),

View File

@ -14,7 +14,6 @@ class DynamicTable extends StatefulWidget {
final void Function(bool?)? selectAll;
final void Function(int, bool, dynamic)? onRowSelected;
final List<String>? initialSelectedIds;
const DynamicTable({
super.key,
required this.headers,
@ -66,14 +65,11 @@ class _DynamicTableState extends State<DynamicTable> {
child: Column(
children: [
Container(
decoration: widget.headerDecoration ??
BoxDecoration(color: Colors.grey[200]),
decoration: widget.headerDecoration ?? BoxDecoration(color: Colors.grey[200]),
child: Row(
children: [
if (widget.withCheckBox) _buildSelectAllCheckbox(),
...widget.headers
.map((header) => _buildTableHeaderCell(header))
.toList(),
...widget.headers.map((header) => _buildTableHeaderCell(header)).toList(),
],
),
),
@ -97,8 +93,7 @@ class _DynamicTableState extends State<DynamicTable> {
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor),
.copyWith(color: ColorsManager.grayColor),
)
],
),
@ -118,12 +113,10 @@ class _DynamicTableState extends State<DynamicTable> {
return Row(
children: [
if (widget.withCheckBox)
_buildRowCheckbox(
index, widget.size.height * 0.10),
_buildRowCheckbox(index, widget.size.height * 0.10),
...row
.map((cell) => _buildTableCell(
cell.toString(),
widget.size.height * 0.10))
.map((cell) =>
_buildTableCell(cell.toString(), widget.size.height * 0.10))
.toList(),
],
);
@ -211,6 +204,27 @@ class _DynamicTableState extends State<DynamicTable> {
batteryLevel = double.tryParse(content.replaceAll('%', '').trim());
}
Color? statusColor;
switch (content) {
case 'Effective':
statusColor = ColorsManager.textGreen;
break;
case 'Expired':
statusColor = ColorsManager.red;
break;
case 'To be effective':
statusColor = ColorsManager.yaGreen;
break;
case 'Online':
statusColor = ColorsManager.green;
break;
case 'Offline':
statusColor = ColorsManager.red;
break;
default:
statusColor = Colors.black; // Default color
}
return Expanded(
child: Container(
height: size,
@ -227,16 +241,11 @@ class _DynamicTableState extends State<DynamicTable> {
child: Text(
content,
style: TextStyle(
color: batteryLevel != null && batteryLevel < 20
? ColorsManager.red // Red color for low battery
: content == 'Online'
? ColorsManager.green // Green color for Online
: content == 'Offline'
? ColorsManager.red // Red color for Offline
: Colors.black,
fontSize: 12,
fontWeight: FontWeight.w400,
),
color: batteryLevel != null && batteryLevel < 20
? ColorsManager.red
: statusColor, // Use the passed color or default to black
fontSize: 10,
fontWeight: FontWeight.w400),
),
),
);

View File

@ -36,10 +36,7 @@ class DateTimeWebWidget extends StatelessWidget {
if (isRequired)
Text(
'* ',
style: Theme.of(context)
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Colors.red),
),
Text(
title,
@ -55,8 +52,7 @@ class DateTimeWebWidget extends StatelessWidget {
),
Container(
height: size.height * 0.055,
padding:
const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10),
padding: const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10),
decoration: containerDecoration,
child: FittedBox(
child: Column(
@ -69,13 +65,10 @@ class DateTimeWebWidget extends StatelessWidget {
child: FittedBox(
child: Text(
firstString,
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor,
fontSize: 12,
fontWeight: FontWeight.w400),
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,
fontSize: 12,
fontWeight: FontWeight.w400),
),
)),
const SizedBox(
@ -90,13 +83,10 @@ class DateTimeWebWidget extends StatelessWidget {
child: FittedBox(
child: Text(
secondString,
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color: ColorsManager.grayColor,
fontSize: 12,
fontWeight: FontWeight.w400),
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor,
fontSize: 12,
fontWeight: FontWeight.w400),
),
)),
const SizedBox(

View File

@ -1,17 +1,15 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:go_router/go_router.dart';
import 'package:graphview/GraphView.dart';
import 'package:syncrow_web/pages/access_management/view/access_management.dart';
import 'package:syncrow_web/pages/auth/model/user_model.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/view/device_managment_page.dart';
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
import 'package:syncrow_web/services/home_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
class HomeBloc extends Bloc<HomeEvent, HomeState> {
final Graph graph = Graph()..isTree = true;
@ -43,8 +41,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
Future fetchUserInfo() async {
try {
var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
user = await HomeApi().fetchUserInfo(uuid);
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
} catch (e) {
@ -58,9 +55,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
icon: Assets.accessIcon,
active: true,
onPress: (context) {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => AccessManagementPage()),
);
context.go(RoutesConst.accessManagementPage);
},
color: null,
),
@ -76,9 +71,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
icon: Assets.devicesIcon,
active: true,
onPress: (context) {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const DeviceManagementPage()),
);
context.go(RoutesConst.deviceManagementPage);
},
color: ColorsManager.primaryColor,
),

View File

@ -24,13 +24,19 @@ class HomeCard extends StatelessWidget {
child: Container(
padding: const EdgeInsets.only(left: 10, right: 10, bottom: 10),
decoration: BoxDecoration(
color:
// evenNumbers && active
// ? ColorsManager.blueColor.withOpacity(0.8)
// :
(active
? ColorsManager.blueColor
: ColorsManager.blueColor.withOpacity(0.2)),
color: index == 0 && active
? ColorsManager.blue1.withOpacity(0.9)
: index == 1 && active
? ColorsManager.blue2.withOpacity(0.9)
: index == 2 && active
? ColorsManager.blue3
: index == 4 && active == false
? ColorsManager.blue4.withOpacity(0.2)
: index == 7 && active == false
? ColorsManager.blue4.withOpacity(0.2)
: ColorsManager.blueColor.withOpacity(0.2),
// (active ?ColorsManager.blueColor
// : ColorsManager.blueColor.withOpacity(0.2)),
borderRadius: BorderRadius.circular(30),
),
child: Column(

View File

@ -8,7 +8,6 @@ class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ResponsiveLayout(
desktopBody: HomeWebPage(), mobileBody: HomeMobilePage());
return ResponsiveLayout(desktopBody: HomeWebPage(), mobileBody: HomeMobilePage());
}
}

View File

@ -12,7 +12,11 @@ class HomeWebPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return WebScaffold(
return PopScope(
canPop: false,
onPopInvoked: (didPop) => false,
child:
WebScaffold(
enableMenuSideba: false,
appBarTitle: Row(
children: [
@ -76,6 +80,6 @@ class HomeWebPage extends StatelessWidget {
);
},
),
));
)));
}
}

View File

@ -0,0 +1,16 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class SpaseManagementicon extends StatelessWidget {
const SpaseManagementicon({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(),
);
}
}

View File

@ -1,4 +1,5 @@
import 'dart:math';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
@ -7,14 +8,14 @@ import 'package:syncrow_web/pages/common/hour_picker_dialog.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.dart';
import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_state.dart';
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
import 'package:syncrow_web/pages/visitor_password/model/failed_operation.dart';
import 'package:syncrow_web/pages/visitor_password/model/schedule_model.dart';
import 'package:syncrow_web/services/access_mang_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/snack_bar.dart';
class VisitorPasswordBloc
extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
class VisitorPasswordBloc extends Bloc<VisitorPasswordEvent, VisitorPasswordState> {
VisitorPasswordBloc() : super(VisitorPasswordInitial()) {
on<SelectUsageFrequency>(selectUsageFrequency);
on<FetchDevice>(_onFetchDevice);
@ -37,8 +38,7 @@ class VisitorPasswordBloc
final TextEditingController deviceNameController = TextEditingController();
final TextEditingController deviceIdController = TextEditingController();
final TextEditingController unitNameController = TextEditingController();
final TextEditingController virtualAddressController =
TextEditingController();
final TextEditingController virtualAddressController = TextEditingController();
List<String> selectedDevices = [];
List<DeviceModel> data = [];
@ -62,15 +62,13 @@ class VisitorPasswordBloc
String startTimeAccess = 'Start Time';
String endTimeAccess = 'End Time';
selectAccessType(
SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
PasswordStatus? passwordStatus;
selectAccessType(SelectPasswordType event, Emitter<VisitorPasswordState> emit) {
accessTypeSelected = event.type;
emit(PasswordTypeSelected(event.type));
}
selectUsageFrequency(
SelectUsageFrequency event, Emitter<VisitorPasswordState> emit) {
selectUsageFrequency(SelectUsageFrequency event, Emitter<VisitorPasswordState> emit) {
usageFrequencySelected = event.usageType;
emit(UsageFrequencySelected(event.usageType));
}
@ -117,12 +115,10 @@ class VisitorPasswordBloc
timePicked.minute,
);
final selectedTimestamp =
selectedDateTime.millisecondsSinceEpoch ~/ 1000;
final selectedTimestamp = selectedDateTime.millisecondsSinceEpoch ~/ 1000;
if (event.isStart) {
if (expirationTimeTimeStamp != null &&
selectedTimestamp > expirationTimeTimeStamp!) {
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.',
);
@ -131,8 +127,7 @@ class VisitorPasswordBloc
effectiveTimeTimeStamp = selectedTimestamp;
startTimeAccess = selectedDateTime.toString().split('.').first;
} else {
if (effectiveTimeTimeStamp != null &&
selectedTimestamp < effectiveTimeTimeStamp!) {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.',
);
@ -147,8 +142,7 @@ class VisitorPasswordBloc
}
}
bool toggleRepeat(
ToggleRepeatEvent event, Emitter<VisitorPasswordState> emit) {
bool toggleRepeat(ToggleRepeatEvent event, Emitter<VisitorPasswordState> emit) {
emit(LoadingInitialState());
repeat = !repeat;
emit(IsRepeatState(repeat: repeat));
@ -180,8 +174,7 @@ class VisitorPasswordBloc
emit(ChangeTimeState());
}
Future<void> _onFetchDevice(
FetchDevice event, Emitter<VisitorPasswordState> emit) async {
Future<void> _onFetchDevice(FetchDevice event, Emitter<VisitorPasswordState> emit) async {
try {
emit(DeviceLoaded());
data = await AccessMangApi().fetchDevices();
@ -192,48 +185,43 @@ class VisitorPasswordBloc
}
//online password
Future<void> postOnlineOneTimePassword(OnlineOneTimePasswordEvent event,
Emitter<VisitorPasswordState> emit) async {
Future<void> postOnlineOneTimePassword(
OnlineOneTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
try {
emit(LoadingInitialState());
generate7DigitNumber();
bool res = await AccessMangApi().postOnlineOneTime(
var res = await AccessMangApi().postOnlineOneTime(
email: event.email,
password: passwordController,
devicesUuid: selectedDevices,
passwordName: event.passwordName,
effectiveTime: effectiveTimeTimeStamp.toString(),
invalidTime: expirationTimeTimeStamp.toString());
if (res == true) {
if (res['statusCode'] == 201) {
passwordStatus = PasswordStatus.fromJson(res['data']);
emit(SuccessState());
} else {
throw Exception('Failed to create password');
}
emit(TableLoaded(data));
} catch (e) {
emit(FailedState(e.toString()));
Navigator.pop(event.context!);
stateDialog(
context: event.context!,
message: e.toString(),
title: 'Something Wrong');
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
print('errorMessage==$errorData');
emit(FailedState(errorMessage.toString()));
}
}
Future<void> postOnlineMultipleTimePassword(
OnlineMultipleTimePasswordEvent event,
Emitter<VisitorPasswordState> emit) async {
OnlineMultipleTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
try {
emit(LoadingInitialState());
await generate7DigitNumber();
bool res = await AccessMangApi().postOnlineMultipleTime(
var res = await AccessMangApi().postOnlineMultipleTime(
scheduleList: [
if (repeat)
Schedule(
effectiveTime: getTimeFromDateTimeString(expirationTime),
invalidTime:
getTimeFromDateTimeString(effectiveTime).toString(),
invalidTime: getTimeFromDateTimeString(effectiveTime).toString(),
workingDay: selectedDays,
),
],
@ -243,79 +231,66 @@ class VisitorPasswordBloc
email: event.email,
devicesUuid: selectedDevices,
passwordName: event.passwordName);
if (res == true) {
if (res['statusCode'] == 201) {
passwordStatus = PasswordStatus.fromJson(res['data']);
emit(SuccessState());
} else {
throw Exception('Failed to create password');
}
emit(TableLoaded(data));
} catch (e) {
emit(FailedState(e.toString()));
Navigator.pop(event.context!);
stateDialog(
context: event.context!,
message: e.toString(),
title: 'Something Wrong');
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
print('errorMessage==$errorData');
emit(FailedState(errorMessage.toString()));
}
}
//offline password
Future<void> postOfflineOneTimePassword(OfflineOneTimePasswordEvent event,
Emitter<VisitorPasswordState> emit) async {
Future<void> postOfflineOneTimePassword(
OfflineOneTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
try {
emit(LoadingInitialState());
await generate7DigitNumber();
bool res = await AccessMangApi().postOffLineOneTime(
email: event.email,
devicesUuid: selectedDevices,
passwordName: event.passwordName);
if (res == true) {
var res = await AccessMangApi().postOffLineOneTime(
email: event.email, devicesUuid: selectedDevices, passwordName: event.passwordName);
if (res['statusCode'] == 201) {
passwordStatus = PasswordStatus.fromJson(res['data']);
emit(SuccessState());
} else {
throw Exception('Failed to create password');
}
emit(TableLoaded(data));
} catch (e) {
emit(FailedState(e.toString()));
Navigator.pop(event.context!);
stateDialog(
context: event.context!,
message: e.toString(),
title: 'Something Wrong');
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
print('errorMessage==$errorData');
emit(FailedState(errorMessage.toString()));
}
}
Future<void> postOfflineMultipleTimePassword(
OfflineMultipleTimePasswordEvent event,
Emitter<VisitorPasswordState> emit) async {
OfflineMultipleTimePasswordEvent event, Emitter<VisitorPasswordState> emit) async {
try {
emit(LoadingInitialState());
await generate7DigitNumber();
bool res = await AccessMangApi().postOffLineMultipleTime(
var res = await AccessMangApi().postOffLineMultipleTime(
email: event.email,
devicesUuid: selectedDevices,
passwordName: event.passwordName,
invalidTime: expirationTimeTimeStamp.toString(),
effectiveTime: effectiveTimeTimeStamp.toString(),
);
if (res == true) {
if (res['statusCode'] == 201) {
passwordStatus = PasswordStatus.fromJson(res['data']);
emit(SuccessState());
} else {
throw Exception('Failed to create password');
}
emit(TableLoaded(data));
} catch (e) {
emit(FailedState(e.toString()));
Navigator.pop(event.context!);
stateDialog(
context: event.context!,
message: e.toString(),
title: 'Something Wrong');
} on DioException catch (e) {
final errorData = e.response!.data;
String errorMessage = errorData['message'];
print('errorMessage==$errorData');
emit(FailedState(errorMessage.toString()));
}
}
void selectDevice(
SelectDeviceEvent event, Emitter<VisitorPasswordState> emit) {
void selectDevice(SelectDeviceEvent event, Emitter<VisitorPasswordState> emit) {
if (selectedDeviceIds.contains(event.deviceId)) {
selectedDeviceIds.remove(event.deviceId);
} else {
@ -358,8 +333,7 @@ class VisitorPasswordBloc
}
@override
Stream<VisitorPasswordState> mapEventToState(
VisitorPasswordEvent event) async* {
Stream<VisitorPasswordState> mapEventToState(VisitorPasswordEvent event) async* {
if (event is FetchDevice) {
} else if (event is UpdateFilteredDevicesEvent) {
yield TableLoaded(event.filteredData);
@ -407,27 +381,20 @@ class VisitorPasswordBloc
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isEffective) {
if (expirationTimeTimeStamp != null &&
selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
} else {
effectiveTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
effectiveTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
} else {
if (effectiveTimeTimeStamp != null &&
selectedTimestamp < effectiveTimeTimeStamp!) {
if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Expiration Time cannot be earlier than Effective Time.');
} else {
expirationTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
expirationTime =
selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp;
}
}
@ -468,23 +435,26 @@ class VisitorPasswordBloc
return null;
}
Future<void> stateDialog({
Future stateDialog({
BuildContext? context,
String? message,
String? title,
dynamic actions,
Widget? widgeta,
}) {
return showCustomDialog(
barrierDismissible: false,
context: context!,
message: message!,
iconPath: Assets.deviceNoteIcon,
title: title,
dialogHeight: 150,
widget: widgeta,
dialogHeight: MediaQuery.of(context).size.height * 0.3,
actions: actions ??
<Widget>[
TextButton(
onPressed: () {
Navigator.of(context).pop();
Navigator.of(context).pop(true);
},
child: const Text('OK'),
),

View File

@ -1,6 +1,6 @@
import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/constants/const.dart';
import 'package:syncrow_web/utils/enum/device_types.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
class DeviceModel {
dynamic productUuid;
@ -54,8 +54,7 @@ class DeviceModel {
if (type == DeviceType.LightBulb) {
tempIcon = Assets.lightBulb;
} else if (type == DeviceType.CeilingSensor ||
type == DeviceType.WallSensor) {
} else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
tempIcon = Assets.sensors;
} else if (type == DeviceType.AC) {
tempIcon = Assets.ac;

View File

@ -0,0 +1,124 @@
class FailedOperation {
final bool success;
final dynamic deviceUuid;
final dynamic error;
FailedOperation({
required this.success,
required this.deviceUuid,
required this.error,
});
factory FailedOperation.fromJson(Map<String, dynamic> json) {
return FailedOperation(
success: json['success'],
deviceUuid: json['deviceUuid'],
error: json['error'],
);
}
Map<String, dynamic> toJson() {
return {
'success': success,
'deviceUuid': deviceUuid,
'error': error,
};
}
}
class SuccessOperation {
final bool success;
// final Result result;
final String deviceUuid;
SuccessOperation({
required this.success,
// required this.result,
required this.deviceUuid,
});
factory SuccessOperation.fromJson(Map<String, dynamic> json) {
return SuccessOperation(
success: json['success'],
// result: Result.fromJson(json['result']),
deviceUuid: json['deviceUuid'],
);
}
Map<String, dynamic> toJson() {
return {
'success': success,
// 'result': result.toJson(),
'deviceUuid': deviceUuid,
};
}
}
// class Result {
// final dynamic effectiveTime;
// final dynamic invalidTime;
// final dynamic offlineTempPassword;
// final dynamic offlineTempPasswordId;
// final dynamic offlineTempPasswordName;
//
// Result({
// required this.effectiveTime,
// required this.invalidTime,
// required this.offlineTempPassword,
// required this.offlineTempPasswordId,
// required this.offlineTempPasswordName,
// });
//
// factory Result.fromJson(Map<String, dynamic> json) {
// return Result(
// effectiveTime: json['effective_time'],
// invalidTime: json['invalid_time'],
// offlineTempPassword: json['offline_temp_password'].toString(),
// offlineTempPasswordId: json['offline_temp_password_id'],
// offlineTempPasswordName: json['offline_temp_password_name'],
// );
// }
//
// Map<String, dynamic> toJson() {
// return {
// 'effective_time': effectiveTime,
// 'invalid_time': invalidTime,
// 'offline_temp_password': offlineTempPassword,
// 'offline_temp_password_id': offlineTempPasswordId,
// 'offline_temp_password_name': offlineTempPasswordName,
// };
// }
// }
class PasswordStatus {
final List<SuccessOperation> successOperations;
final List<FailedOperation> failedOperations;
PasswordStatus({
required this.successOperations,
required this.failedOperations,
});
factory PasswordStatus.fromJson(Map<String, dynamic> json) {
return PasswordStatus(
successOperations: (json['successOperations'] as List)
.map((i) => SuccessOperation.fromJson(i))
.toList(),
failedOperations: (json['failedOperations'] as List)
.map((i) => FailedOperation.fromJson(i))
.toList(),
);
}
Map<String, dynamic> toJson() {
return {
'successOperations': successOperations.map((e) => e.toJson()).toList(),
'failedOperations': failedOperations.map((e) => e.toJson()).toList(),
};
}
}

View File

@ -9,7 +9,7 @@ import 'package:syncrow_web/pages/visitor_password/bloc/visitor_password_event.d
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/constants/const.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
import 'package:syncrow_web/utils/style.dart';
class AddDeviceDialog extends StatelessWidget {

View File

@ -20,21 +20,75 @@ class VisitorPasswordDialog extends StatelessWidget {
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
var text = Theme.of(context)
.textTheme
.bodySmall!
.copyWith(color: Colors.black, fontSize: 13);
var text = Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black, fontSize: 13);
return BlocProvider(
create: (context) => VisitorPasswordBloc(),
child: BlocListener<VisitorPasswordBloc, VisitorPasswordState>(
listener: (context, state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
if (state is SuccessState) {
visitorBloc.stateDialog(
context: context,
message: 'Password Created Successfully',
title: 'Send Success',
);
visitorBloc
.stateDialog(
context: context,
message: 'Password Created Successfully',
title: 'Send Success',
widgeta: Column(
children: [
if (visitorBloc.passwordStatus!.failedOperations.isNotEmpty)
Column(
children: [
const Text('Failed Devises'),
SizedBox(
width: 200,
height: 50,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: visitorBloc.passwordStatus!.failedOperations.length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.all(5),
decoration: containerDecoration,
height: 45,
child: Center(
child: Text(visitorBloc
.passwordStatus!.failedOperations[index].deviceUuid)),
);
},
),
),
],
),
if (visitorBloc.passwordStatus!.successOperations.isNotEmpty)
Column(
children: [
const Text('Success Devises'),
SizedBox(
width: 200,
height: 50,
child: ListView.builder(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: visitorBloc.passwordStatus!.successOperations.length,
itemBuilder: (context, index) {
return Container(
margin: EdgeInsets.all(5),
decoration: containerDecoration,
height: 45,
child: Center(
child: Text(visitorBloc.passwordStatus!
.successOperations[index].deviceUuid)),
);
},
),
),
],
),
],
))
.then((v) {
Navigator.of(context).pop();
});
} else if (state is FailedState) {
visitorBloc.stateDialog(
context: context,
@ -46,16 +100,15 @@ class VisitorPasswordDialog extends StatelessWidget {
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
builder: (BuildContext context, VisitorPasswordState state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
bool isRepeat =
state is IsRepeatState ? state.repeat : visitorBloc.repeat;
bool isRepeat = state is IsRepeatState ? state.repeat : visitorBloc.repeat;
return AlertDialog(
backgroundColor: Colors.white,
title: Text(
'Create visitor password',
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
fontWeight: FontWeight.w400,
fontSize: 24,
color: Colors.black),
style: Theme.of(context)
.textTheme
.headlineLarge!
.copyWith(fontWeight: FontWeight.w400, fontSize: 24, color: Colors.black),
),
content: state is LoadingInitialState
? const Center(child: CircularProgressIndicator())
@ -73,8 +126,7 @@ class VisitorPasswordDialog extends StatelessWidget {
flex: 2,
child: CustomWebTextField(
validator: visitorBloc.validate,
controller:
visitorBloc.userNameController,
controller: visitorBloc.userNameController,
isRequired: true,
textFieldName: 'Name',
description: '',
@ -116,95 +168,111 @@ class VisitorPasswordDialog extends StatelessWidget {
),
Row(
children: <Widget>[
Flexible(
child: RadioListTile<String>(
contentPadding: EdgeInsets.zero,
title: Text(
'Online Password',
style: text,
),
value: 'Online Password',
groupValue: (state
is PasswordTypeSelected)
? state.selectedType
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(
value));
}
},
),
),
Flexible(
child: RadioListTile<String>(
contentPadding: EdgeInsets.zero,
title: Text('Offline Password',
style: text),
value: 'Offline Password',
groupValue: (state
is PasswordTypeSelected)
? state.selectedType
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(
value));
}
},
),
),
Flexible(
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 = '';
}
},
),
Expanded(
flex: 2,
child: Row(
children: [
SizedBox(
width: size.width * 0.12,
child: RadioListTile<String>(
contentPadding: EdgeInsets.zero,
title: Text(
'Online Password',
style: text,
),
value: 'Online Password',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
}
},
),
),
SizedBox(
width: size.width * 0.12,
child: RadioListTile<String>(
contentPadding: EdgeInsets.zero,
title: Text('Offline Password', style: text),
value: 'Offline Password',
groupValue: (state is PasswordTypeSelected)
? state.selectedType
: visitorBloc.accessTypeSelected,
onChanged: (String? value) {
if (value != null) {
context
.read<VisitorPasswordBloc>()
.add(SelectPasswordType(value));
}
},
),
),
SizedBox(
width: size.width * 0.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(
flex: 2,
),
],
),
Text(
'Only currently online devices can be selected. It is recommended to use when the device network is stable, and the system randomly generates a digital password',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontWeight: FontWeight.w400,
color: ColorsManager.grayColor,
fontSize: 9),
),
if (visitorBloc.accessTypeSelected == 'Online Password')
Text(
'Only currently online devices can be selected. It is recommended to use when the device network is stable, and the system randomly generates a digital password',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontWeight: FontWeight.w400,
color: ColorsManager.grayColor,
fontSize: 9),
),
if (visitorBloc.accessTypeSelected == 'Offline Password')
Text(
'Unaffected by the online status of the device, you can select online or offline device, and 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,
)
],
),
visitorBloc.accessTypeSelected ==
'Dynamic Password'
visitorBloc.accessTypeSelected == 'Dynamic Password'
? const SizedBox()
: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
@ -223,7 +291,8 @@ class VisitorPasswordDialog extends StatelessWidget {
),
Row(
children: <Widget>[
Flexible(
SizedBox(
width: size.width * 0.12,
child: RadioListTile<String>(
contentPadding: EdgeInsets.zero,
title: Text(
@ -231,88 +300,113 @@ class VisitorPasswordDialog extends StatelessWidget {
style: text,
),
value: 'One-Time',
groupValue: (state
is UsageFrequencySelected)
groupValue: (state is UsageFrequencySelected)
? state.selectedFrequency
: visitorBloc
.usageFrequencySelected,
: visitorBloc.usageFrequencySelected,
onChanged: (String? value) {
if (value != null) {
context
.read<
VisitorPasswordBloc>()
.add(
SelectUsageFrequency(
value));
.read<VisitorPasswordBloc>()
.add(SelectUsageFrequency(value));
}
},
),
),
Flexible(
SizedBox(
width: size.width * 0.12,
child: RadioListTile<String>(
contentPadding: EdgeInsets.zero,
title: Text('Periodic',
style: text),
title: Text('Periodic', style: text),
value: 'Periodic',
groupValue: (state
is UsageFrequencySelected)
groupValue: (state is UsageFrequencySelected)
? state.selectedFrequency
: visitorBloc
.usageFrequencySelected,
: visitorBloc.usageFrequencySelected,
onChanged: (String? value) {
if (value != null) {
context
.read<
VisitorPasswordBloc>()
.add(
SelectUsageFrequency(
value));
.read<VisitorPasswordBloc>()
.add(SelectUsageFrequency(value));
}
},
),
),
],
),
Text(
'Within the validity period, each device can be unlocked only once.',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
color:
ColorsManager.grayColor,
fontSize: 9),
)
//One-Time
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.accessTypeSelected == 'Online Password')
Text(
'Within the validity period, each device can be unlocked only once.',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, fontSize: 9),
),
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.',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, fontSize: 9),
),
// Periodic
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password')
Text(
'Within the validity period, there is no limit to the number of times each device can be unlocked, and it should be used at least once within 24 hours after the entry into force.',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, fontSize: 9),
),
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Online Password')
Text(
'Within the validity period, there is no limit to the number of times each device can be unlocked.',
style: Theme.of(context).textTheme.bodySmall!.copyWith(
color: ColorsManager.grayColor, fontSize: 9),
),
],
),
const SizedBox(
height: 20,
),
if ((visitorBloc.usageFrequencySelected !=
'One-Time' ||
visitorBloc.accessTypeSelected !=
'Offline Password') &&
if ((visitorBloc.usageFrequencySelected != 'One-Time' ||
visitorBloc.accessTypeSelected != 'Offline Password') &&
(visitorBloc.usageFrequencySelected != ''))
DateTimeWebWidget(
isRequired: true,
title: 'Access Period',
size: size,
endTime: () {
visitorBloc.add(SelectTimeVisitorPassword(
context: context,
isStart: false,
isRepeat: false));
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
visitorBloc.add(
SelectTimeEvent(context: context, isEffective: false));
} else {
visitorBloc.add(SelectTimeVisitorPassword(
context: context, isStart: false, isRepeat: false));
}
},
startTime: () {
visitorBloc.add(SelectTimeVisitorPassword(
context: context,
isStart: true,
isRepeat: false));
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
visitorBloc.add(
SelectTimeEvent(context: context, isEffective: true));
} else {
visitorBloc.add(SelectTimeVisitorPassword(
context: context, isStart: true, isRepeat: false));
}
},
firstString:
visitorBloc.startTimeAccess.toString(),
secondString:
visitorBloc.endTimeAccess.toString(),
firstString: (visitorBloc.usageFrequencySelected ==
'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password')
? visitorBloc.effectiveTime
: visitorBloc.startTimeAccess.toString(),
secondString: (visitorBloc.usageFrequencySelected ==
'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password')
? visitorBloc.expirationTime
: visitorBloc.endTimeAccess.toString(),
icon: Assets.calendarIcon),
const SizedBox(
height: 20,
@ -337,21 +431,16 @@ class VisitorPasswordDialog extends StatelessWidget {
),
Text(
'Within the validity period, each device can be unlocked only once.',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontWeight: FontWeight.w400,
color: ColorsManager.grayColor,
fontSize: 9),
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontWeight: FontWeight.w400,
color: ColorsManager.grayColor,
fontSize: 9),
),
const SizedBox(
height: 20,
),
if (visitorBloc.usageFrequencySelected ==
'Periodic' &&
visitorBloc.accessTypeSelected ==
'Online Password')
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Online Password')
SizedBox(
width: 100,
child: Column(
@ -362,8 +451,7 @@ class VisitorPasswordDialog extends StatelessWidget {
child: CupertinoSwitch(
value: visitorBloc.repeat,
onChanged: (value) {
visitorBloc
.add(ToggleRepeatEvent());
visitorBloc.add(ToggleRepeatEvent());
},
applyTheme: true,
),
@ -371,13 +459,9 @@ class VisitorPasswordDialog extends StatelessWidget {
],
),
),
if (visitorBloc.usageFrequencySelected ==
'Periodic' &&
visitorBloc.accessTypeSelected ==
'Online Password')
isRepeat
? const RepeatWidget()
: const SizedBox(),
if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == 'Online Password')
isRepeat ? const RepeatWidget() : const SizedBox(),
Container(
decoration: containerDecoration,
width: size.width / 9,
@ -388,28 +472,22 @@ class VisitorPasswordDialog extends StatelessWidget {
barrierDismissible: false,
builder: (BuildContext context) {
return AddDeviceDialog(
selectedDeviceIds:
visitorBloc.selectedDevices,
selectedDeviceIds: visitorBloc.selectedDevices,
);
},
).then((listDevice) {
if (listDevice != null) {
visitorBloc.selectedDevices =
listDevice;
visitorBloc.selectedDevices = listDevice;
}
});
},
borderRadius: 8,
child: Text(
'+ Add Device',
style: Theme.of(context)
.textTheme
.bodySmall!
.copyWith(
fontWeight: FontWeight.w400,
color:
ColorsManager.whiteColors,
fontSize: 12),
style: Theme.of(context).textTheme.bodySmall!.copyWith(
fontWeight: FontWeight.w400,
color: ColorsManager.whiteColors,
fontSize: 12),
),
),
),
@ -447,15 +525,36 @@ class VisitorPasswordDialog extends StatelessWidget {
onPressed: () {
if (visitorBloc.forgetFormKey.currentState!.validate()) {
if (visitorBloc.selectedDevices.isNotEmpty) {
if (visitorBloc.effectiveTimeTimeStamp != null &&
visitorBloc.expirationTimeTimeStamp != null) {
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.accessTypeSelected == 'Offline Password') {
setPasswordFunction(context, size, visitorBloc);
} else if (visitorBloc.accessTypeSelected == 'Dynamic Password') {
print('objectobjectobjectobject');
setPasswordFunction(context, size, visitorBloc);
} else {
visitorBloc.stateDialog(
context: context,
message:
'Please select Access Period to continue',
title: 'Access Period');
if (visitorBloc.effectiveTimeTimeStamp != null &&
visitorBloc.expirationTimeTimeStamp != null) {
if (isRepeat == true) {
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');
}
}
} else {
visitorBloc.stateDialog(
@ -465,6 +564,57 @@ 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',
@ -501,8 +651,7 @@ class VisitorPasswordDialog extends StatelessWidget {
content: SizedBox(
height: size.height * 0.25,
child: Center(
child:
CircularProgressIndicator(), // Display a loading spinner
child: CircularProgressIndicator(), // Display a loading spinner
),
),
);
@ -526,10 +675,7 @@ class VisitorPasswordDialog extends StatelessWidget {
),
Text(
'Set Password',
style: Theme.of(context)
.textTheme
.headlineLarge!
.copyWith(
style: Theme.of(context).textTheme.headlineLarge!.copyWith(
fontSize: 30,
fontWeight: FontWeight.w400,
color: Colors.black,
@ -578,47 +724,39 @@ class VisitorPasswordDialog extends StatelessWidget {
borderRadius: 8,
onPressed: () {
Navigator.pop(context);
if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.accessTypeSelected ==
'Online Password') {
visitorBloc.add(OnlineOneTimePasswordEvent(
context: context,
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
));
} else if (visitorBloc.usageFrequencySelected ==
'Periodic' &&
visitorBloc.accessTypeSelected ==
'Online Password') {
visitorBloc.add(OnlineMultipleTimePasswordEvent(
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
effectiveTime:
visitorBloc.effectiveTimeTimeStamp.toString(),
invalidTime:
visitorBloc.expirationTimeTimeStamp.toString(),
));
} else if (visitorBloc.usageFrequencySelected ==
'One-Time' &&
visitorBloc.accessTypeSelected ==
'Offline Password') {
visitorBloc.add(OfflineOneTimePasswordEvent(
context: context,
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
));
} else if (visitorBloc.usageFrequencySelected ==
'Periodic' &&
visitorBloc.accessTypeSelected ==
'Offline Password') {
visitorBloc.add(OfflineMultipleTimePasswordEvent(
passwordName: visitorBloc.userNameController.text,
email: visitorBloc.emailController.text,
effectiveTime:
visitorBloc.effectiveTimeTimeStamp.toString(),
invalidTime:
visitorBloc.expirationTimeTimeStamp.toString(),
));
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(),
));
}
}
},
child: Text(

View File

@ -1,5 +1,4 @@
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:syncrow_web/pages/access_management/model/password_model.dart';
import 'package:syncrow_web/pages/visitor_password/model/device_model.dart';
@ -48,39 +47,29 @@ class AccessMangApi {
}
}
Future<bool> postOnlineOneTime(
Future postOnlineOneTime(
{String? email,
String? passwordName,
String? password,
String? effectiveTime,
String? invalidTime,
List<String>? devicesUuid}) async {
try {
final response = await HTTPService().post(
path: ApiEndpoints.sendOnlineOneTime,
body: jsonEncode({
"email": email,
"passwordName": passwordName,
"password": password,
"devicesUuid": devicesUuid,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime
}),
showServerMessage: true,
expectedResponseModel: (json) {
if (json['statusCode'].toString() == '201') {
return true;
} else {
return false;
}
},
);
return response;
} on DioException catch (e) {
debugPrint('Error: ${e.message}');
debugPrint('Error fetching ${e.response!.statusMessage}');
return false;
}
final response = await HTTPService().post(
path: ApiEndpoints.sendOnlineOneTime,
body: jsonEncode({
"email": email,
"passwordName": passwordName,
"password": password,
"devicesUuid": devicesUuid,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime
}),
showServerMessage: true,
expectedResponseModel: (json) {
return json;
},
);
return response;
}
Future postOnlineMultipleTime(
@ -91,66 +80,41 @@ class AccessMangApi {
String? passwordName,
List<Schedule>? scheduleList,
List<String>? devicesUuid}) async {
try {
Map<String, dynamic> body = {
"email": email,
"devicesUuid": devicesUuid,
"passwordName": passwordName,
"password": password,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime,
};
if (scheduleList != null) {
body["scheduleList"] =
scheduleList.map((schedule) => schedule.toJson()).toList();
}
final response = await HTTPService().post(
path: ApiEndpoints.sendOnlineMultipleTime,
body: jsonEncode(body),
showServerMessage: true,
expectedResponseModel: (json) {
if (json['data']['successOperations'][0]['success'].toString() ==
'true') {
return true;
} else {
return false;
}
},
);
return response;
} on DioException catch (e) {
debugPrint('Error fetching ${e.type.name}');
debugPrint('Error fetching ${e.response!.statusMessage}');
return false;
Map<String, dynamic> body = {
"email": email,
"devicesUuid": devicesUuid,
"passwordName": passwordName,
"password": password,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime,
};
if (scheduleList != null) {
body["scheduleList"] = scheduleList.map((schedule) => schedule.toJson()).toList();
}
final response = await HTTPService().post(
path: ApiEndpoints.sendOnlineMultipleTime,
body: jsonEncode(body),
showServerMessage: true,
expectedResponseModel: (json) {
return json;
},
);
return response;
}
// OffLine One Time Password
Future postOffLineOneTime(
{String? email, String? passwordName, List<String>? devicesUuid}) async {
try {
final response = await HTTPService().post(
path: ApiEndpoints.sendOffLineOneTime,
body: jsonEncode({
"email": email,
"passwordName": passwordName,
"devicesUuid": devicesUuid
}),
showServerMessage: true,
expectedResponseModel: (json) {
if (json['data']['successOperations'][0]['success'].toString() ==
'true') {
return true;
} else {
return false;
}
});
return response;
} catch (e) {
debugPrint('Error fetching $e');
return [];
}
final response = await HTTPService().post(
path: ApiEndpoints.sendOffLineOneTime,
body: jsonEncode({"email": email, "passwordName": passwordName, "devicesUuid": devicesUuid}),
showServerMessage: true,
expectedResponseModel: (json) {
return json;
},
);
return response;
}
Future postOffLineMultipleTime(
@ -159,29 +123,27 @@ class AccessMangApi {
String? effectiveTime,
String? invalidTime,
List<String>? devicesUuid}) async {
try {
final response = await HTTPService().post(
path: ApiEndpoints.sendOffLineOneTime,
body: jsonEncode({
"email": email,
"devicesUuid": devicesUuid,
"passwordName": passwordName,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime
}),
showServerMessage: true,
expectedResponseModel: (json) {
if (json['data']['successOperations'][0]['success'].toString() ==
'true') {
return true;
} else {
return false;
}
});
return response;
} catch (e) {
debugPrint('Error fetching $e');
return [];
}
print(jsonEncode({
"email": email,
"devicesUuid": devicesUuid,
"passwordName": passwordName,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime,
}));
final response = await HTTPService().post(
path: ApiEndpoints.sendOffLineMultipleTime,
body: jsonEncode({
"email": email,
"devicesUuid": devicesUuid,
"passwordName": passwordName,
"effectiveTime": effectiveTime,
"invalidTime": invalidTime,
}),
showServerMessage: true,
expectedResponseModel: (json) {
return json;
},
);
return response;
}
}

View File

@ -29,17 +29,17 @@ class AuthenticationAPI {
return response;
}
static Future<int?> sendOtp(
{required String email, required String regionUuid}) async {
static Future<int?> sendOtp({required String email, required String regionUuid}) async {
try {
final response = await HTTPService().post(
path: ApiEndpoints.sendOtp,
body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid},
showServerMessage: true,
expectedResponseModel: (json) {
return 30;
return json['data']['cooldown'];
});
return 30;
return response;
} on DioException catch (e) {
if (e.response != null) {
if (e.response!.statusCode == 400) {
@ -52,8 +52,7 @@ class AuthenticationAPI {
return cooldown;
}
} else {
debugPrint(
'Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
return 1;
}
} else {
@ -66,8 +65,7 @@ class AuthenticationAPI {
}
}
static Future verifyOtp(
{required String email, required String otpCode}) async {
static Future verifyOtp({required String email, required String otpCode}) async {
try {
final response = await HTTPService().post(
path: ApiEndpoints.verifyOtp,
@ -99,9 +97,7 @@ class AuthenticationAPI {
path: ApiEndpoints.getRegion,
showServerMessage: true,
expectedResponseModel: (json) {
return (json as List)
.map((zone) => RegionModel.fromJson(zone))
.toList();
return (json as List).map((zone) => RegionModel.fromJson(zone)).toList();
});
return response;
}

34
lib/utils/app_routes.dart Normal file
View File

@ -0,0 +1,34 @@
import 'package:go_router/go_router.dart';
import 'package:syncrow_web/pages/access_management/view/access_management.dart';
import 'package:syncrow_web/pages/auth/view/login_page.dart';
import 'package:syncrow_web/pages/device_managment/all_devices/view/device_managment_page.dart';
import 'package:syncrow_web/pages/home/view/home_page.dart';
import 'package:syncrow_web/pages/visitor_password/view/visitor_password_dialog.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
class AppRoutes {
static List<GoRoute> getRoutes() {
return [
GoRoute(
path: RoutesConst.auth,
builder: (context, state) => const LoginPage(),
),
GoRoute(
path: RoutesConst.home,
builder: (context, state) => const HomePage(),
),
GoRoute(
path: RoutesConst.visitorPassword,
builder: (context, state) => const VisitorPasswordDialog(),
),
GoRoute(
path: RoutesConst.accessManagementPage,
builder: (context, state) => const AccessManagementPage(),
),
GoRoute(
path: RoutesConst.deviceManagementPage,
builder: (context, state) => const DeviceManagementPage(),
),
];
}
}

View File

@ -36,4 +36,11 @@ abstract class ColorsManager {
static const Color blueColor = Color(0xFF0036E6);
static const Color boxColor = Color(0xFFF5F6F7);
static const Color boxDivider = Color(0xFFE0E0E0);
static const Color blue1 = Color(0xFF0036E6);
static const Color blue2 = Color(0xFF0026A2);
static const Color blue3 = Color(0xFF00165E);
static const Color blue4 = Color(0xFF001E7E);
static const Color textGreen = Color(0xFF008905);
static const Color yaGreen = Color(0xFFFFBF44);
}
//0036E6

View File

@ -13,12 +13,10 @@ class Assets {
static const String rightLine = "assets/images/right_line.png";
static const String google = "assets/images/google.svg";
static const String facebook = "assets/images/facebook.svg";
static const String invisiblePassword =
"assets/images/Password_invisible.svg";
static const String invisiblePassword = "assets/images/Password_invisible.svg";
static const String visiblePassword = "assets/images/Password_visible.svg";
static const String accessIcon = "assets/images/access_icon.svg";
static const String spaseManagementIcon =
"assets/images/spase_management_icon.svg";
static const String spaseManagementIcon = "assets/images/spase_management_icon.svg";
static const String devicesIcon = "assets/images/devices_icon.svg";
static const String moveinIcon = "assets/images/movein_icon.svg";
static const String constructionIcon = "assets/images/construction_icon.svg";
@ -31,15 +29,13 @@ class Assets {
static const String emptyTable = "assets/images/empty_table.svg";
// General assets
static const String motionlessDetection =
"assets/icons/motionless_detection.svg";
static const String motionlessDetection = "assets/icons/motionless_detection.svg";
static const String acHeating = "assets/icons/ac_heating.svg";
static const String acPowerOff = "assets/icons/ac_power_off.svg";
static const String acFanMiddle = "assets/icons/ac_fan_middle.svg";
static const String switchAlarmSound = "assets/icons/switch_alarm_sound.svg";
static const String resetOff = "assets/icons/reset_off.svg";
static const String sensitivityOperationIcon =
"assets/icons/sesitivity_operation_icon.svg";
static const String sensitivityOperationIcon = "assets/icons/sesitivity_operation_icon.svg";
static const String motionDetection = "assets/icons/motion_detection.svg";
static const String freezing = "assets/icons/freezing.svg";
static const String indicator = "assets/icons/indicator.svg";
@ -60,8 +56,7 @@ class Assets {
static const String celsiusDegrees = "assets/icons/celsius_degrees.svg";
static const String masterState = "assets/icons/master_state.svg";
static const String acPower = "assets/icons/ac_power.svg";
static const String farDetectionFunction =
"assets/icons/far_detection_function.svg";
static const String farDetectionFunction = "assets/icons/far_detection_function.svg";
static const String nobodyTime = "assets/icons/nobody_time.svg";
// Automation functions
@ -69,47 +64,33 @@ class Assets {
"assets/icons/automation_functions/temp_password_unlock.svg";
static const String doorlockNormalOpen =
"assets/icons/automation_functions/doorlock_normal_open.svg";
static const String doorbell =
"assets/icons/automation_functions/doorbell.svg";
static const String doorbell = "assets/icons/automation_functions/doorbell.svg";
static const String remoteUnlockViaApp =
"assets/icons/automation_functions/remote_unlock_via_app.svg";
static const String doubleLock =
"assets/icons/automation_functions/double_lock.svg";
static const String selfTestResult =
"assets/icons/automation_functions/self_test_result.svg";
static const String lockAlarm =
"assets/icons/automation_functions/lock_alarm.svg";
static const String presenceState =
"assets/icons/automation_functions/presence_state.svg";
static const String currentTemp =
"assets/icons/automation_functions/current_temp.svg";
static const String presence =
"assets/icons/automation_functions/presence.svg";
static const String doubleLock = "assets/icons/automation_functions/double_lock.svg";
static const String selfTestResult = "assets/icons/automation_functions/self_test_result.svg";
static const String lockAlarm = "assets/icons/automation_functions/lock_alarm.svg";
static const String presenceState = "assets/icons/automation_functions/presence_state.svg";
static const String currentTemp = "assets/icons/automation_functions/current_temp.svg";
static const String presence = "assets/icons/automation_functions/presence.svg";
static const String residualElectricity =
"assets/icons/automation_functions/residual_electricity.svg";
static const String hijackAlarm =
"assets/icons/automation_functions/hijack_alarm.svg";
static const String passwordUnlock =
"assets/icons/automation_functions/password_unlock.svg";
static const String hijackAlarm = "assets/icons/automation_functions/hijack_alarm.svg";
static const String passwordUnlock = "assets/icons/automation_functions/password_unlock.svg";
static const String remoteUnlockRequest =
"assets/icons/automation_functions/remote_unlock_req.svg";
static const String cardUnlock =
"assets/icons/automation_functions/card_unlock.svg";
static const String cardUnlock = "assets/icons/automation_functions/card_unlock.svg";
static const String motion = "assets/icons/automation_functions/motion.svg";
static const String fingerprintUnlock =
"assets/icons/automation_functions/fingerprint_unlock.svg";
// Presence Sensor Assets
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
static const String sensorPresenceIcon =
"assets/icons/sensor_presence_ic.svg";
static const String sensorPresenceIcon = "assets/icons/sensor_presence_ic.svg";
static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg";
static const String illuminanceRecordIcon =
"assets/icons/illuminance_record_ic.svg";
static const String presenceRecordIcon =
"assets/icons/presence_record_ic.svg";
static const String helpDescriptionIcon =
"assets/icons/help_description_ic.svg";
static const String illuminanceRecordIcon = "assets/icons/illuminance_record_ic.svg";
static const String presenceRecordIcon = "assets/icons/presence_record_ic.svg";
static const String helpDescriptionIcon = "assets/icons/help_description_ic.svg";
static const String lightPulp = "assets/icons/light_pulb.svg";
static const String acDevice = "assets/icons/ac_device.svg";
@ -142,4 +123,5 @@ class Assets {
static const String dyi = 'assets/icons/dyi.svg';
static const String office = 'assets/icons/office.svg';
static const String parlour = 'assets/icons/parlour.svg';
static const String grid = "assets/images/grid.svg";
}

View File

@ -0,0 +1,7 @@
class RoutesConst {
static const String auth = '/login';
static const String home = '/';
static const String visitorPassword = '/visitor-password';
static const String accessManagementPage = '/access-management-page';
static const String deviceManagementPage = '/device-management-page';
}

View File

@ -5,3 +5,6 @@ class NavigationService {
static GlobalKey<ScaffoldMessengerState>? snackbarKey =
GlobalKey<ScaffoldMessengerState>();
}