diff --git a/assets/dome.json b/assets/dome.json new file mode 100644 index 00000000..39e6ee7c --- /dev/null +++ b/assets/dome.json @@ -0,0 +1,88 @@ +[ + { + "accessUser": "Ali Doe", + "accessType": "Admin", + "accessPeriod": "2023-08-01", + "accessibleDevice": "Smart Door", + "authorizationSource": "System", + "authorizer": "Jane Smith", + "authorizationTime": "2023-08-01 10:00 AM", + "accessStatus": "Granted", + "actions": "View" + }, { + "accessUser": "oamr Doe", + "accessType": "Admin", + "accessPeriod": "2023-08-01", + "accessibleDevice": "Smart Door", + "authorizationSource": "System", + "authorizer": "Jane Smith", + "authorizationTime": "2023-08-01 10:00 AM", + "accessStatus": "Granted", + "actions": "View" + }, { + "accessUser": "John Doe", + "accessType": "Admin", + "accessPeriod": "2023-08-01", + "accessibleDevice": "Smart Door", + "authorizationSource": "System", + "authorizer": "Jane Smith", + "authorizationTime": "2023-08-01 10:00 AM", + "accessStatus": "Granted", + "actions": "View" + }, + + { + "accessUser": "John Doe", + "accessType": "Admin", + "accessPeriod": "2023-08-01", + "accessibleDevice": "Smart Door", + "authorizationSource": "System", + "authorizer": "Jane Smith", + "authorizationTime": "2023-08-01 10:00 AM", + "accessStatus": "Granted", + "actions": "View" + }, + { + "accessUser": "John Doe", + "accessType": "Admin", + "accessPeriod": "2023-08-01", + "accessibleDevice": "Smart Door", + "authorizationSource": "System", + "authorizer": "Jane Smith", + "authorizationTime": "2023-08-01 10:00 AM", + "accessStatus": "Granted", + "actions": "View" + }, + { + "accessUser": "John Doe", + "accessType": "Admin", + "accessPeriod": "2023-08-01 ", + "accessibleDevice": "Smart Door", + "authorizationSource": "System", + "authorizer": "Jane Smith", + "authorizationTime": "2023-08-01 10:00 AM", + "accessStatus": "Granted", + "actions": "View" + }, { + "accessUser": "John Doe", + "accessType": "Admin", + "accessPeriod": "2023-08-01 ", + "accessibleDevice": "Smart Door", + "authorizationSource": "System", + "authorizer": "Jane Smith", + "authorizationTime": "2023-08-01 10:00 AM", + "accessStatus": "Granted", + "actions": "View" + }, + { + "accessUser": "Alice Johnson", + "accessType": "User", + "accessPeriod": "2023-08-01 to 2023-08-31", + "accessibleDevice": "Smart Lock", + "authorizationSource": "Admin", + "authorizer": "John Doe", + "authorizationTime": "2023-08-02 11:00 AM", + "accessStatus": "Pending", + "actions": "Approve" + } +] diff --git a/assets/images/calendar_icon.svg b/assets/images/calendar_icon.svg new file mode 100644 index 00000000..bdf23bee --- /dev/null +++ b/assets/images/calendar_icon.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/lib/main.dart b/lib/main.dart index 14d48c3e..615851eb 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,9 +29,7 @@ class MyApp extends StatelessWidget { providers: [ BlocProvider(create: (context) => HomeBloc()), ], - child: - - MaterialApp( + child: MaterialApp( debugShowCheckedModeBanner: false, // Hide debug banner scrollBehavior: const MaterialScrollBehavior().copyWith( dragDevices: { @@ -58,7 +56,7 @@ class MyApp extends StatelessWidget { colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), // Set up color scheme useMaterial3: true, // Enable Material 3 ), - home: isLoggedIn == 'Success' ? const HomePage() : const LoginPage(), + home: isLoggedIn == 'Success' ? const HomePage() : const LoginPage(), )); } } diff --git a/lib/pages/access_management/access_management.dart b/lib/pages/access_management/access_management.dart deleted file mode 100644 index f7fee005..00000000 --- a/lib/pages/access_management/access_management.dart +++ /dev/null @@ -1,142 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_svg/svg.dart'; -import 'package:syncrow_web/utils/color_manager.dart'; -import 'package:syncrow_web/utils/constants/assets.dart'; -import 'package:syncrow_web/web_layout/web_scaffold.dart'; - -class AccessManagementPage extends StatelessWidget { - const AccessManagementPage({super.key}); - - @override - Widget build(BuildContext context) { - Size size = MediaQuery.of(context).size; - - return WebScaffold( - enableMenuSideba: false, - appBarTitle: Row( - children: [ - Text( - 'Access Management', - style: Theme.of(context).textTheme.headlineLarge, - ) - ], - ), - appBarBody: [ - Text( - 'Physical Access', - style: Theme.of(context) - .textTheme - .headlineMedium! - .copyWith(color: Colors.white), - ), - Text( - 'App Access', - style: Theme.of(context) - .textTheme - .headlineMedium! - .copyWith(color: Colors.white), - ) - ], - scaffoldBody: Container( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Container( - width:size.width*0.3, - height: size.height*0.05, - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 5, - blurRadius: 7, - offset: Offset(0, 3), // changes position of shadow - ), - ], - color: ColorsManager.boxColor, - borderRadius: BorderRadius.all(Radius.circular(10))), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceAround, - children: [ - Text('All'), - Text('To Be Effective (0)'), - Text('Effective (0)'), - Text('Expired'), - ], - ), - ), - SizedBox(height: 10,), - Row( - children: [ - Container( - width:size.width*0.08, - height: size.height*0.05, - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 5, - blurRadius: 7, - offset: Offset(0, 3), // changes position of shadow - ), - ], - color: ColorsManager.boxColor, - borderRadius: BorderRadius.all(Radius.circular(10))), - child: TextFormField() - ), - Container( - width:size.width*0.08, - height: size.height*0.05, - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 5, - blurRadius: 7, - offset: Offset(0, 3), // changes position of shadow - ), - ], - color: ColorsManager.boxColor, - borderRadius: BorderRadius.all(Radius.circular(10))), - child: TextFormField() - ), - Container( - width:size.width*0.08, - height: size.height*0.05, - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 5, - blurRadius: 7, - offset: Offset(0, 3), // changes position of shadow - ), - ], - color: ColorsManager.boxColor, - borderRadius: BorderRadius.all(Radius.circular(10))), - child: TextFormField() - ), - Container( - width:size.width*0.08, - height: size.height*0.05, - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 5, - blurRadius: 7, - offset: Offset(0, 3), // changes position of shadow - ), - ], - color: ColorsManager.boxColor, - borderRadius: BorderRadius.all(Radius.circular(10))), - child: TextFormField() - ) - ], - ), - - ], - ), - )); - } -} diff --git a/lib/pages/access_management/bloc/access_bloc.dart b/lib/pages/access_management/bloc/access_bloc.dart new file mode 100644 index 00000000..8938fc36 --- /dev/null +++ b/lib/pages/access_management/bloc/access_bloc.dart @@ -0,0 +1,26 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_web/pages/access_management/bloc/access_event.dart'; +import 'package:syncrow_web/pages/access_management/bloc/access_state.dart'; +import 'package:syncrow_web/pages/access_management/model/access_manag_model.dart'; +import 'package:syncrow_web/services/access_mang_api.dart'; + +class AccessBloc extends Bloc { + AccessBloc() : super((AccessInitial())) { + on(_onFetchTableData); + } + String startTime = 'Start Time'; + String endTime = 'End Time'; + + Future _onFetchTableData( + FetchTableData event, Emitter emit) async { + try { + emit(AccessLoaded()); + List data = await AccessMangApi().fetchInfo(); + print('objectwww888888${data[0].accessPeriod}'); + + emit(TableLoaded(data)); + } catch (e) { + emit(FailedState(e.toString())); + } + } +} diff --git a/lib/pages/access_management/bloc/access_event.dart b/lib/pages/access_management/bloc/access_event.dart new file mode 100644 index 00000000..60512387 --- /dev/null +++ b/lib/pages/access_management/bloc/access_event.dart @@ -0,0 +1,11 @@ + +import 'package:equatable/equatable.dart'; + +abstract class AccessEvent extends Equatable { + const AccessEvent(); + + @override + List get props => []; +} +class FetchTableData extends AccessEvent {} + diff --git a/lib/pages/access_management/bloc/access_state.dart b/lib/pages/access_management/bloc/access_state.dart new file mode 100644 index 00000000..94bbc90c --- /dev/null +++ b/lib/pages/access_management/bloc/access_state.dart @@ -0,0 +1,31 @@ +import 'package:equatable/equatable.dart'; +import 'package:syncrow_web/pages/access_management/model/access_manag_model.dart'; + +abstract class AccessState extends Equatable { + const AccessState(); + + @override + List get props => []; +} + +class AccessInitial extends AccessState {} + +class AccessLoaded extends AccessState {} +class FailedState extends AccessState { + final String message; + + FailedState(this.message); + + @override + List get props => [message]; +} + +class TableLoaded extends AccessState { + final List data; + + const TableLoaded(this.data); + + @override + List get props => [data]; +} + diff --git a/lib/pages/access_management/model/access_manag_model.dart b/lib/pages/access_management/model/access_manag_model.dart new file mode 100644 index 00000000..ef468c8e --- /dev/null +++ b/lib/pages/access_management/model/access_manag_model.dart @@ -0,0 +1,37 @@ +class AccessManagModel { + final String accessUser; + final String accessType; + final String accessPeriod; + final String accessibleDevice; + final String authorizationSource; + final String authorizer; + final String authorizationTime; + final String accessStatus; + final String actions; + + AccessManagModel({ + required this.accessUser, + required this.accessType, + required this.accessPeriod, + required this.accessibleDevice, + required this.authorizationSource, + required this.authorizer, + required this.authorizationTime, + required this.accessStatus, + required this.actions, + }); + + factory AccessManagModel.fromJson(Map json) { + return AccessManagModel( + accessUser: json['accessUser'], + accessType: json['accessType'], + accessPeriod: json['accessPeriod'], + accessibleDevice: json['accessibleDevice'], + authorizationSource: json['authorizationSource'], + authorizer: json['authorizer'], + authorizationTime: json['authorizationTime'], + accessStatus: json['accessStatus'], + actions: json['actions'], + ); + } +} diff --git a/lib/pages/access_management/view/access_management.dart b/lib/pages/access_management/view/access_management.dart new file mode 100644 index 00000000..00856a99 --- /dev/null +++ b/lib/pages/access_management/view/access_management.dart @@ -0,0 +1,301 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_svg/flutter_svg.dart'; +import 'package:syncrow_web/pages/access_management/bloc/access_bloc.dart'; +import 'package:syncrow_web/pages/access_management/bloc/access_event.dart'; +import 'package:syncrow_web/pages/access_management/bloc/access_state.dart'; +import 'package:syncrow_web/pages/common/default_button.dart'; +import 'package:syncrow_web/utils/color_manager.dart'; +import 'package:syncrow_web/utils/constants/assets.dart'; +import 'package:syncrow_web/utils/style.dart'; +import 'package:syncrow_web/web_layout/web_scaffold.dart'; + +class AccessManagementPage extends StatelessWidget { + const AccessManagementPage({super.key}); + @override + Widget build(BuildContext context) { + Size size = MediaQuery.of(context).size; + return WebScaffold( + enableMenuSideba: false, + appBarTitle: Row( + children: [ + Text( + 'Access Management', + style: Theme.of(context).textTheme.headlineLarge, + ) + ], + ), + appBarBody: [ + Text( + 'Physical Access', + style: Theme.of(context) + .textTheme + .headlineMedium! + .copyWith(color: Colors.white), + ), + ], + scaffoldBody: BlocProvider( + create: (BuildContext context) => AccessBloc()..add(FetchTableData() ), + child: BlocConsumer( + listener: (context, state) { + if (state is FailedState) { + // CustomSnackBar.displaySnackBar( + // state.errorMessage + // ); + } + }, builder: (context, state) { + return Container( + padding: EdgeInsets.all(30), + height: size.height, + width: size.width, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + width: size.width * 0.3, + height: size.height * 0.05, + decoration: containerDecoration, + child: const Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Text('All'), + Text('To Be Effective (0)'), + Text('Effective (0)'), + Text('Expired'), + ], + ), + ), + const SizedBox( + height: 20, + ), + Wrap( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + Text('User Name'), + Container( + width: size.width*0.15, + decoration: containerDecoration, + child: TextFormField( + decoration: textBoxDecoration()! + .copyWith(hintText: 'Please enter'), + )), + ], + ), + const SizedBox(width: 15,), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Text('Email Address'), + Container( + width: size.width*0.15, + decoration: containerDecoration, + child: TextFormField( + decoration: textBoxDecoration()! + .copyWith(hintText: 'Please enter'), + )), + ], + ), + const SizedBox(width: 15,), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Text('Access Time'), + Container( + width: size.width*0.18, + padding: EdgeInsets.all(10), + decoration: containerDecoration, + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + InkWell(child: Text(BlocProvider.of(context).startTime)), + const Icon(Icons.arrow_right_alt), + InkWell(child: Text(BlocProvider.of(context).endTime)), + SvgPicture.asset( + Assets.calendarIcon, + ), + ], + ), + ], + )), + ], + ), + const SizedBox(width: 15,), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.start, + children: [ + const Text('Authorization Source'), + Container( + width: size.width*0.18, + decoration: containerDecoration, + child: TextFormField( + decoration: textBoxDecoration(), + )), + ], + ), + const SizedBox(width: 15,), + SizedBox( + width: size.width*0.06, + child: Column( + children: [ + Text(''), + Container( + decoration: containerDecoration, + + child: DefaultButton(child: Text('Search'),borderRadius: 9)), + ], + ), + ), + const SizedBox(width: 10,), + SizedBox( + width: size.width*0.06, + child: Column( + children: [ + Text(''), + Container( + decoration: containerDecoration, + child: DefaultButton( + 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: const DefaultButton( + borderRadius: 8, + child: 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:state is TableLoaded? + Container( + decoration: containerDecoration, + width: size.width, + child: Padding( + padding: const EdgeInsets.all(10.0), + child: ListView( + scrollDirection: Axis.horizontal, + children: [ + Container( + width: size.width, + height:size.height , + child: Column( + children: [ + + Container( + color: ColorsManager.boxColor, + child: Row( + children: [ + _buildTableHeaderCell('Access User'), + _buildTableHeaderCell('Access Type'), + _buildTableHeaderCell('Access Period'), + _buildTableHeaderCell('Accessible Device'), + _buildTableHeaderCell('Authorization Source'), + _buildTableHeaderCell('Authorizer'), + _buildTableHeaderCell('Authorization Time'), + _buildTableHeaderCell('Access Status'), + _buildTableHeaderCell('Actions'), + ], + ), + ), + + Expanded( + child: Container( + width: size.width, + color: ColorsManager.whiteColors, + child: ListView( + shrinkWrap: true, + children: [ + Column( + children: state.data.map((item) { + return Row( + children: [ + _buildTableCell(item.accessUser), + _buildTableCell(item.accessType), + _buildTableCell(item.accessPeriod), + _buildTableCell(item.accessibleDevice), + _buildTableCell(item.authorizationSource), + _buildTableCell(item.authorizer), + _buildTableCell(item.authorizationTime), + _buildTableCell(item.accessStatus), + _buildTableCell(item.actions), + ], + ); + }).toList(), + ), + ], + ), + ), + ), + ], + ), + ), + ], + ), + ), + ):const Center(child: CircularProgressIndicator()) + ) + ], + ), + ); + }))); + } +} +Widget _buildTableHeaderCell(String title) { + return Expanded( + child: Container( + decoration: const BoxDecoration( + border: Border.symmetric(vertical: BorderSide(color: ColorsManager.boxDivider)) + ), + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(title, style: TextStyle(fontWeight: FontWeight.bold)), + ), + ), + ); +} + +Widget _buildTableCell(String content) { + return Expanded( + child: Container( + padding: const EdgeInsets.all(20.0), + decoration: const BoxDecoration( + border: Border.symmetric(horizontal: BorderSide(color: ColorsManager.boxDivider)) + ), + alignment: Alignment.centerLeft, + child: Text(content,style: TextStyle(color: Colors.black,fontSize: 12),), + ), + ); +} diff --git a/lib/pages/auth/bloc/auth_bloc.dart b/lib/pages/auth/bloc/auth_bloc.dart index 00f6227f..7e57f7ab 100644 --- a/lib/pages/auth/bloc/auth_bloc.dart +++ b/lib/pages/auth/bloc/auth_bloc.dart @@ -23,6 +23,7 @@ class AuthBloc extends Bloc { on(_onUpdateTimer); on(_passwordVisible); on(_fetchRegion); + on(selectRegion); } ////////////////////////////// forget password ////////////////////////////////// @@ -32,7 +33,7 @@ class AuthBloc extends Bloc { final forgetFormKey = GlobalKey(); Timer? _timer; int _remainingTime = 0; - List? regionList; + List? regionList=[RegionModel(name: 'name', id: 'id')]; Future _onStartTimer(StartTimerEvent event, Emitter emit) async { if (_validateInputs(emit)) return; @@ -42,7 +43,8 @@ class AuthBloc extends Bloc { _remainingTime = 60; add(UpdateTimerEvent( remainingTime: _remainingTime, isButtonEnabled: false)); - await AuthenticationAPI.sendOtp(email: forgetEmailController.text); + debugPrint('_remainingTime=$_remainingTime'); + _remainingTime = (await AuthenticationAPI.sendOtp(email: forgetEmailController.text,regionUuid: regionUuid))!; _timer = Timer.periodic(const Duration(seconds: 1), (timer) { _remainingTime--; if (_remainingTime <= 0) { @@ -99,6 +101,7 @@ class AuthBloc extends Bloc { String maskedEmail = ''; String otpCode = ''; String validate = ''; + String regionUuid = ''; static Token token = Token.emptyConstructor(); static UserModel? user; bool showValidationMessage = false; @@ -116,6 +119,7 @@ class AuthBloc extends Bloc { model: LoginWithEmailModel( email: event.username, password: event.password, + regionUuid: event.regionUuid ), ); } catch (failure) { @@ -274,15 +278,7 @@ class AuthBloc extends Bloc { return '$maskedLocalPart@$domainPart'; } - final List regions = [ - 'North America', - 'South America', - 'Europe', - 'Asia', - 'Africa', - 'Australia', - 'Antarctica', - ]; + static Future getTokenAndValidate() async { @@ -317,8 +313,8 @@ class AuthBloc extends Bloc { void _fetchRegion(RegionInitialEvent event, Emitter emit) async { try { emit(AuthLoading()); - regionList = await AuthenticationAPI.fetchRegion(); - emit(LoginSuccess()); + regionList = await AuthenticationAPI.fetchRegion(); + emit(AuthInitialState()); } catch (e) { emit( LoginFailure(error: e.toString())); @@ -326,6 +322,34 @@ class AuthBloc extends Bloc { } + Future selectRegion(SelectRegionEvent event, Emitter emit) async { + try { + emit(AuthLoading()); + regionUuid= event.val; + emit(AuthInitialState()); + } catch (e) { + emit(FailureForgetState(error: e.toString())); + return; + } + } + + String formattedTime(int time) { + final int days = (time / 86400).floor(); // 86400 seconds in a day + final int hours = ((time % 86400) / 3600).floor(); + final int minutes = (((time % 86400) % 3600) / 60).floor(); + final int seconds = (((time % 86400) % 3600) % 60).floor(); + + final String formattedTime = [ + if (days > 0) '${days}d', // Append 'd' for days + if (days > 0 || hours > 0) hours.toString().padLeft(2, '0'), // Show hours if there are days or hours + minutes.toString().padLeft(2, '0'), + seconds.toString().padLeft(2, '0'), + ].join(':'); + + return formattedTime; + } + + } diff --git a/lib/pages/auth/bloc/auth_event.dart b/lib/pages/auth/bloc/auth_event.dart index 8a410555..50cd5c56 100644 --- a/lib/pages/auth/bloc/auth_event.dart +++ b/lib/pages/auth/bloc/auth_event.dart @@ -1,4 +1,5 @@ import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; abstract class AuthEvent extends Equatable { const AuthEvent(); @@ -10,11 +11,12 @@ abstract class AuthEvent extends Equatable { class LoginButtonPressed extends AuthEvent { final String username; final String password; + final String regionUuid; - const LoginButtonPressed({required this.username, required this.password}); + const LoginButtonPressed({required this.username, required this.password, required this.regionUuid}); @override - List get props => [username, password]; + List get props => [username, password,regionUuid]; } class CheckBoxEvent extends AuthEvent { @@ -52,4 +54,10 @@ class PasswordVisibleEvent extends AuthEvent{ class RegionInitialEvent extends AuthEvent {} -class SelectRegionEvent extends AuthEvent {} +class SelectRegionEvent extends AuthEvent { + final String val; + const SelectRegionEvent({required this.val}); + @override + List get props => [val]; +} + diff --git a/lib/pages/auth/bloc/auth_state.dart b/lib/pages/auth/bloc/auth_state.dart index 4b6359eb..973ee400 100644 --- a/lib/pages/auth/bloc/auth_state.dart +++ b/lib/pages/auth/bloc/auth_state.dart @@ -12,6 +12,7 @@ class LoginInitial extends AuthState {} class AuthTokenLoading extends AuthState {} class AuthLoading extends AuthState {} +class AuthInitialState extends AuthState {} class LoginSuccess extends AuthState {} @@ -73,3 +74,12 @@ class AuthTokenError extends AuthError { class AuthSuccess extends AuthState {} class AuthTokenSuccess extends AuthSuccess {} +class TimerUpdated extends AuthState { + final String formattedTime; + final bool isButtonEnabled; + + TimerUpdated({ + required this.formattedTime, + required this.isButtonEnabled, + }); +} diff --git a/lib/pages/auth/model/login_with_email_model.dart b/lib/pages/auth/model/login_with_email_model.dart index c387b0d2..88be9808 100644 --- a/lib/pages/auth/model/login_with_email_model.dart +++ b/lib/pages/auth/model/login_with_email_model.dart @@ -1,16 +1,19 @@ class LoginWithEmailModel { final String email; final String password; + final String regionUuid; LoginWithEmailModel({ required this.email, required this.password, + required this.regionUuid, }); factory LoginWithEmailModel.fromJson(Map json) { return LoginWithEmailModel( email: json['email'], password: json['password'], + regionUuid: json['regionUuid'], ); } @@ -18,6 +21,7 @@ class LoginWithEmailModel { return { 'email': email, 'password': password, + 'regionUuid': regionUuid, }; } } diff --git a/lib/pages/auth/view/forget_password_web_page.dart b/lib/pages/auth/view/forget_password_web_page.dart index d24691b6..0ae96d02 100644 --- a/lib/pages/auth/view/forget_password_web_page.dart +++ b/lib/pages/auth/view/forget_password_web_page.dart @@ -4,6 +4,7 @@ import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; +import 'package:syncrow_web/pages/auth/model/region_model.dart'; import 'package:syncrow_web/pages/common/default_button.dart'; import 'package:syncrow_web/pages/common/first_layer.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -13,9 +14,10 @@ class ForgetPasswordWebPage extends StatelessWidget { const ForgetPasswordWebPage({super.key}); @override Widget build(BuildContext context) { + return Scaffold( body: BlocProvider( - create: (context) => AuthBloc(), + create: (context) => AuthBloc()..add(RegionInitialEvent()), child: BlocConsumer( listener: (context, state) { if (state is SuccessForgetState){ @@ -30,7 +32,7 @@ class ForgetPasswordWebPage extends StatelessWidget { } }, builder: (context, state) { - if (state is LoadingForgetState) { + if (state is AuthLoading) { return const Center(child: CircularProgressIndicator()); } else { return _buildForm(context, state); @@ -147,14 +149,14 @@ class ForgetPasswordWebPage extends StatelessWidget { ), isDense: true, style: const TextStyle(color: Colors.black), - items: forgetBloc.regions.map((String region) { + items:forgetBloc.regionList!.map((RegionModel region) { return DropdownMenuItem( - value: region, - child: Text(region), + value: region.id, + child: Text(region.name), ); }).toList(), onChanged: (String? value) { - print(value); + forgetBloc.add(SelectRegionEvent(val: value!,)); }, ), ) @@ -201,8 +203,9 @@ class ForgetPasswordWebPage extends StatelessWidget { onTap: () { BlocProvider.of(context).add(StartTimerEvent()); }, - child: Text( - 'Get Code ${state is TimerState && !state.isButtonEnabled ? "(${state.remainingTime.toString()})" : ""}', + child: + Text( + 'Get Code ${state is TimerState && !state.isButtonEnabled ? "(${ BlocProvider.of(context).formattedTime(state.remainingTime)})" : ""}', style: TextStyle( color: state is TimerState && !state.isButtonEnabled ? Colors.grey diff --git a/lib/pages/auth/view/login_mobile_page.dart b/lib/pages/auth/view/login_mobile_page.dart index a2877bf5..50684bab 100644 --- a/lib/pages/auth/view/login_mobile_page.dart +++ b/lib/pages/auth/view/login_mobile_page.dart @@ -6,6 +6,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; +import 'package:syncrow_web/pages/auth/model/region_model.dart'; import 'package:syncrow_web/pages/auth/view/forget_password_page.dart'; import 'package:syncrow_web/pages/common/default_button.dart'; import 'package:syncrow_web/utils/color_manager.dart'; @@ -145,13 +146,13 @@ class LoginMobilePage extends StatelessWidget { textAlign: TextAlign.center, ), ), + isDense: true, style: const TextStyle(color: Colors.black), - items: - loginBloc.regions.map((String region) { + items:loginBloc.regionList!.map((RegionModel region) { return DropdownMenuItem( - value: region, - child: Text(region), + value: region.name, + child: Text(region.name), ); }).toList(), onChanged: (String? value) { @@ -300,10 +301,9 @@ class LoginMobilePage extends StatelessWidget { .validate()) { loginBloc.add( LoginButtonPressed( - username: - loginBloc.loginEmailController.text, - password: - loginBloc.loginPasswordController.text, + regionUuid:'' , + username: loginBloc.loginEmailController.text, + password: loginBloc.loginPasswordController.text, ), ); } diff --git a/lib/pages/auth/view/login_web_page.dart b/lib/pages/auth/view/login_web_page.dart index 1a473df7..bd2259fa 100644 --- a/lib/pages/auth/view/login_web_page.dart +++ b/lib/pages/auth/view/login_web_page.dart @@ -7,6 +7,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_event.dart'; import 'package:syncrow_web/pages/auth/bloc/auth_state.dart'; +import 'package:syncrow_web/pages/auth/model/region_model.dart'; import 'package:syncrow_web/pages/auth/view/forget_password_page.dart'; import 'package:syncrow_web/pages/common/default_button.dart'; import 'package:syncrow_web/pages/common/first_layer.dart'; @@ -28,7 +29,7 @@ class _LoginWebPageState extends State { Widget build(BuildContext context) { return Scaffold( body: BlocProvider( - create: (BuildContext context) => AuthBloc(), + create: (BuildContext context) => AuthBloc()..add(RegionInitialEvent()), child: BlocConsumer( listener: (context, state) { if (state is LoginSuccess) { @@ -153,13 +154,16 @@ class _LoginWebPageState extends State { ), isDense: true, style: const TextStyle(color: Colors.black), - items:loginBloc.regions.map((String region) { + items:loginBloc.regionList!.map((RegionModel region) { return DropdownMenuItem( - value: region, - child: Text(region), + value: region.id, + child: Text(region.name), ); }).toList(), - onChanged: (String? value) {}, + onChanged: (String? value) { + + loginBloc.add(SelectRegionEvent(val: value!,)); + }, ), ) ], @@ -310,6 +314,7 @@ class _LoginWebPageState extends State { onPressed: () { if (loginBloc.loginFormKey.currentState!.validate()) { loginBloc.add(LoginButtonPressed( + regionUuid:loginBloc.regionUuid , username: loginBloc.loginEmailController.text, password: loginBloc.loginPasswordController.text, ), diff --git a/lib/pages/common/default_button.dart b/lib/pages/common/default_button.dart index d588acb9..02254828 100644 --- a/lib/pages/common/default_button.dart +++ b/lib/pages/common/default_button.dart @@ -18,7 +18,6 @@ class DefaultButton extends StatelessWidget { this.height, this.padding, }); - final void Function()? onPressed; final Widget child; final double? height; @@ -28,15 +27,10 @@ class DefaultButton extends StatelessWidget { final double? padding; final bool isDone; final bool isLoading; - final TextStyle? customTextStyle; - final ButtonStyle? customButtonStyle; - final Color? backgroundColor; - final Color? foregroundColor; - @override Widget build(BuildContext context) { return ElevatedButton( diff --git a/lib/pages/home/bloc/home_bloc.dart b/lib/pages/home/bloc/home_bloc.dart index f261c39a..db233d3c 100644 --- a/lib/pages/home/bloc/home_bloc.dart +++ b/lib/pages/home/bloc/home_bloc.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:graphview/GraphView.dart'; -import 'package:syncrow_web/pages/access_management/access_management.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/home/bloc/home_event.dart'; import 'package:syncrow_web/pages/home/bloc/home_state.dart'; @@ -38,7 +38,6 @@ class HomeBloc extends Bloc { ..levelSeparation = (150) ..subtreeSeparation = (150) ..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM); - emit(HomeUpdateTree(graph: graph, builder: builder)); } diff --git a/lib/services/access_mang_api.dart b/lib/services/access_mang_api.dart new file mode 100644 index 00000000..0882e98b --- /dev/null +++ b/lib/services/access_mang_api.dart @@ -0,0 +1,36 @@ +import 'dart:convert'; + +import 'package:flutter/services.dart'; +import 'package:syncrow_web/pages/access_management/model/access_manag_model.dart'; +import 'package:syncrow_web/pages/auth/model/user_model.dart'; +import 'package:syncrow_web/services/api/http_service.dart'; +import 'package:syncrow_web/utils/constants/api_const.dart'; + +class AccessMangApi{ + + // Future> fetchInfo() async { + // final response = await HTTPService().get( + // path: '/Users/mohammad/StudioProjects/web_auth/assets/demo.json', + // showServerMessage: true, + // expectedResponseModel: (json) { + // print('fetchInfo=$json'); + // return (json as List).map((item) => AccessManagModel.fromJson(item)).toList(); + // }, + // ); + // return response; + // } + + Future> fetchInfo() async { + // Load the JSON file + final jsonString = await rootBundle.loadString('assets/dome.json'); + + // Parse the JSON string + final List jsonList = json.decode(jsonString); + print('jsonList=${jsonList.runtimeType}'); + print('jsonList=${jsonList}'); + // Convert the list of JSON objects to a list of AccessManagModel instances + final List accessList = jsonList.map((item) => AccessManagModel.fromJson(item)).toList(); + + return accessList; + } +} \ No newline at end of file diff --git a/lib/services/api/http_interceptor.dart b/lib/services/api/http_interceptor.dart index ff3fc0d4..cece39a7 100644 --- a/lib/services/api/http_interceptor.dart +++ b/lib/services/api/http_interceptor.dart @@ -13,7 +13,8 @@ class HTTPInterceptor extends InterceptorsWrapper { List headerExclusionListOfAddedParameters = [ ApiEndpoints.login, - ApiEndpoints.getRegion + ApiEndpoints.getRegion, + ApiEndpoints.sendOtp ]; @override diff --git a/lib/services/auth_api.dart b/lib/services/auth_api.dart index 58a705ff..3c7f3fbf 100644 --- a/lib/services/auth_api.dart +++ b/lib/services/auth_api.dart @@ -1,5 +1,7 @@ import 'dart:convert'; +import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; import 'package:syncrow_web/pages/auth/model/region_model.dart'; import 'package:syncrow_web/pages/auth/model/token.dart'; import 'package:syncrow_web/services/api/http_service.dart'; @@ -8,6 +10,7 @@ import 'package:syncrow_web/utils/constants/api_const.dart'; class AuthenticationAPI { static Future loginWithEmail({required var model}) async { + print('model=$model'); final response = await HTTPService().post( path: ApiEndpoints.login, body: model.toJson(), @@ -19,22 +22,57 @@ class AuthenticationAPI { } static Future forgetPassword( - {required var email, required var password}) async { + {required var email, required var password,}) async { final response = await HTTPService().post( path: ApiEndpoints.forgetPassword, - body: {"email": email, "password": password}, + body: { + "email": email, + "password": password + }, showServerMessage: true, expectedResponseModel: (json) {}); return response; } - static Future sendOtp({required var email}) async { - final response = await HTTPService().post( - path: ApiEndpoints.sendOtp, - body: {"email": email, "type": "VERIFICATION"}, - showServerMessage: true, - expectedResponseModel: (json) {}); - return response; + + static Future sendOtp({required String email, required String regionUuid}) async { + try { + final response = await HTTPService().post( + path: ApiEndpoints.sendOtp, + body: { + "email": email, + "type": "PASSWORD", + "regionUuid": regionUuid + }, + showServerMessage: true, + options: Options(), + expectedResponseModel: (json) { + Map parsedJson = jsonDecode(json); + int cooldown = parsedJson['data']['cooldown']; + debugPrint('Cooldown: $cooldown seconds'); + return cooldown; + } + ); + return response; + } on DioError catch (e) { + if (e.response != null) { + if (e.response!.statusCode == 400) { + // Handle 400 Bad Request + final errorData = e.response!.data; + String errorMessage = errorData['message'] ?? 'Unknown error'; + int cooldown = errorData['data']['cooldown'] ?? 0; + return cooldown; + } else { + debugPrint('Error: ${e.response!.statusCode} - ${e.response!.statusMessage}'); + } + } else { + debugPrint('Error: ${e.message}'); + } + return null; + } catch (e) { + debugPrint('Unexpected Error: $e'); + return null; + } } static Future verifyOtp( diff --git a/lib/services/home_api.dart b/lib/services/home_api.dart index 29ad30ab..42e732b4 100644 --- a/lib/services/home_api.dart +++ b/lib/services/home_api.dart @@ -3,13 +3,11 @@ import 'package:syncrow_web/services/api/http_service.dart'; import 'package:syncrow_web/utils/constants/api_const.dart'; class HomeApi{ - Future fetchUserInfo(userId) async { final response = await HTTPService().get( path: ApiEndpoints.getUser.replaceAll('{userUuid}', userId!), showServerMessage: true, expectedResponseModel: (json) { - print('user=$json'); return UserModel.fromJson(json); } ); diff --git a/lib/utils/color_manager.dart b/lib/utils/color_manager.dart index 492e5f8a..01e539dc 100644 --- a/lib/utils/color_manager.dart +++ b/lib/utils/color_manager.dart @@ -30,4 +30,5 @@ abstract class ColorsManager { static const Color btnColor = Color(0xFF00008B); static const Color blueColor = Color(0xFF0036E6); static const Color boxColor = Color(0xFFF5F6F7); + static const Color boxDivider = Color(0xFFE0E0E0); } diff --git a/lib/utils/constants/assets.dart b/lib/utils/constants/assets.dart index 0d0b3924..d53f82a7 100644 --- a/lib/utils/constants/assets.dart +++ b/lib/utils/constants/assets.dart @@ -23,4 +23,5 @@ class Assets { static const String energyIcon = "assets/images/energy_icon.svg"; static const String integrationsIcon = "assets/images/Integrations_icon.svg"; static const String assetIcon = "assets/images/asset_icon.svg"; + static const String calendarIcon = "assets/images/calendar_icon.svg"; } diff --git a/lib/utils/style.dart b/lib/utils/style.dart index 7260e78d..5edcdfad 100644 --- a/lib/utils/style.dart +++ b/lib/utils/style.dart @@ -23,4 +23,15 @@ InputDecoration? textBoxDecoration({bool suffixIcon = false}) => InputDecoration -Decoration containerDecoration = const BoxDecoration(color: Colors.white,borderRadius: BorderRadius.all(Radius.circular(20))); \ No newline at end of file +Decoration containerDecoration = BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 5, + blurRadius: 7, + offset: Offset(0, + 3), // changes position of shadow + ), + ], + color: ColorsManager.boxColor, + borderRadius: BorderRadius.all(Radius.circular(10))); \ No newline at end of file diff --git a/lib/web_layout/web_app_bar.dart b/lib/web_layout/web_app_bar.dart index f9316f05..7b1ee1a7 100644 --- a/lib/web_layout/web_app_bar.dart +++ b/lib/web_layout/web_app_bar.dart @@ -13,7 +13,7 @@ class WebAppBar extends StatelessWidget { Widget build(BuildContext context) { return BlocBuilder(builder: (context, state) { return Container( - height: 120, + height: 100, decoration: const BoxDecoration(color: ColorsManager.secondaryColor), padding: const EdgeInsets.all(10), child: Expanded( diff --git a/lib/web_layout/web_scaffold.dart b/lib/web_layout/web_scaffold.dart index e190dac1..567710bd 100644 --- a/lib/web_layout/web_scaffold.dart +++ b/lib/web_layout/web_scaffold.dart @@ -29,7 +29,7 @@ class WebScaffold extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Opacity( - opacity: 0.6, + opacity: 0.7, child: WebAppBar( title: appBarTitle, body: appBarBody, diff --git a/pubspec.yaml b/pubspec.yaml index b4c3f411..c1fd3f66 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -70,6 +70,7 @@ flutter: # To add assets to your application, add an assets section, like this: assets: - assets/images/ + - assets/ # An image asset can refer to one or more resolution-specific "variants", see