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

18
assets/images/grid.svg Normal file
View File

@ -0,0 +1,18 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1423_2976)">
<path d="M4.5 17.5004H2C1.46957 17.5004 0.960859 17.7111 0.585786 18.0862C0.210714 18.4612 0 18.9699 0 19.5004L0 22.0004C0 22.5308 0.210714 23.0395 0.585786 23.4146C0.960859 23.7896 1.46957 24.0004 2 24.0004H4.5C5.03043 24.0004 5.53914 23.7896 5.91421 23.4146C6.28929 23.0395 6.5 22.5308 6.5 22.0004V19.5004C6.5 18.9699 6.28929 18.4612 5.91421 18.0862C5.53914 17.7111 5.03043 17.5004 4.5 17.5004ZM4.5 22.0004H2V19.5004H4.5V22.0004Z" fill="white"/>
<path d="M22 17.5004H19.5C18.9696 17.5004 18.4609 17.7111 18.0858 18.0862C17.7107 18.4612 17.5 18.9699 17.5 19.5004V22.0004C17.5 22.5308 17.7107 23.0395 18.0858 23.4146C18.4609 23.7896 18.9696 24.0004 19.5 24.0004H22C22.5304 24.0004 23.0391 23.7896 23.4142 23.4146C23.7893 23.0395 24 22.5308 24 22.0004V19.5004C24 18.9699 23.7893 18.4612 23.4142 18.0862C23.0391 17.7111 22.5304 17.5004 22 17.5004ZM22 22.0004H19.5V19.5004H22V22.0004Z" fill="white"/>
<path d="M4.5 8.74976H2C1.46957 8.74976 0.960859 8.96047 0.585786 9.33554C0.210714 9.71061 0 10.2193 0 10.7498L0 13.2497C0 13.7802 0.210714 14.2889 0.585786 14.664C0.960859 15.039 1.46957 15.2497 2 15.2497H4.5C5.03043 15.2497 5.53914 15.039 5.91421 14.664C6.28929 14.2889 6.5 13.7802 6.5 13.2497V10.7498C6.5 10.2193 6.28929 9.71061 5.91421 9.33554C5.53914 8.96047 5.03043 8.74976 4.5 8.74976ZM4.5 13.2497H2V10.7498H4.5V13.2497Z" fill="white"/>
<path d="M22 8.74976H19.5C18.9696 8.74976 18.4609 8.96047 18.0858 9.33554C17.7107 9.71061 17.5 10.2193 17.5 10.7498V13.2497C17.5 13.7802 17.7107 14.2889 18.0858 14.664C18.4609 15.039 18.9696 15.2497 19.5 15.2497H22C22.5304 15.2497 23.0391 15.039 23.4142 14.664C23.7893 14.2889 24 13.7802 24 13.2497V10.7498C24 10.2193 23.7893 9.71061 23.4142 9.33554C23.0391 8.96047 22.5304 8.74976 22 8.74976ZM22 13.2497H19.5V10.7498H22V13.2497Z" fill="white"/>
<path d="M4.5 0H2C1.46957 0 0.960859 0.210714 0.585786 0.585786C0.210714 0.960859 0 1.46957 0 2L0 4.5C0 5.03043 0.210714 5.53914 0.585786 5.91421C0.960859 6.28929 1.46957 6.5 2 6.5H4.5C5.03043 6.5 5.53914 6.28929 5.91421 5.91421C6.28929 5.53914 6.5 5.03043 6.5 4.5V2C6.5 1.46957 6.28929 0.960859 5.91421 0.585786C5.53914 0.210714 5.03043 0 4.5 0V0ZM4.5 4.5H2V2H4.5V4.5Z" fill="white"/>
<path d="M13.25 17.5004H10.75C10.2196 17.5004 9.71086 17.7111 9.33579 18.0862C8.96071 18.4612 8.75 18.9699 8.75 19.5004V22.0004C8.75 22.5308 8.96071 23.0395 9.33579 23.4146C9.71086 23.7896 10.2196 24.0004 10.75 24.0004H13.25C13.7804 24.0004 14.2891 23.7896 14.6642 23.4146C15.0393 23.0395 15.25 22.5308 15.25 22.0004V19.5004C15.25 18.9699 15.0393 18.4612 14.6642 18.0862C14.2891 17.7111 13.7804 17.5004 13.25 17.5004ZM13.25 22.0004H10.75V19.5004H13.25V22.0004Z" fill="white"/>
<path d="M13.25 8.74976H10.75C10.2196 8.74976 9.71086 8.96047 9.33579 9.33554C8.96071 9.71061 8.75 10.2193 8.75 10.7498V13.2497C8.75 13.7802 8.96071 14.2889 9.33579 14.664C9.71086 15.039 10.2196 15.2497 10.75 15.2497H13.25C13.7804 15.2497 14.2891 15.039 14.6642 14.664C15.0393 14.2889 15.25 13.7802 15.25 13.2497V10.7498C15.25 10.2193 15.0393 9.71061 14.6642 9.33554C14.2891 8.96047 13.7804 8.74976 13.25 8.74976ZM13.25 13.2497H10.75V10.7498H13.25V13.2497Z" fill="white"/>
<path d="M13.25 0H10.75C10.2196 0 9.71086 0.210714 9.33579 0.585786C8.96071 0.960859 8.75 1.46957 8.75 2V4.5C8.75 5.03043 8.96071 5.53914 9.33579 5.91421C9.71086 6.28929 10.2196 6.5 10.75 6.5H13.25C13.7804 6.5 14.2891 6.28929 14.6642 5.91421C15.0393 5.53914 15.25 5.03043 15.25 4.5V2C15.25 1.46957 15.0393 0.960859 14.6642 0.585786C14.2891 0.210714 13.7804 0 13.25 0V0ZM13.25 4.5H10.75V2H13.25V4.5Z" fill="white"/>
<path d="M22 0H19.5C18.9696 0 18.4609 0.210714 18.0858 0.585786C17.7107 0.960859 17.5 1.46957 17.5 2V4.5C17.5 5.03043 17.7107 5.53914 18.0858 5.91421C18.4609 6.28929 18.9696 6.5 19.5 6.5H22C22.5304 6.5 23.0391 6.28929 23.4142 5.91421C23.7893 5.53914 24 5.03043 24 4.5V2C24 1.46957 23.7893 0.960859 23.4142 0.585786C23.0391 0.210714 22.5304 0 22 0V0ZM22 4.5H19.5V2H22V4.5Z" fill="white"/>
</g>
<defs>
<clipPath id="clip0_1423_2976">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

View File

@ -1,3 +1,4 @@
description: This file stores settings for Dart & Flutter DevTools. description: This file stores settings for Dart & Flutter DevTools.
documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states
extensions: extensions:
- provider: true

View File

@ -2,28 +2,34 @@ import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_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/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: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/services/locator.dart';
import 'package:syncrow_web/utils/app_routes.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
Future<void> main() async { Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized(); WidgetsFlutterBinding.ensureInitialized();
initialSetup(); // Perform initial setup, e.g., dependency injection initialSetup();
String checkToken = await AuthBloc.getTokenAndValidate(); String checkToken = await AuthBloc.getTokenAndValidate();
GoRouter router = GoRouter(
initialLocation: checkToken == 'Success' ? RoutesConst.home : RoutesConst.auth,
routes: AppRoutes.getRoutes(),
);
runApp(MyApp( runApp(MyApp(
isLoggedIn: checkToken, router: router,
)); ));
} }
class MyApp extends StatelessWidget { class MyApp extends StatelessWidget {
final dynamic isLoggedIn; final GoRouter router;
const MyApp({ const MyApp({
super.key, super.key,
required this.isLoggedIn, required this.router,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MultiBlocProvider( return MultiBlocProvider(
@ -33,7 +39,7 @@ class MyApp extends StatelessWidget {
create: (context) => VisitorPasswordBloc(), create: (context) => VisitorPasswordBloc(),
) )
], ],
child: MaterialApp( child: MaterialApp.router(
debugShowCheckedModeBanner: false, // Hide debug banner debugShowCheckedModeBanner: false, // Hide debug banner
scrollBehavior: const MaterialScrollBehavior().copyWith( scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: { dragDevices: {
@ -48,9 +54,7 @@ class MyApp extends StatelessWidget {
fontFamily: 'Aftika', fontFamily: 'Aftika',
textTheme: const TextTheme( textTheme: const TextTheme(
bodySmall: TextStyle( bodySmall: TextStyle(
fontSize: 13, fontSize: 13, color: ColorsManager.whiteColors, fontWeight: FontWeight.bold),
color: ColorsManager.whiteColors,
fontWeight: FontWeight.bold),
bodyMedium: TextStyle(color: Colors.black87, fontSize: 14), bodyMedium: TextStyle(color: Colors.black87, fontSize: 14),
bodyLarge: TextStyle(fontSize: 16, color: Colors.white), bodyLarge: TextStyle(fontSize: 16, color: Colors.white),
headlineSmall: TextStyle(color: Colors.black87, fontSize: 18), headlineSmall: TextStyle(color: Colors.black87, fontSize: 18),
@ -61,47 +65,10 @@ class MyApp extends StatelessWidget {
fontWeight: FontWeight.bold, 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/pages/access_management/model/password_model.dart';
import 'package:syncrow_web/services/access_mang_api.dart'; import 'package:syncrow_web/services/access_mang_api.dart';
import 'package:syncrow_web/utils/color_manager.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'; import 'package:syncrow_web/utils/snack_bar.dart';
class AccessBloc extends Bloc<AccessEvent, AccessState> { class AccessBloc extends Bloc<AccessEvent, AccessState> {
@ -26,8 +26,7 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
List<PasswordModel> filteredData = []; List<PasswordModel> filteredData = [];
List<PasswordModel> data = []; List<PasswordModel> data = [];
Future<void> _onFetchTableData( Future<void> _onFetchTableData(FetchTableData event, Emitter<AccessState> emit) async {
FetchTableData event, Emitter<AccessState> emit) async {
try { try {
emit(AccessLoaded()); emit(AccessLoaded());
data = await AccessMangApi().fetchVisitorPassword(); data = await AccessMangApi().fetchVisitorPassword();
@ -40,28 +39,19 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
void updateTabsCount() { void updateTabsCount() {
int toBeEffectiveCount = data int toBeEffectiveCount =
.where((item) => item.passwordStatus.value == 'To Be Effective') data.where((item) => item.passwordStatus.value == 'To be effective').length;
.length; int effectiveCount = data.where((item) => item.passwordStatus.value == 'Effective').length;
int effectiveCount = int expiredCount = data.where((item) => item.passwordStatus.value == 'Expired').length;
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[1] = 'To Be Effective ($toBeEffectiveCount)';
tabs[2] = 'Effective ($effectiveCount)'; tabs[2] = 'Effective ($effectiveCount)';
tabs[3] = 'Expired ($expiredCount)'; tabs[3] = 'Expired ($expiredCount)';
} }
int selectedIndex = 0; int selectedIndex = 0;
final List<String> tabs = [ final List<String> tabs = ['All', 'To Be Effective (0)', 'Effective (0)', 'Expired'];
'All',
'To Be Effective (0)',
'Effective (0)',
'Expired'
];
Future selectFilterTap( Future selectFilterTap(TabChangedEvent event, Emitter<AccessState> emit) async {
TabChangedEvent event, Emitter<AccessState> emit) async {
try { try {
emit(AccessLoaded()); emit(AccessLoaded());
selectedIndex = event.selectedIndex; selectedIndex = event.selectedIndex;
@ -75,7 +65,6 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async { Future<void> selectTime(SelectTime event, Emitter<AccessState> emit) async {
emit(AccessLoaded()); emit(AccessLoaded());
final DateTime? picked = await showDatePicker( final DateTime? picked = await showDatePicker(
context: event.context, context: event.context,
initialDate: DateTime.now(), initialDate: DateTime.now(),
@ -83,111 +72,112 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
lastDate: DateTime(2101), lastDate: DateTime(2101),
); );
if (picked != null) { if (picked != null) {
final TimeOfDay? timePicked = await showTimePicker( final selectedDateTime = DateTime(
context: event.context, picked.year,
initialTime: TimeOfDay.now(), picked.month,
builder: (context, child) { picked.day,
return Theme(
data: ThemeData.light().copyWith(
colorScheme: const ColorScheme.light(
primary: ColorsManager.primaryColor,
onSurface: Colors.black,
),
buttonTheme: const ButtonThemeData(
colorScheme: ColorScheme.light(
primary: Colors.green,
),
),
),
child: child!,
);
},
); );
if (timePicked != null) { final selectedTimestamp = DateTime(
final selectedDateTime = DateTime( selectedDateTime.year,
picked.year, selectedDateTime.month,
picked.month, selectedDateTime.day,
picked.day, selectedDateTime.hour,
timePicked.hour, selectedDateTime.minute,
timePicked.minute, ).millisecondsSinceEpoch ~/
); 1000; // Divide by 1000 to remove milliseconds
final selectedTimestamp = DateTime( if (event.isStart) {
selectedDateTime.year, if (expirationTimeTimeStamp != null && selectedTimestamp > expirationTimeTimeStamp!) {
selectedDateTime.month, CustomSnackBar.displaySnackBar('Effective Time cannot be later than Expiration Time.');
selectedDateTime.day,
selectedDateTime.hour,
selectedDateTime.minute,
).millisecondsSinceEpoch ~/
1000; // Divide by 1000 to remove milliseconds
if (event.isStart) {
if (expirationTimeTimeStamp != null &&
selectedTimestamp > expirationTimeTimeStamp!) {
CustomSnackBar.displaySnackBar(
'Effective Time cannot be later than Expiration Time.');
} else {
startTime = selectedDateTime
.toString()
.split('.')
.first; // Remove seconds and milliseconds
effectiveTimeTimeStamp = selectedTimestamp;
}
} else { } else {
if (effectiveTimeTimeStamp != null && startTime =
selectedTimestamp < effectiveTimeTimeStamp!) { selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
CustomSnackBar.displaySnackBar( effectiveTimeTimeStamp = selectedTimestamp;
'Expiration Time cannot be earlier than Effective Time.'); }
} else { } else {
endTime = selectedDateTime if (effectiveTimeTimeStamp != null && selectedTimestamp < effectiveTimeTimeStamp!) {
.toString() CustomSnackBar.displaySnackBar('Expiration Time cannot be earlier than Effective Time.');
.split('.') } else {
.first; // Remove seconds and milliseconds endTime = selectedDateTime.toString().split('.').first; // Remove seconds and milliseconds
expirationTimeTimeStamp = selectedTimestamp; expirationTimeTimeStamp = selectedTimestamp;
}
} }
} }
} }
emit(ChangeTimeState()); emit(ChangeTimeState());
} }
Future<void> _filterData( Future<void> _filterData(FilterDataEvent event, Emitter<AccessState> emit) async {
FilterDataEvent event, Emitter<AccessState> emit) async {
emit(AccessLoaded()); emit(AccessLoaded());
try { try {
filteredData = data.where((item) { filteredData = data.where((item) {
bool matchesCriteria = true; 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) { if (event.passwordName != null && event.passwordName!.isNotEmpty) {
final bool matchesName = item.passwordName != null && final bool matchesName =
item.passwordName.contains(event.passwordName); item.passwordName != null && item.passwordName.contains(event.passwordName);
if (!matchesName) { if (!matchesName) {
matchesCriteria = false; matchesCriteria = false;
} }
} }
if (event.startTime != null && event.endTime != null) {
final int? effectiveTime = // Filter by start date only
int.tryParse(item.effectiveTime.toString()); if (event.startTime != null && event.endTime == null) {
final int? invalidTime = int.tryParse(item.invalidTime.toString()); DateTime startDateOnly =
if (effectiveTime == null || invalidTime == null) { DateTime.fromMillisecondsSinceEpoch(event.startTime! * 1000).toUtc().toLocal();
startDateOnly = DateTime(startDateOnly.year, startDateOnly.month, startDateOnly.day);
if (effectiveDateOnly.isBefore(startDateOnly)) {
matchesCriteria = false; 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; matchesCriteria = false;
} else if (event.selectedTabIndex == 2 && } else if (event.selectedTabIndex == 2 && item.passwordStatus.value != 'Effective') {
item.passwordStatus.value != 'Effective') {
matchesCriteria = false; matchesCriteria = false;
} else if (event.selectedTabIndex == 3 && } else if (event.selectedTabIndex == 3 && item.passwordStatus.value != 'Expired') {
item.passwordStatus.value != 'Expired') {
matchesCriteria = false; matchesCriteria = false;
} }
return matchesCriteria; return matchesCriteria;
}).toList(); }).toList();
emit(TableLoaded(filteredData)); emit(TableLoaded(filteredData));
} catch (e) { } catch (e) {
emit(FailedState(e.toString())); emit(FailedState(e.toString()));
@ -206,13 +196,11 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
} }
String timestampToDate(dynamic timestamp) { String timestampToDate(dynamic timestamp) {
DateTime dateTime = DateTime dateTime = DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
DateTime.fromMillisecondsSinceEpoch(int.parse(timestamp) * 1000);
return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}"; return "${dateTime.year}/${dateTime.month.toString().padLeft(2, '0')}/${dateTime.day.toString().padLeft(2, '0')}";
} }
Future<void> onTabChanged( Future<void> onTabChanged(TabChangedEvent event, Emitter<AccessState> emit) async {
TabChangedEvent event, Emitter<AccessState> emit) async {
try { try {
emit(AccessLoaded()); emit(AccessLoaded());
selectedIndex = event.selectedIndex; selectedIndex = event.selectedIndex;
@ -221,19 +209,14 @@ class AccessBloc extends Bloc<AccessEvent, AccessState> {
filteredData = data; filteredData = data;
break; break;
case 1: // To Be Effective case 1: // To Be Effective
filteredData = data filteredData =
.where((item) => item.passwordStatus.value == "To Be Effective") data.where((item) => item.passwordStatus.value == "To Be Effective").toList();
.toList();
break; break;
case 2: // Effective case 2: // Effective
filteredData = data filteredData = data.where((item) => item.passwordStatus.value == "Effective").toList();
.where((item) => item.passwordStatus.value == "Effective")
.toList();
break; break;
case 3: // Expired case 3: // Expired
filteredData = data filteredData = data.where((item) => item.passwordStatus.value == "Expired").toList();
.where((item) => item.passwordStatus.value == "Expired")
.toList();
break; break;
default: default:
filteredData = data; 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 { class PasswordModel {
final dynamic passwordId; final dynamic passwordId;

View File

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

View File

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

View File

@ -36,10 +36,7 @@ class DateTimeWebWidget extends StatelessWidget {
if (isRequired) if (isRequired)
Text( Text(
'* ', '* ',
style: Theme.of(context) style: Theme.of(context).textTheme.bodyMedium!.copyWith(color: Colors.red),
.textTheme
.bodyMedium!
.copyWith(color: Colors.red),
), ),
Text( Text(
title, title,
@ -55,8 +52,7 @@ class DateTimeWebWidget extends StatelessWidget {
), ),
Container( Container(
height: size.height * 0.055, height: size.height * 0.055,
padding: padding: const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10),
const EdgeInsets.only(top: 10, bottom: 10, right: 30, left: 10),
decoration: containerDecoration, decoration: containerDecoration,
child: FittedBox( child: FittedBox(
child: Column( child: Column(
@ -69,13 +65,10 @@ class DateTimeWebWidget extends StatelessWidget {
child: FittedBox( child: FittedBox(
child: Text( child: Text(
firstString, firstString,
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme color: ColorsManager.grayColor,
.bodySmall! fontSize: 12,
.copyWith( fontWeight: FontWeight.w400),
color: ColorsManager.grayColor,
fontSize: 12,
fontWeight: FontWeight.w400),
), ),
)), )),
const SizedBox( const SizedBox(
@ -90,13 +83,10 @@ class DateTimeWebWidget extends StatelessWidget {
child: FittedBox( child: FittedBox(
child: Text( child: Text(
secondString, secondString,
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme color: ColorsManager.grayColor,
.bodySmall! fontSize: 12,
.copyWith( fontWeight: FontWeight.w400),
color: ColorsManager.grayColor,
fontSize: 12,
fontWeight: FontWeight.w400),
), ),
)), )),
const SizedBox( 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_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:go_router/go_router.dart';
import 'package:graphview/GraphView.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/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_event.dart';
import 'package:syncrow_web/pages/home/bloc/home_state.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/pages/home/home_model/home_item_model.dart';
import 'package:syncrow_web/services/home_api.dart'; import 'package:syncrow_web/services/home_api.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart'; import 'package:syncrow_web/utils/constants/assets.dart';
import 'package:syncrow_web/utils/constants/routes_const.dart';
class HomeBloc extends Bloc<HomeEvent, HomeState> { class HomeBloc extends Bloc<HomeEvent, HomeState> {
final Graph graph = Graph()..isTree = true; final Graph graph = Graph()..isTree = true;
@ -43,8 +41,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
Future fetchUserInfo() async { Future fetchUserInfo() async {
try { try {
var uuid = var uuid = await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
user = await HomeApi().fetchUserInfo(uuid); user = await HomeApi().fetchUserInfo(uuid);
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
} catch (e) { } catch (e) {
@ -58,9 +55,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
icon: Assets.accessIcon, icon: Assets.accessIcon,
active: true, active: true,
onPress: (context) { onPress: (context) {
Navigator.of(context).push( context.go(RoutesConst.accessManagementPage);
MaterialPageRoute(builder: (context) => AccessManagementPage()),
);
}, },
color: null, color: null,
), ),
@ -76,9 +71,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
icon: Assets.devicesIcon, icon: Assets.devicesIcon,
active: true, active: true,
onPress: (context) { onPress: (context) {
Navigator.of(context).push( context.go(RoutesConst.deviceManagementPage);
MaterialPageRoute(builder: (context) => const DeviceManagementPage()),
);
}, },
color: ColorsManager.primaryColor, color: ColorsManager.primaryColor,
), ),

View File

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

View File

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

View File

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

View File

@ -1,6 +1,6 @@
import 'package:syncrow_web/utils/constants/assets.dart'; 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/enum/device_types.dart';
import 'package:syncrow_web/utils/constants/app_enum.dart';
class DeviceModel { class DeviceModel {
dynamic productUuid; dynamic productUuid;
@ -54,8 +54,7 @@ class DeviceModel {
if (type == DeviceType.LightBulb) { if (type == DeviceType.LightBulb) {
tempIcon = Assets.lightBulb; tempIcon = Assets.lightBulb;
} else if (type == DeviceType.CeilingSensor || } else if (type == DeviceType.CeilingSensor || type == DeviceType.WallSensor) {
type == DeviceType.WallSensor) {
tempIcon = Assets.sensors; tempIcon = Assets.sensors;
} else if (type == DeviceType.AC) { } else if (type == DeviceType.AC) {
tempIcon = Assets.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/pages/visitor_password/bloc/visitor_password_state.dart';
import 'package:syncrow_web/utils/color_manager.dart'; import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.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'; import 'package:syncrow_web/utils/style.dart';
class AddDeviceDialog extends StatelessWidget { class AddDeviceDialog extends StatelessWidget {

View File

@ -20,21 +20,75 @@ class VisitorPasswordDialog extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
var text = Theme.of(context) var text = Theme.of(context).textTheme.bodySmall!.copyWith(color: Colors.black, fontSize: 13);
.textTheme
.bodySmall!
.copyWith(color: Colors.black, fontSize: 13);
return BlocProvider( return BlocProvider(
create: (context) => VisitorPasswordBloc(), create: (context) => VisitorPasswordBloc(),
child: BlocListener<VisitorPasswordBloc, VisitorPasswordState>( child: BlocListener<VisitorPasswordBloc, VisitorPasswordState>(
listener: (context, state) { listener: (context, state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context); final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
if (state is SuccessState) { if (state is SuccessState) {
visitorBloc.stateDialog( visitorBloc
context: context, .stateDialog(
message: 'Password Created Successfully', context: context,
title: 'Send Success', 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) { } else if (state is FailedState) {
visitorBloc.stateDialog( visitorBloc.stateDialog(
context: context, context: context,
@ -46,16 +100,15 @@ class VisitorPasswordDialog extends StatelessWidget {
child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>( child: BlocBuilder<VisitorPasswordBloc, VisitorPasswordState>(
builder: (BuildContext context, VisitorPasswordState state) { builder: (BuildContext context, VisitorPasswordState state) {
final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context); final visitorBloc = BlocProvider.of<VisitorPasswordBloc>(context);
bool isRepeat = bool isRepeat = state is IsRepeatState ? state.repeat : visitorBloc.repeat;
state is IsRepeatState ? state.repeat : visitorBloc.repeat;
return AlertDialog( return AlertDialog(
backgroundColor: Colors.white, backgroundColor: Colors.white,
title: Text( title: Text(
'Create visitor password', 'Create visitor password',
style: Theme.of(context).textTheme.headlineLarge!.copyWith( style: Theme.of(context)
fontWeight: FontWeight.w400, .textTheme
fontSize: 24, .headlineLarge!
color: Colors.black), .copyWith(fontWeight: FontWeight.w400, fontSize: 24, color: Colors.black),
), ),
content: state is LoadingInitialState content: state is LoadingInitialState
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
@ -73,8 +126,7 @@ class VisitorPasswordDialog extends StatelessWidget {
flex: 2, flex: 2,
child: CustomWebTextField( child: CustomWebTextField(
validator: visitorBloc.validate, validator: visitorBloc.validate,
controller: controller: visitorBloc.userNameController,
visitorBloc.userNameController,
isRequired: true, isRequired: true,
textFieldName: 'Name', textFieldName: 'Name',
description: '', description: '',
@ -116,95 +168,111 @@ class VisitorPasswordDialog extends StatelessWidget {
), ),
Row( Row(
children: <Widget>[ children: <Widget>[
Flexible( Expanded(
child: RadioListTile<String>( flex: 2,
contentPadding: EdgeInsets.zero, child: Row(
title: Text( children: [
'Online Password', SizedBox(
style: text, width: size.width * 0.12,
), child: RadioListTile<String>(
value: 'Online Password', contentPadding: EdgeInsets.zero,
groupValue: (state title: Text(
is PasswordTypeSelected) 'Online Password',
? state.selectedType style: text,
: visitorBloc.accessTypeSelected, ),
onChanged: (String? value) { value: 'Online Password',
if (value != null) { groupValue: (state is PasswordTypeSelected)
context ? state.selectedType
.read<VisitorPasswordBloc>() : visitorBloc.accessTypeSelected,
.add(SelectPasswordType( onChanged: (String? value) {
value)); if (value != null) {
} context
}, .read<VisitorPasswordBloc>()
), .add(SelectPasswordType(value));
), }
Flexible( },
child: RadioListTile<String>( ),
contentPadding: EdgeInsets.zero, ),
title: Text('Offline Password', SizedBox(
style: text), width: size.width * 0.12,
value: 'Offline Password', child: RadioListTile<String>(
groupValue: (state contentPadding: EdgeInsets.zero,
is PasswordTypeSelected) title: Text('Offline Password', style: text),
? state.selectedType value: 'Offline Password',
: visitorBloc.accessTypeSelected, groupValue: (state is PasswordTypeSelected)
onChanged: (String? value) { ? state.selectedType
if (value != null) { : visitorBloc.accessTypeSelected,
context onChanged: (String? value) {
.read<VisitorPasswordBloc>() if (value != null) {
.add(SelectPasswordType( context
value)); .read<VisitorPasswordBloc>()
} .add(SelectPasswordType(value));
}, }
), },
), ),
Flexible( ),
child: RadioListTile<String>( SizedBox(
contentPadding: EdgeInsets.zero, width: size.width * 0.12,
title: Text( child: RadioListTile<String>(
'Dynamic Password', contentPadding: EdgeInsets.zero,
style: text, title: Text(
), 'Dynamic Password',
value: 'Dynamic Password', style: text,
groupValue: (state ),
is PasswordTypeSelected) value: 'Dynamic Password',
? state.selectedType groupValue: (state is PasswordTypeSelected)
: visitorBloc.accessTypeSelected, ? state.selectedType
onChanged: (String? value) { : visitorBloc.accessTypeSelected,
if (value != null) { onChanged: (String? value) {
context if (value != null) {
.read<VisitorPasswordBloc>() context
.add(SelectPasswordType( .read<VisitorPasswordBloc>()
value)); .add(SelectPasswordType(value));
visitorBloc visitorBloc.usageFrequencySelected = '';
.usageFrequencySelected = ''; }
} },
}, ),
), ),
],
)),
const Spacer(
flex: 2,
), ),
], ],
), ),
Text( if (visitorBloc.accessTypeSelected == 'Online Password')
'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', Text(
style: Theme.of(context) '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',
.textTheme style: Theme.of(context).textTheme.bodySmall!.copyWith(
.bodySmall! fontWeight: FontWeight.w400,
.copyWith( color: ColorsManager.grayColor,
fontWeight: FontWeight.w400, fontSize: 9),
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( const SizedBox(
height: 20, height: 20,
) )
], ],
), ),
visitorBloc.accessTypeSelected == visitorBloc.accessTypeSelected == 'Dynamic Password'
'Dynamic Password'
? const SizedBox() ? const SizedBox()
: Column( : Column(
crossAxisAlignment: crossAxisAlignment: CrossAxisAlignment.start,
CrossAxisAlignment.start,
children: [ children: [
Row( Row(
children: [ children: [
@ -223,7 +291,8 @@ class VisitorPasswordDialog extends StatelessWidget {
), ),
Row( Row(
children: <Widget>[ children: <Widget>[
Flexible( SizedBox(
width: size.width * 0.12,
child: RadioListTile<String>( child: RadioListTile<String>(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: Text( title: Text(
@ -231,88 +300,113 @@ class VisitorPasswordDialog extends StatelessWidget {
style: text, style: text,
), ),
value: 'One-Time', value: 'One-Time',
groupValue: (state groupValue: (state is UsageFrequencySelected)
is UsageFrequencySelected)
? state.selectedFrequency ? state.selectedFrequency
: visitorBloc : visitorBloc.usageFrequencySelected,
.usageFrequencySelected,
onChanged: (String? value) { onChanged: (String? value) {
if (value != null) { if (value != null) {
context context
.read< .read<VisitorPasswordBloc>()
VisitorPasswordBloc>() .add(SelectUsageFrequency(value));
.add(
SelectUsageFrequency(
value));
} }
}, },
), ),
), ),
Flexible( SizedBox(
width: size.width * 0.12,
child: RadioListTile<String>( child: RadioListTile<String>(
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
title: Text('Periodic', title: Text('Periodic', style: text),
style: text),
value: 'Periodic', value: 'Periodic',
groupValue: (state groupValue: (state is UsageFrequencySelected)
is UsageFrequencySelected)
? state.selectedFrequency ? state.selectedFrequency
: visitorBloc : visitorBloc.usageFrequencySelected,
.usageFrequencySelected,
onChanged: (String? value) { onChanged: (String? value) {
if (value != null) { if (value != null) {
context context
.read< .read<VisitorPasswordBloc>()
VisitorPasswordBloc>() .add(SelectUsageFrequency(value));
.add(
SelectUsageFrequency(
value));
} }
}, },
), ),
), ),
], ],
), ),
Text(
'Within the validity period, each device can be unlocked only once.', //One-Time
style: Theme.of(context) if (visitorBloc.usageFrequencySelected == 'One-Time' &&
.textTheme visitorBloc.accessTypeSelected == 'Online Password')
.bodySmall! Text(
.copyWith( 'Within the validity period, each device can be unlocked only once.',
color: style: Theme.of(context).textTheme.bodySmall!.copyWith(
ColorsManager.grayColor, color: ColorsManager.grayColor, fontSize: 9),
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( const SizedBox(
height: 20, height: 20,
), ),
if ((visitorBloc.usageFrequencySelected != if ((visitorBloc.usageFrequencySelected != 'One-Time' ||
'One-Time' || visitorBloc.accessTypeSelected != 'Offline Password') &&
visitorBloc.accessTypeSelected !=
'Offline Password') &&
(visitorBloc.usageFrequencySelected != '')) (visitorBloc.usageFrequencySelected != ''))
DateTimeWebWidget( DateTimeWebWidget(
isRequired: true, isRequired: true,
title: 'Access Period', title: 'Access Period',
size: size, size: size,
endTime: () { endTime: () {
visitorBloc.add(SelectTimeVisitorPassword( if (visitorBloc.usageFrequencySelected == 'Periodic' &&
context: context, visitorBloc.accessTypeSelected == 'Offline Password') {
isStart: false, visitorBloc.add(
isRepeat: false)); SelectTimeEvent(context: context, isEffective: false));
} else {
visitorBloc.add(SelectTimeVisitorPassword(
context: context, isStart: false, isRepeat: false));
}
}, },
startTime: () { startTime: () {
visitorBloc.add(SelectTimeVisitorPassword( if (visitorBloc.usageFrequencySelected == 'Periodic' &&
context: context, visitorBloc.accessTypeSelected == 'Offline Password') {
isStart: true, visitorBloc.add(
isRepeat: false)); SelectTimeEvent(context: context, isEffective: true));
} else {
visitorBloc.add(SelectTimeVisitorPassword(
context: context, isStart: true, isRepeat: false));
}
}, },
firstString: firstString: (visitorBloc.usageFrequencySelected ==
visitorBloc.startTimeAccess.toString(), 'Periodic' &&
secondString: visitorBloc.accessTypeSelected == 'Offline Password')
visitorBloc.endTimeAccess.toString(), ? visitorBloc.effectiveTime
: visitorBloc.startTimeAccess.toString(),
secondString: (visitorBloc.usageFrequencySelected ==
'Periodic' &&
visitorBloc.accessTypeSelected == 'Offline Password')
? visitorBloc.expirationTime
: visitorBloc.endTimeAccess.toString(),
icon: Assets.calendarIcon), icon: Assets.calendarIcon),
const SizedBox( const SizedBox(
height: 20, height: 20,
@ -337,21 +431,16 @@ class VisitorPasswordDialog extends StatelessWidget {
), ),
Text( Text(
'Within the validity period, each device can be unlocked only once.', 'Within the validity period, each device can be unlocked only once.',
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme fontWeight: FontWeight.w400,
.bodySmall! color: ColorsManager.grayColor,
.copyWith( fontSize: 9),
fontWeight: FontWeight.w400,
color: ColorsManager.grayColor,
fontSize: 9),
), ),
const SizedBox( const SizedBox(
height: 20, height: 20,
), ),
if (visitorBloc.usageFrequencySelected == if (visitorBloc.usageFrequencySelected == 'Periodic' &&
'Periodic' && visitorBloc.accessTypeSelected == 'Online Password')
visitorBloc.accessTypeSelected ==
'Online Password')
SizedBox( SizedBox(
width: 100, width: 100,
child: Column( child: Column(
@ -362,8 +451,7 @@ class VisitorPasswordDialog extends StatelessWidget {
child: CupertinoSwitch( child: CupertinoSwitch(
value: visitorBloc.repeat, value: visitorBloc.repeat,
onChanged: (value) { onChanged: (value) {
visitorBloc visitorBloc.add(ToggleRepeatEvent());
.add(ToggleRepeatEvent());
}, },
applyTheme: true, applyTheme: true,
), ),
@ -371,13 +459,9 @@ class VisitorPasswordDialog extends StatelessWidget {
], ],
), ),
), ),
if (visitorBloc.usageFrequencySelected == if (visitorBloc.usageFrequencySelected == 'Periodic' &&
'Periodic' && visitorBloc.accessTypeSelected == 'Online Password')
visitorBloc.accessTypeSelected == isRepeat ? const RepeatWidget() : const SizedBox(),
'Online Password')
isRepeat
? const RepeatWidget()
: const SizedBox(),
Container( Container(
decoration: containerDecoration, decoration: containerDecoration,
width: size.width / 9, width: size.width / 9,
@ -388,28 +472,22 @@ class VisitorPasswordDialog extends StatelessWidget {
barrierDismissible: false, barrierDismissible: false,
builder: (BuildContext context) { builder: (BuildContext context) {
return AddDeviceDialog( return AddDeviceDialog(
selectedDeviceIds: selectedDeviceIds: visitorBloc.selectedDevices,
visitorBloc.selectedDevices,
); );
}, },
).then((listDevice) { ).then((listDevice) {
if (listDevice != null) { if (listDevice != null) {
visitorBloc.selectedDevices = visitorBloc.selectedDevices = listDevice;
listDevice;
} }
}); });
}, },
borderRadius: 8, borderRadius: 8,
child: Text( child: Text(
'+ Add Device', '+ Add Device',
style: Theme.of(context) style: Theme.of(context).textTheme.bodySmall!.copyWith(
.textTheme fontWeight: FontWeight.w400,
.bodySmall! color: ColorsManager.whiteColors,
.copyWith( fontSize: 12),
fontWeight: FontWeight.w400,
color:
ColorsManager.whiteColors,
fontSize: 12),
), ),
), ),
), ),
@ -447,15 +525,36 @@ class VisitorPasswordDialog extends StatelessWidget {
onPressed: () { onPressed: () {
if (visitorBloc.forgetFormKey.currentState!.validate()) { if (visitorBloc.forgetFormKey.currentState!.validate()) {
if (visitorBloc.selectedDevices.isNotEmpty) { if (visitorBloc.selectedDevices.isNotEmpty) {
if (visitorBloc.effectiveTimeTimeStamp != null && if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.expirationTimeTimeStamp != null) { visitorBloc.accessTypeSelected == 'Offline Password') {
setPasswordFunction(context, size, visitorBloc);
} else if (visitorBloc.accessTypeSelected == 'Dynamic Password') {
print('objectobjectobjectobject');
setPasswordFunction(context, size, visitorBloc); setPasswordFunction(context, size, visitorBloc);
} else { } else {
visitorBloc.stateDialog( if (visitorBloc.effectiveTimeTimeStamp != null &&
context: context, visitorBloc.expirationTimeTimeStamp != null) {
message: if (isRepeat == true) {
'Please select Access Period to continue', if (visitorBloc.expirationTime != 'End Time' &&
title: 'Access Period'); 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 { } else {
visitorBloc.stateDialog( 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, borderRadius: 8,
child: Text( child: Text(
'Ok', 'Ok',
@ -501,8 +651,7 @@ class VisitorPasswordDialog extends StatelessWidget {
content: SizedBox( content: SizedBox(
height: size.height * 0.25, height: size.height * 0.25,
child: Center( child: Center(
child: child: CircularProgressIndicator(), // Display a loading spinner
CircularProgressIndicator(), // Display a loading spinner
), ),
), ),
); );
@ -526,10 +675,7 @@ class VisitorPasswordDialog extends StatelessWidget {
), ),
Text( Text(
'Set Password', 'Set Password',
style: Theme.of(context) style: Theme.of(context).textTheme.headlineLarge!.copyWith(
.textTheme
.headlineLarge!
.copyWith(
fontSize: 30, fontSize: 30,
fontWeight: FontWeight.w400, fontWeight: FontWeight.w400,
color: Colors.black, color: Colors.black,
@ -578,47 +724,39 @@ class VisitorPasswordDialog extends StatelessWidget {
borderRadius: 8, borderRadius: 8,
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
if (visitorBloc.usageFrequencySelected == 'One-Time' && if (visitorBloc.accessTypeSelected == 'Dynamic Password') {
visitorBloc.accessTypeSelected == } else {
'Online Password') { if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.add(OnlineOneTimePasswordEvent( visitorBloc.accessTypeSelected == 'Online Password') {
context: context, visitorBloc.add(OnlineOneTimePasswordEvent(
passwordName: visitorBloc.userNameController.text, context: context,
email: visitorBloc.emailController.text, passwordName: visitorBloc.userNameController.text,
)); email: visitorBloc.emailController.text,
} else if (visitorBloc.usageFrequencySelected == ));
'Periodic' && } else if (visitorBloc.usageFrequencySelected == 'Periodic' &&
visitorBloc.accessTypeSelected == visitorBloc.accessTypeSelected == 'Online Password') {
'Online Password') { visitorBloc.add(OnlineMultipleTimePasswordEvent(
visitorBloc.add(OnlineMultipleTimePasswordEvent( passwordName: visitorBloc.userNameController.text,
passwordName: visitorBloc.userNameController.text, email: visitorBloc.emailController.text,
email: visitorBloc.emailController.text, effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(),
effectiveTime: invalidTime: visitorBloc.expirationTimeTimeStamp.toString(),
visitorBloc.effectiveTimeTimeStamp.toString(), ));
invalidTime: } else if (visitorBloc.usageFrequencySelected == 'One-Time' &&
visitorBloc.expirationTimeTimeStamp.toString(), visitorBloc.accessTypeSelected == 'Offline Password') {
)); visitorBloc.add(OfflineOneTimePasswordEvent(
} else if (visitorBloc.usageFrequencySelected == context: context,
'One-Time' && passwordName: visitorBloc.userNameController.text,
visitorBloc.accessTypeSelected == email: visitorBloc.emailController.text,
'Offline Password') { ));
visitorBloc.add(OfflineOneTimePasswordEvent( } else if (visitorBloc.usageFrequencySelected == 'Periodic' &&
context: context, visitorBloc.accessTypeSelected == 'Offline Password') {
passwordName: visitorBloc.userNameController.text, visitorBloc.add(OfflineMultipleTimePasswordEvent(
email: visitorBloc.emailController.text, passwordName: visitorBloc.userNameController.text,
)); email: visitorBloc.emailController.text,
} else if (visitorBloc.usageFrequencySelected == effectiveTime: visitorBloc.effectiveTimeTimeStamp.toString(),
'Periodic' && invalidTime: visitorBloc.expirationTimeTimeStamp.toString(),
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( child: Text(

View File

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

View File

@ -29,17 +29,17 @@ class AuthenticationAPI {
return response; return response;
} }
static Future<int?> sendOtp( static Future<int?> sendOtp({required String email, required String regionUuid}) async {
{required String email, required String regionUuid}) async {
try { try {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.sendOtp, path: ApiEndpoints.sendOtp,
body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid}, body: {"email": email, "type": "PASSWORD", "regionUuid": regionUuid},
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return 30; return json['data']['cooldown'];
}); });
return 30;
return response;
} on DioException catch (e) { } on DioException catch (e) {
if (e.response != null) { if (e.response != null) {
if (e.response!.statusCode == 400) { if (e.response!.statusCode == 400) {
@ -52,8 +52,7 @@ class AuthenticationAPI {
return cooldown; return cooldown;
} }
} else { } else {
debugPrint( debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
'Error: ${e.response!.statusCode} - ${e.response!.statusMessage}');
return 1; return 1;
} }
} else { } else {
@ -66,8 +65,7 @@ class AuthenticationAPI {
} }
} }
static Future verifyOtp( static Future verifyOtp({required String email, required String otpCode}) async {
{required String email, required String otpCode}) async {
try { try {
final response = await HTTPService().post( final response = await HTTPService().post(
path: ApiEndpoints.verifyOtp, path: ApiEndpoints.verifyOtp,
@ -99,9 +97,7 @@ class AuthenticationAPI {
path: ApiEndpoints.getRegion, path: ApiEndpoints.getRegion,
showServerMessage: true, showServerMessage: true,
expectedResponseModel: (json) { expectedResponseModel: (json) {
return (json as List) return (json as List).map((zone) => RegionModel.fromJson(zone)).toList();
.map((zone) => RegionModel.fromJson(zone))
.toList();
}); });
return response; 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 blueColor = Color(0xFF0036E6);
static const Color boxColor = Color(0xFFF5F6F7); static const Color boxColor = Color(0xFFF5F6F7);
static const Color boxDivider = Color(0xFFE0E0E0); 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 rightLine = "assets/images/right_line.png";
static const String google = "assets/images/google.svg"; static const String google = "assets/images/google.svg";
static const String facebook = "assets/images/facebook.svg"; static const String facebook = "assets/images/facebook.svg";
static const String invisiblePassword = static const String invisiblePassword = "assets/images/Password_invisible.svg";
"assets/images/Password_invisible.svg";
static const String visiblePassword = "assets/images/Password_visible.svg"; static const String visiblePassword = "assets/images/Password_visible.svg";
static const String accessIcon = "assets/images/access_icon.svg"; static const String accessIcon = "assets/images/access_icon.svg";
static const String spaseManagementIcon = static const String spaseManagementIcon = "assets/images/spase_management_icon.svg";
"assets/images/spase_management_icon.svg";
static const String devicesIcon = "assets/images/devices_icon.svg"; static const String devicesIcon = "assets/images/devices_icon.svg";
static const String moveinIcon = "assets/images/movein_icon.svg"; static const String moveinIcon = "assets/images/movein_icon.svg";
static const String constructionIcon = "assets/images/construction_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"; static const String emptyTable = "assets/images/empty_table.svg";
// General assets // General assets
static const String motionlessDetection = static const String motionlessDetection = "assets/icons/motionless_detection.svg";
"assets/icons/motionless_detection.svg";
static const String acHeating = "assets/icons/ac_heating.svg"; static const String acHeating = "assets/icons/ac_heating.svg";
static const String acPowerOff = "assets/icons/ac_power_off.svg"; static const String acPowerOff = "assets/icons/ac_power_off.svg";
static const String acFanMiddle = "assets/icons/ac_fan_middle.svg"; static const String acFanMiddle = "assets/icons/ac_fan_middle.svg";
static const String switchAlarmSound = "assets/icons/switch_alarm_sound.svg"; static const String switchAlarmSound = "assets/icons/switch_alarm_sound.svg";
static const String resetOff = "assets/icons/reset_off.svg"; static const String resetOff = "assets/icons/reset_off.svg";
static const String sensitivityOperationIcon = static const String sensitivityOperationIcon = "assets/icons/sesitivity_operation_icon.svg";
"assets/icons/sesitivity_operation_icon.svg";
static const String motionDetection = "assets/icons/motion_detection.svg"; static const String motionDetection = "assets/icons/motion_detection.svg";
static const String freezing = "assets/icons/freezing.svg"; static const String freezing = "assets/icons/freezing.svg";
static const String indicator = "assets/icons/indicator.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 celsiusDegrees = "assets/icons/celsius_degrees.svg";
static const String masterState = "assets/icons/master_state.svg"; static const String masterState = "assets/icons/master_state.svg";
static const String acPower = "assets/icons/ac_power.svg"; static const String acPower = "assets/icons/ac_power.svg";
static const String farDetectionFunction = static const String farDetectionFunction = "assets/icons/far_detection_function.svg";
"assets/icons/far_detection_function.svg";
static const String nobodyTime = "assets/icons/nobody_time.svg"; static const String nobodyTime = "assets/icons/nobody_time.svg";
// Automation functions // Automation functions
@ -69,47 +64,33 @@ class Assets {
"assets/icons/automation_functions/temp_password_unlock.svg"; "assets/icons/automation_functions/temp_password_unlock.svg";
static const String doorlockNormalOpen = static const String doorlockNormalOpen =
"assets/icons/automation_functions/doorlock_normal_open.svg"; "assets/icons/automation_functions/doorlock_normal_open.svg";
static const String doorbell = static const String doorbell = "assets/icons/automation_functions/doorbell.svg";
"assets/icons/automation_functions/doorbell.svg";
static const String remoteUnlockViaApp = static const String remoteUnlockViaApp =
"assets/icons/automation_functions/remote_unlock_via_app.svg"; "assets/icons/automation_functions/remote_unlock_via_app.svg";
static const String doubleLock = static const String doubleLock = "assets/icons/automation_functions/double_lock.svg";
"assets/icons/automation_functions/double_lock.svg"; static const String selfTestResult = "assets/icons/automation_functions/self_test_result.svg";
static const String selfTestResult = static const String lockAlarm = "assets/icons/automation_functions/lock_alarm.svg";
"assets/icons/automation_functions/self_test_result.svg"; static const String presenceState = "assets/icons/automation_functions/presence_state.svg";
static const String lockAlarm = static const String currentTemp = "assets/icons/automation_functions/current_temp.svg";
"assets/icons/automation_functions/lock_alarm.svg"; static const String presence = "assets/icons/automation_functions/presence.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 = static const String residualElectricity =
"assets/icons/automation_functions/residual_electricity.svg"; "assets/icons/automation_functions/residual_electricity.svg";
static const String hijackAlarm = static const String hijackAlarm = "assets/icons/automation_functions/hijack_alarm.svg";
"assets/icons/automation_functions/hijack_alarm.svg"; static const String passwordUnlock = "assets/icons/automation_functions/password_unlock.svg";
static const String passwordUnlock =
"assets/icons/automation_functions/password_unlock.svg";
static const String remoteUnlockRequest = static const String remoteUnlockRequest =
"assets/icons/automation_functions/remote_unlock_req.svg"; "assets/icons/automation_functions/remote_unlock_req.svg";
static const String cardUnlock = static const String cardUnlock = "assets/icons/automation_functions/card_unlock.svg";
"assets/icons/automation_functions/card_unlock.svg";
static const String motion = "assets/icons/automation_functions/motion.svg"; static const String motion = "assets/icons/automation_functions/motion.svg";
static const String fingerprintUnlock = static const String fingerprintUnlock =
"assets/icons/automation_functions/fingerprint_unlock.svg"; "assets/icons/automation_functions/fingerprint_unlock.svg";
// Presence Sensor Assets // Presence Sensor Assets
static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg"; static const String sensorMotionIcon = "assets/icons/sensor_motion_ic.svg";
static const String sensorPresenceIcon = static const String sensorPresenceIcon = "assets/icons/sensor_presence_ic.svg";
"assets/icons/sensor_presence_ic.svg";
static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg"; static const String sensorVacantIcon = "assets/icons/sensor_vacant_ic.svg";
static const String illuminanceRecordIcon = static const String illuminanceRecordIcon = "assets/icons/illuminance_record_ic.svg";
"assets/icons/illuminance_record_ic.svg"; static const String presenceRecordIcon = "assets/icons/presence_record_ic.svg";
static const String presenceRecordIcon = static const String helpDescriptionIcon = "assets/icons/help_description_ic.svg";
"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 lightPulp = "assets/icons/light_pulb.svg";
static const String acDevice = "assets/icons/ac_device.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 dyi = 'assets/icons/dyi.svg';
static const String office = 'assets/icons/office.svg'; static const String office = 'assets/icons/office.svg';
static const String parlour = 'assets/icons/parlour.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 = static GlobalKey<ScaffoldMessengerState>? snackbarKey =
GlobalKey<ScaffoldMessengerState>(); GlobalKey<ScaffoldMessengerState>();
} }

View File

@ -216,6 +216,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "7.7.0" version: "7.7.0"
go_router:
dependency: "direct main"
description:
name: go_router
sha256: "2ddb88e9ad56ae15ee144ed10e33886777eb5ca2509a914850a5faa7b52ff459"
url: "https://pub.dev"
source: hosted
version: "14.2.7"
graphview: graphview:
dependency: "direct main" dependency: "direct main"
description: description:
@ -260,18 +268,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "3f87a60e8c63aecc975dda1ceedbc8f24de75f09e4856ea27daf8958f2f0ce05" sha256: "7f0df31977cb2c0b88585095d168e689669a2cc9b97c309665e3386f3e9d341a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.5" version: "10.0.4"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: "932549fb305594d82d7183ecd9fa93463e9914e1b67cacc34bc40906594a1806" sha256: "06e98f569d004c1315b991ded39924b21af84cf14cc94791b8aea337d25b57f8"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.5" version: "3.0.3"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
@ -288,6 +296,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.0" version: "3.0.0"
logging:
dependency: transitive
description:
name: logging
sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340"
url: "https://pub.dev"
source: hosted
version: "1.2.0"
matcher: matcher:
dependency: transitive dependency: transitive
description: description:
@ -300,18 +316,18 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: material_color_utilities name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.11.1" version: "0.8.0"
meta: meta:
dependency: transitive dependency: transitive
description: description:
name: meta name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 sha256: "7687075e408b093f36e6bbf6c91878cc0d4cd10f409506f7bc996f68220b9136"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.15.0" version: "1.12.0"
nested: nested:
dependency: transitive dependency: transitive
description: description:
@ -521,10 +537,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: "5b8a98dafc4d5c4c9c72d8b31ab2b23fc13422348d2997120294d3bac86b4ddb" sha256: "9955ae474176f7ac8ee4e989dadfb411a58c30415bcfb648fa04b2b8a03afa7f"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.2" version: "0.7.0"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@ -569,10 +585,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vm_service name: vm_service
sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" sha256: "3923c89304b715fb1eb6423f017651664a03bf5f4b29983627c4da791f74a4ec"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "14.2.5" version: "14.2.1"
web: web:
dependency: transitive dependency: transitive
description: description:

View File

@ -44,7 +44,9 @@ dependencies:
flutter_secure_storage: ^9.2.2 flutter_secure_storage: ^9.2.2
shared_preferences: ^2.3.0 shared_preferences: ^2.3.0
data_table_2: ^2.5.15 data_table_2: ^2.5.15
go_router:
intl: ^0.19.0 intl: ^0.19.0
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter