region and access_management ui

This commit is contained in:
mohammad
2024-08-12 14:36:46 +03:00
parent 1d226742e6
commit cb0ebcca37
28 changed files with 703 additions and 206 deletions

View File

@ -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(),
));
}
}

View File

@ -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()
)
],
),
],
),
));
}
}

View File

@ -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<AccessEvent, AccessState> {
AccessBloc() : super((AccessInitial())) {
on<FetchTableData>(_onFetchTableData);
}
String startTime = 'Start Time';
String endTime = 'End Time';
Future<void> _onFetchTableData(
FetchTableData event, Emitter<AccessState> emit) async {
try {
emit(AccessLoaded());
List<AccessManagModel> data = await AccessMangApi().fetchInfo();
print('objectwww888888${data[0].accessPeriod}');
emit(TableLoaded(data));
} catch (e) {
emit(FailedState(e.toString()));
}
}
}

View File

@ -0,0 +1,11 @@
import 'package:equatable/equatable.dart';
abstract class AccessEvent extends Equatable {
const AccessEvent();
@override
List<Object> get props => [];
}
class FetchTableData extends AccessEvent {}

View File

@ -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<Object> get props => [];
}
class AccessInitial extends AccessState {}
class AccessLoaded extends AccessState {}
class FailedState extends AccessState {
final String message;
FailedState(this.message);
@override
List<Object> get props => [message];
}
class TableLoaded extends AccessState {
final List<AccessManagModel> data;
const TableLoaded(this.data);
@override
List<Object> get props => [data];
}

View File

@ -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<String, dynamic> 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'],
);
}
}

View File

@ -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<AccessBloc, AccessState>(
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<AccessBloc>(context).startTime)),
const Icon(Icons.arrow_right_alt),
InkWell(child: Text(BlocProvider.of<AccessBloc>(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),),
),
);
}

View File

@ -23,6 +23,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
on<UpdateTimerEvent>(_onUpdateTimer);
on<PasswordVisibleEvent>(_passwordVisible);
on<RegionInitialEvent>(_fetchRegion);
on<SelectRegionEvent>(selectRegion);
}
////////////////////////////// forget password //////////////////////////////////
@ -32,7 +33,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
final forgetFormKey = GlobalKey<FormState>();
Timer? _timer;
int _remainingTime = 0;
List<RegionModel>? regionList;
List<RegionModel>? regionList=[RegionModel(name: 'name', id: 'id')];
Future<void> _onStartTimer(StartTimerEvent event, Emitter<AuthState> emit) async {
if (_validateInputs(emit)) return;
@ -42,7 +43,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
_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<AuthEvent, AuthState> {
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<AuthEvent, AuthState> {
model: LoginWithEmailModel(
email: event.username,
password: event.password,
regionUuid: event.regionUuid
),
);
} catch (failure) {
@ -274,15 +278,7 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
return '$maskedLocalPart@$domainPart';
}
final List<String> regions = [
'North America',
'South America',
'Europe',
'Asia',
'Africa',
'Australia',
'Antarctica',
];
static Future<String> getTokenAndValidate() async {
@ -317,8 +313,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
void _fetchRegion(RegionInitialEvent event, Emitter<AuthState> 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<AuthEvent, AuthState> {
}
Future selectRegion(SelectRegionEvent event, Emitter<AuthState> 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;
}
}

View File

@ -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<Object> get props => [username, password];
List<Object> 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<Object> get props => [val];
}

View File

@ -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,
});
}

View File

@ -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<String, dynamic> 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,
};
}
}

View File

@ -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<AuthBloc, AuthState>(
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<String>(
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<AuthBloc>(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<AuthBloc>(context).formattedTime(state.remainingTime)})" : ""}',
style: TextStyle(
color: state is TimerState && !state.isButtonEnabled
? Colors.grey

View File

@ -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<String>(
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,
),
);
}

View File

@ -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<LoginWebPage> {
Widget build(BuildContext context) {
return Scaffold(
body: BlocProvider(
create: (BuildContext context) => AuthBloc(),
create: (BuildContext context) => AuthBloc()..add(RegionInitialEvent()),
child: BlocConsumer<AuthBloc, AuthState>(
listener: (context, state) {
if (state is LoginSuccess) {
@ -153,13 +154,16 @@ class _LoginWebPageState extends State<LoginWebPage> {
),
isDense: true,
style: const TextStyle(color: Colors.black),
items:loginBloc.regions.map((String region) {
items:loginBloc.regionList!.map((RegionModel region) {
return DropdownMenuItem<String>(
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<LoginWebPage> {
onPressed: () {
if (loginBloc.loginFormKey.currentState!.validate()) {
loginBloc.add(LoginButtonPressed(
regionUuid:loginBloc.regionUuid ,
username: loginBloc.loginEmailController.text,
password: loginBloc.loginPasswordController.text,
),

View File

@ -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(

View File

@ -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<HomeEvent, HomeState> {
..levelSeparation = (150)
..subtreeSeparation = (150)
..orientation = (BuchheimWalkerConfiguration.ORIENTATION_TOP_BOTTOM);
emit(HomeUpdateTree(graph: graph, builder: builder));
}

View File

@ -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<List<AccessManagModel>> 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<List<AccessManagModel>> fetchInfo() async {
// Load the JSON file
final jsonString = await rootBundle.loadString('assets/dome.json');
// Parse the JSON string
final List<dynamic> 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<AccessManagModel> accessList = jsonList.map((item) => AccessManagModel.fromJson(item)).toList();
return accessList;
}
}

View File

@ -13,7 +13,8 @@ class HTTPInterceptor extends InterceptorsWrapper {
List<String> headerExclusionListOfAddedParameters = [
ApiEndpoints.login,
ApiEndpoints.getRegion
ApiEndpoints.getRegion,
ApiEndpoints.sendOtp
];
@override

View File

@ -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<Token> 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<int?> sendOtp({required String email, required String regionUuid}) async {
try {
final response = await HTTPService().post(
path: ApiEndpoints.sendOtp,
body: {
"email": email,
"type": "PASSWORD",
"regionUuid": regionUuid
},
showServerMessage: true,
options: Options(),
expectedResponseModel: (json) {
Map<String, dynamic> 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<bool> verifyOtp(

View File

@ -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);
}
);

View File

@ -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);
}

View File

@ -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";
}

View File

@ -23,4 +23,15 @@ InputDecoration? textBoxDecoration({bool suffixIcon = false}) => InputDecoration
Decoration containerDecoration = const BoxDecoration(color: Colors.white,borderRadius: BorderRadius.all(Radius.circular(20)));
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)));

View File

@ -13,7 +13,7 @@ class WebAppBar extends StatelessWidget {
Widget build(BuildContext context) {
return BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
return Container(
height: 120,
height: 100,
decoration: const BoxDecoration(color: ColorsManager.secondaryColor),
padding: const EdgeInsets.all(10),
child: Expanded(

View File

@ -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,