get user info and access management page

This commit is contained in:
mohammad
2024-08-08 16:54:02 +03:00
parent ab0551b2ce
commit 1d226742e6
13 changed files with 385 additions and 115 deletions

View File

@ -1,7 +1,9 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
import 'package:syncrow_web/pages/auth/view/login_page.dart';
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
import 'package:syncrow_web/pages/home/view/home_page.dart';
import 'package:syncrow_web/services/locator.dart';
import 'package:syncrow_web/utils/color_manager.dart';
@ -23,7 +25,13 @@ class MyApp extends StatelessWidget {
});
@override
Widget build(BuildContext context) {
return MaterialApp(
return MultiBlocProvider(
providers: [
BlocProvider(create: (context) => HomeBloc()),
],
child:
MaterialApp(
debugShowCheckedModeBanner: false, // Hide debug banner
scrollBehavior: const MaterialScrollBehavior().copyWith(
dragDevices: {
@ -51,6 +59,6 @@ class MyApp extends StatelessWidget {
useMaterial3: true, // Enable Material 3
),
home: isLoggedIn == 'Success' ? const HomePage() : const LoginPage(),
);
));
}
}

View File

@ -0,0 +1,142 @@
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

@ -6,19 +6,17 @@ class UserModel {
static String userUuidKey = 'userUuid';
final String? uuid;
final String? email;
final String? name;
final String? firstName;
final String? lastName;
final String? photoUrl;
final String? phoneNumber;
final bool? isEmailVerified;
final bool? isAgreementAccepted;
UserModel({
required this.uuid,
required this.email,
required this.name,
required this.firstName,
required this.lastName,
required this.photoUrl,
required this.phoneNumber,
required this.isEmailVerified,
@ -29,7 +27,8 @@ class UserModel {
return UserModel(
uuid: json['id'],
email: json['email'],
name: json['name'],
firstName: json['firstName'],
lastName: json['lastName'],
photoUrl: json['photoUrl'],
phoneNumber: json['phoneNumber'],
isEmailVerified: json['isEmailVerified'],
@ -46,7 +45,8 @@ class UserModel {
return UserModel(
uuid: tempJson['uuid'].toString(),
email: tempJson['email'],
name: null,
firstName: null,
lastName: null,
photoUrl: null,
phoneNumber: null,
isEmailVerified: null,
@ -58,7 +58,8 @@ class UserModel {
return {
'id': uuid,
'email': email,
'name': name,
'firstName': firstName,
'lastName': lastName,
'photoUrl': photoUrl,
'phoneNumber': phoneNumber,
'isEmailVerified': isEmailVerified,

View File

@ -1,23 +1,34 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:graphview/GraphView.dart';
import 'package:syncrow_web/pages/access_management/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';
import 'package:syncrow_web/pages/home/home_model/home_item_model.dart';
import 'package:syncrow_web/services/home_api.dart';
import 'package:syncrow_web/utils/color_manager.dart';
import 'package:syncrow_web/utils/constants/assets.dart';
class HomeBloc extends Bloc<HomeEvent, HomeState> {
final Graph graph = Graph()..isTree = true;
final BuchheimWalkerConfiguration builder = BuchheimWalkerConfiguration();
List<Node> sourcesList = [];
List<Node> destinationsList = [];
static UserModel? user;
HomeBloc() : super((HomeInitial())) {
on<CreateNewNode>(_createNode);
fetchUserInfo();
}
void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
emit(HomeInitial());
sourcesList.add(event.sourceNode);
destinationsList.add(event.destinationNode);
for (int i = 0; i < sourcesList.length; i++) {
graph.addEdge(sourcesList[i], destinationsList[i]);
}
@ -30,4 +41,87 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
emit(HomeUpdateTree(graph: graph, builder: builder));
}
Future fetchUserInfo() async {
try {
var uuid =
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
user = await HomeApi().fetchUserInfo(uuid);
emit(HomeUserInfoLoaded(user!)); // Emit state after fetching user info
} catch (e) {
return;
}
}
List<HomeItemModel> homeItems = [
HomeItemModel(
title: 'Access',
icon: Assets.accessIcon,
active: true,
onPress: (context) {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => AccessManagementPage()),
);
},
color: null,
),
HomeItemModel(
title: 'Space\nManagement',
icon: Assets.spaseManagementIcon,
active: true,
onPress: (context) {
},
color: ColorsManager.primaryColor,
),
HomeItemModel(
title: 'Devices',
icon: Assets.devicesIcon,
active: true,
onPress: (context) {
},
color: ColorsManager.primaryColor,
),
HomeItemModel(
title: 'Move in',
icon: Assets.moveinIcon,
active: false,
onPress: (context) {
},
color: ColorsManager.primaryColor,
),
HomeItemModel(
title: 'Construction',
icon: Assets.constructionIcon,
active: false,
onPress: (context) {
},
color: ColorsManager.primaryColor,
),
HomeItemModel(
title: 'Energy',
icon: Assets.energyIcon,
active: false,
onPress: (context) {
},
color: ColorsManager.slidingBlueColor.withOpacity(0.2),
),
HomeItemModel(
title: 'Integrations',
icon: Assets.integrationsIcon,
active: false,
onPress: (context) {
},
color: ColorsManager.slidingBlueColor.withOpacity(0.2),
),
HomeItemModel(
title: 'Asset',
icon: Assets.assetIcon,
active: false,
onPress: (context) {
},
color: ColorsManager.slidingBlueColor.withOpacity(0.2),
),
];
}

View File

@ -1,5 +1,6 @@
import 'package:equatable/equatable.dart';
import 'package:graphview/GraphView.dart';
import 'package:syncrow_web/pages/auth/model/user_model.dart';
abstract class HomeState extends Equatable {
const HomeState();
@ -24,3 +25,8 @@ class HomeUpdateTree extends HomeState {
@override
List<Object> get props => [graph, builder];
}
class HomeUserInfoLoaded extends HomeState {
final UserModel user;
HomeUserInfoLoaded(this.user);
}

View File

@ -0,0 +1,22 @@
import 'package:flutter/cupertino.dart';
class HomeItemModel {
final String? title;
final String? icon;
final Color? color;
final bool? active;
final void Function(BuildContext context) onPress;
HomeItemModel({
this.title,
this.icon,
this.color,
this.active,
required this.onPress,
});
}

View File

@ -7,113 +7,75 @@ 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';
import '../bloc/home_state.dart';
class HomeWebPage extends StatelessWidget {
HomeWebPage({super.key});
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
return WebScaffold(
enableMenuSideba:false ,
appBarTitle: Row(
children: [
SvgPicture.asset(
Assets.loginLogo,
width: 150,
),
],
),
scaffoldBody: BlocProvider(
create: (context) => HomeBloc(),
child: SizedBox(
height: size.height,
width: size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: size.height * 0.1),
const Text(
'ACCESS YOUR APPS',
style: TextStyle(fontSize: 40, fontWeight: FontWeight.w700),
),
const SizedBox(height: 30),
Expanded(
flex: 4,
child: SizedBox(
height: size.height * 0.6,
width: size.width * 0.68,
child: GridView.builder(
itemCount: 8,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
crossAxisSpacing: 20.0,
mainAxisSpacing: 20.0,
childAspectRatio: 1.5,
),
itemBuilder: (context, index) {
return HomeCard(
index:index,
active:ceilingSensorButtons[index]['active'],
name: ceilingSensorButtons[index]['title'],
img:ceilingSensorButtons[index]['icon'] ,
onTap: () {
},);
},
),
),
),
],
),
enableMenuSideba: false,
appBarTitle: Row(
children: [
SvgPicture.asset(
Assets.loginLogo,
width: 150,
),
],
),
),
);
scaffoldBody: BlocProvider(
create: (context) => HomeBloc(),
child: BlocConsumer<HomeBloc, HomeState>(
listener: (BuildContext context, state) {},
builder: (context, state) {
final homeBloc = BlocProvider.of<HomeBloc>(context);
return SizedBox(
height: size.height,
width: size.width,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(height: size.height * 0.1),
Text(
'ACCESS YOUR APPS',
style: Theme.of(context)
.textTheme.headlineLarge!
.copyWith(color: Colors.black, fontSize: 40),
),
const SizedBox(height: 30),
Expanded(
flex: 4,
child: SizedBox(
height: size.height * 0.6,
width: size.width * 0.68,
child: GridView.builder(
itemCount: 8,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 4,
crossAxisSpacing: 20.0,
mainAxisSpacing: 20.0,
childAspectRatio: 1.5,
),
itemBuilder: (context, index) {
return HomeCard(
index: index,
active: homeBloc.homeItems[index].active!,
name: homeBloc.homeItems[index].title!,
img: homeBloc.homeItems[index].icon!,
onTap: () => homeBloc.homeItems[index].onPress(context),
);
},
),
),
),
],
),
);
},
),
));
}
dynamic ceilingSensorButtons =
[
{
'title': 'Access',
'icon': Assets.accessIcon,
'active': true,
},
{
'title': 'Space\nManagement',
'icon': Assets.spaseManagementIcon,
'color': ColorsManager.primaryColor,
'active': true,
},
{
'title': 'Devices',
'icon':Assets.devicesIcon,
'active': true,
},
{
'title': 'Move in',
'icon': Assets.moveinIcon,
'active': false,
},
{
'title': 'Construction',
'icon': Assets.constructionIcon,
'active': false,
},
{
'title': 'Energy',
'icon': Assets.energyIcon,
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
'active': false,
},
{
'title': 'Integrations',
'icon': Assets.integrationsIcon,
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
'active': false,
}, {
'title': 'Asset',
'icon': Assets.assetIcon,
'color': ColorsManager.slidingBlueColor.withOpacity(0.2),
'active': false,
},
];
}

View File

@ -0,0 +1,18 @@
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 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);
}
);
return response;
}
}

View File

@ -29,4 +29,5 @@ abstract class ColorsManager {
static const Color textGray = Color(0xffD5D5D5);
static const Color btnColor = Color(0xFF00008B);
static const Color blueColor = Color(0xFF0036E6);
static const Color boxColor = Color(0xFFF5F6F7);
}

View File

@ -9,4 +9,5 @@ abstract class ApiEndpoints {
static const String sendOtp = '$baseUrl/authentication/user/send-otp';
static const String verifyOtp = '$baseUrl/authentication/user/verify-otp';
static const String getRegion = '$baseUrl/region';
static const String getUser = '$baseUrl/user/{userUuid}';
}

View File

@ -1,4 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
import 'package:syncrow_web/utils/color_manager.dart';
class WebAppBar extends StatelessWidget {
@ -8,7 +11,8 @@ class WebAppBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
return BlocBuilder<HomeBloc, HomeState>(builder: (context, state) {
return Container(
height: 120,
decoration: const BoxDecoration(color: ColorsManager.secondaryColor),
padding: const EdgeInsets.all(10),
@ -48,8 +52,9 @@ class WebAppBar extends StatelessWidget {
const SizedBox(
width: 10,
),
if(HomeBloc.user!=null)
Text(
'mohamamd alnemer ',
'${HomeBloc.user!.firstName.toString() ?? ''} ${HomeBloc.user!.lastName.toString() ?? ''} ',
style: Theme.of(context).textTheme.bodyLarge,
),
],
@ -58,5 +63,6 @@ class WebAppBar extends StatelessWidget {
),
),
);
});
}
}

View File

@ -65,6 +65,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.0.8"
data_table_2:
dependency: "direct main"
description:
name: data_table_2
sha256: f02ec9b24f44420816a87370ff4f4e533e15b274f6267e4c9a88a585ad1a0473
url: "https://pub.dev"
source: hosted
version: "2.5.15"
dio:
dependency: "direct main"
description:

View File

@ -43,6 +43,7 @@ dependencies:
get_it: ^7.6.7
flutter_secure_storage: ^9.2.2
shared_preferences: ^2.3.0
data_table_2: ^2.5.15
dev_dependencies:
flutter_test: