mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-09 22:57:21 +00:00
add_user_dialog
This commit is contained in:
3
assets/icons/arrow_down.svg
Normal file
3
assets/icons/arrow_down.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="8" height="5" viewBox="0 0 8 5" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M8 0.740463C8 0.574789 7.93931 0.408979 7.8179 0.282701C7.57528 0.0297901 7.18168 0.0297901 6.93903 0.282701L4 3.34404L1.06095 0.282701C0.818322 0.0297898 0.424717 0.0297898 0.182084 0.282701C-0.0606947 0.535291 -0.0606947 0.945601 0.182084 1.19819L3.56055 4.71746C3.80318 4.97034 4.1968 4.97034 4.43945 4.71746L7.8179 1.19819C7.93932 1.07191 8 0.906104 8 0.740463Z" fill="#999999" fill-opacity="0.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 511 B |
3
assets/icons/arrow_forward.svg
Normal file
3
assets/icons/arrow_forward.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="5" height="9" viewBox="0 0 5 9" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M0.647445 0.5C0.481771 0.5 0.315961 0.560695 0.189683 0.6821C-0.0632278 0.924716 -0.0632278 1.31832 0.189683 1.56097L3.25102 4.5L0.189683 7.43905C-0.0632278 7.68168 -0.0632278 8.07528 0.189683 8.31792C0.442273 8.56069 0.852583 8.56069 1.10517 8.31792L4.62444 4.93945C4.87732 4.69682 4.87732 4.3032 4.62444 4.06055L1.10517 0.6821C0.978895 0.560678 0.813086 0.5 0.647445 0.5Z" fill="#999999" fill-opacity="0.7"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 519 B |
@ -3,12 +3,18 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_event.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_status.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_status.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/model/tree_node_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/model/community_model.dart';
|
||||||
|
import 'package:syncrow_web/pages/spaces_management/model/space_model.dart';
|
||||||
|
import 'package:syncrow_web/services/space_mana_api.dart';
|
||||||
|
|
||||||
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||||
UsersBloc() : super(UsersInitial()) {
|
UsersBloc() : super(UsersInitial()) {
|
||||||
on<GetUsers>(_getUsers);
|
on<GetUsers>(_getUsers);
|
||||||
on<ChangeUserStatus>(_changeUserStatus);
|
on<ChangeUserStatus>(_changeUserStatus);
|
||||||
on<CheckStepStatus>(isCompleteBasicsFun);
|
on<CheckStepStatus>(isCompleteBasicsFun);
|
||||||
|
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
|
||||||
|
on<SearchAnode>(searchTreeNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<RolesUserModel> users = [];
|
List<RolesUserModel> users = [];
|
||||||
@ -86,9 +92,9 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
final TextEditingController phoneController = TextEditingController();
|
final TextEditingController phoneController = TextEditingController();
|
||||||
final TextEditingController jobTitleController = TextEditingController();
|
final TextEditingController jobTitleController = TextEditingController();
|
||||||
|
|
||||||
bool isCompleteBasics = false;
|
bool? isCompleteBasics;
|
||||||
bool isCompleteRolePermissions = false;
|
bool? isCompleteRolePermissions;
|
||||||
bool isCompleteSpaces = false;
|
bool? isCompleteSpaces;
|
||||||
|
|
||||||
int numberBasics = 0;
|
int numberBasics = 0;
|
||||||
int numberSpaces = 0;
|
int numberSpaces = 0;
|
||||||
@ -102,35 +108,137 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
|||||||
phoneController.text.isNotEmpty &&
|
phoneController.text.isNotEmpty &&
|
||||||
jobTitleController.text.isNotEmpty;
|
jobTitleController.text.isNotEmpty;
|
||||||
emit(ChangeStatusSteps());
|
emit(ChangeStatusSteps());
|
||||||
|
return isCompleteBasics;
|
||||||
}
|
}
|
||||||
|
|
||||||
// void checkStatus(CheckStepStatus event, Emitter<UsersState> emit) {
|
isCompleteSpacesFun(CheckStepStatus event, Emitter<UsersState> emit) {
|
||||||
// try {
|
emit(UsersLoadingState());
|
||||||
// // Check if basic fields are completed
|
isCompleteSpaces = false;
|
||||||
// isCompleteBasics = firstNameController.text.isNotEmpty &&
|
emit(ChangeStatusSteps());
|
||||||
// lastNameController.text.isNotEmpty &&
|
print('isCompleteBasics==$isCompleteSpaces');
|
||||||
// emailController.text.isNotEmpty &&
|
return isCompleteSpaces;
|
||||||
// phoneController.text.isNotEmpty &&
|
}
|
||||||
// jobTitleController.text.isNotEmpty;
|
|
||||||
// // Emit the updated state
|
|
||||||
// if (isCompleteBasics && isCompleteRolePermissions && isCompleteSpaces) {
|
|
||||||
// } else {
|
|
||||||
// // emit(IncompleteState(
|
|
||||||
// // isCompleteBasics, isCompleteRolePermissions, isCompleteSpaces));
|
|
||||||
// }
|
|
||||||
// } catch (e) {
|
|
||||||
// emit(ErrorState(e.toString()));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// Example placeholder methods for role permissions and spaces
|
|
||||||
bool checkRolePermissions() {
|
bool checkRolePermissions() {
|
||||||
// Add logic to check if role permissions are completed
|
return true;
|
||||||
return true; // Replace with actual logic
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkSpaces() {
|
bool checkSpaces() {
|
||||||
// Add logic to check if spaces are completed
|
return true;
|
||||||
return true; // Replace with actual logic
|
}
|
||||||
|
|
||||||
|
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
||||||
|
String communityUuid) async {
|
||||||
|
return await CommunitySpaceManagementApi().getSpaceHierarchy(communityUuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<TreeNode> updatedCommunities = [];
|
||||||
|
List<TreeNode> spacesNodes = [];
|
||||||
|
_onLoadCommunityAndSpaces(
|
||||||
|
LoadCommunityAndSpacesEvent event,
|
||||||
|
Emitter<UsersState> emit,
|
||||||
|
) async {
|
||||||
|
emit(UsersLoadingState()); // Emit loading state
|
||||||
|
try {
|
||||||
|
// Fetch the list of communities
|
||||||
|
List<CommunityModel> communities =
|
||||||
|
await CommunitySpaceManagementApi().fetchCommunities();
|
||||||
|
|
||||||
|
// Fetch spaces and create TreeNodes for each community
|
||||||
|
updatedCommunities = await Future.wait(
|
||||||
|
communities.map((community) async {
|
||||||
|
// Fetch spaces for the current community
|
||||||
|
List<SpaceModel> spaces =
|
||||||
|
await _fetchSpacesForCommunity(community.uuid);
|
||||||
|
|
||||||
|
// Recursively build the tree structure
|
||||||
|
spacesNodes = _buildTreeNodes(spaces);
|
||||||
|
|
||||||
|
// Return a TreeNode for the community, with spaces as its children
|
||||||
|
return TreeNode(
|
||||||
|
uuid: community.uuid,
|
||||||
|
title: community.name,
|
||||||
|
children: spacesNodes,
|
||||||
|
isChecked: false, // Initial state; can be updated later
|
||||||
|
isHighlighted: false,
|
||||||
|
isExpanded: true, // Default to expanded for better UX
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Emit the final state with the structured tree
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
|
||||||
|
return updatedCommunities; // Return the structured data if needed
|
||||||
|
} catch (e) {
|
||||||
|
// Emit error state in case of failure
|
||||||
|
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to recursively build tree nodes
|
||||||
|
List<TreeNode> _buildTreeNodes(List<SpaceModel> spaces) {
|
||||||
|
return spaces.map((space) {
|
||||||
|
// If the space has children, recursively build nodes for them
|
||||||
|
List<TreeNode> childNodes =
|
||||||
|
space.children != null ? _buildTreeNodes(space.children!) : [];
|
||||||
|
|
||||||
|
// Create a TreeNode for the current space
|
||||||
|
return TreeNode(
|
||||||
|
uuid: space.uuid!,
|
||||||
|
title: space.name,
|
||||||
|
isChecked: false,
|
||||||
|
isHighlighted: false,
|
||||||
|
isExpanded: childNodes.isNotEmpty, // Expand if there are children
|
||||||
|
children: childNodes,
|
||||||
|
);
|
||||||
|
}).toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void searchTreeNode(SearchAnode event, Emitter<UsersState> emit) {
|
||||||
|
emit(UsersLoadingState()); // Emit loading state
|
||||||
|
|
||||||
|
// Clear all highlights if the search term is empty
|
||||||
|
if (event.searchTerm!.isEmpty) {
|
||||||
|
_clearHighlights(updatedCommunities);
|
||||||
|
} else {
|
||||||
|
// Perform the search and update the highlights
|
||||||
|
_searchAndHighlightNodes(updatedCommunities, event.searchTerm!);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Emit the updated state after processing all nodes
|
||||||
|
emit(ChangeStatusSteps());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to clear all highlights in the tree
|
||||||
|
void _clearHighlights(List<TreeNode> nodes) {
|
||||||
|
for (var node in nodes) {
|
||||||
|
node.isHighlighted = false;
|
||||||
|
if (node.children.isNotEmpty) {
|
||||||
|
_clearHighlights(node.children);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to search and highlight nodes recursively
|
||||||
|
bool _searchAndHighlightNodes(List<TreeNode> nodes, String searchTerm) {
|
||||||
|
bool anyMatch = false;
|
||||||
|
|
||||||
|
for (var node in nodes) {
|
||||||
|
// Check if this node matches the search term
|
||||||
|
bool isMatch =
|
||||||
|
node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||||
|
|
||||||
|
// Recursively check children for matches
|
||||||
|
bool childMatch = _searchAndHighlightNodes(node.children, searchTerm);
|
||||||
|
|
||||||
|
// Highlight this node if it matches or any of its children match
|
||||||
|
node.isHighlighted = isMatch || childMatch;
|
||||||
|
|
||||||
|
// Update if any matches were found in this branch
|
||||||
|
anyMatch = anyMatch || node.isHighlighted;
|
||||||
|
}
|
||||||
|
|
||||||
|
return anyMatch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/model/tree_node_model.dart';
|
||||||
|
|
||||||
sealed class UsersEvent extends Equatable {
|
sealed class UsersEvent extends Equatable {
|
||||||
const UsersEvent();
|
const UsersEvent();
|
||||||
@ -10,6 +11,12 @@ class GetUsers extends UsersEvent {
|
|||||||
List<Object?> get props => [];
|
List<Object?> get props => [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class LoadCommunityAndSpacesEvent extends UsersEvent {
|
||||||
|
const LoadCommunityAndSpacesEvent();
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
|
|
||||||
class GetBatchStatus extends UsersEvent {
|
class GetBatchStatus extends UsersEvent {
|
||||||
final List<String> uuids;
|
final List<String> uuids;
|
||||||
const GetBatchStatus(this.uuids);
|
const GetBatchStatus(this.uuids);
|
||||||
@ -17,6 +24,7 @@ class GetBatchStatus extends UsersEvent {
|
|||||||
List<Object?> get props => [uuids];
|
List<Object?> get props => [uuids];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//LoadCommunityAndSpacesEvent
|
||||||
class ChangeUserStatus extends UsersEvent {
|
class ChangeUserStatus extends UsersEvent {
|
||||||
final String userId;
|
final String userId;
|
||||||
final String newStatus;
|
final String newStatus;
|
||||||
@ -33,3 +41,11 @@ class CheckStepStatus extends UsersEvent {
|
|||||||
@override
|
@override
|
||||||
List<Object?> get props => [steps];
|
List<Object?> get props => [steps];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SearchAnode extends UsersEvent {
|
||||||
|
List<TreeNode>? nodes;
|
||||||
|
String? searchTerm;
|
||||||
|
SearchAnode({this.nodes, this.searchTerm});
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [nodes, searchTerm];
|
||||||
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
class TreeNode {
|
||||||
|
String uuid;
|
||||||
|
String title;
|
||||||
|
bool isChecked;
|
||||||
|
bool isHighlighted;
|
||||||
|
bool isExpanded;
|
||||||
|
List<TreeNode> children;
|
||||||
|
|
||||||
|
TreeNode({
|
||||||
|
required this.uuid,
|
||||||
|
required this.title,
|
||||||
|
this.isChecked = false,
|
||||||
|
this.isHighlighted = false,
|
||||||
|
this.isExpanded = false,
|
||||||
|
this.children = const [],
|
||||||
|
});
|
||||||
|
}
|
@ -2,6 +2,7 @@ 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:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_status.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_status.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/view/basics_view.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/view/basics_view.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/view/roles_and_permission.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/view/roles_and_permission.dart';
|
||||||
@ -22,7 +23,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (BuildContext context) => UsersBloc(),
|
create: (BuildContext context) => UsersBloc()..add(LoadCommunityAndSpacesEvent()),
|
||||||
child: BlocConsumer<UsersBloc, UsersState>(
|
child: BlocConsumer<UsersBloc, UsersState>(
|
||||||
listener: (context, state) {},
|
listener: (context, state) {},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
@ -58,9 +59,9 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
_buildStepIndicator(1, "Basics", _blocRole),
|
_buildStep1Indicator(1, "Basics", _blocRole),
|
||||||
_buildStepIndicator(2, "Spaces", _blocRole),
|
_buildStep2Indicator(2, "Spaces", _blocRole),
|
||||||
_buildStepIndicator(
|
_buildStep3Indicator(
|
||||||
3, "Role & Permissions", _blocRole),
|
3, "Role & Permissions", _blocRole),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@ -120,14 +121,13 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method to get the form content based on the current step
|
|
||||||
Widget _getFormContent() {
|
Widget _getFormContent() {
|
||||||
switch (currentStep) {
|
switch (currentStep) {
|
||||||
case 1:
|
case 1:
|
||||||
@ -141,22 +141,70 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to build step indicators
|
Widget _buildStep2Indicator(int step, String label, UsersBloc bloc) {
|
||||||
Widget _buildStepIndicator(int step, String label, UsersBloc bloc) {
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
currentStep = step;
|
||||||
|
bloc.add(const CheckStepStatus());
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(5.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
currentStep == step
|
||||||
|
? Assets.currentProcessIcon
|
||||||
|
: bloc.isCompleteSpaces == false
|
||||||
|
? Assets.wrongProcessIcon
|
||||||
|
: Assets.uncomplete_ProcessIcon,
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: currentStep == step
|
||||||
|
? ColorsManager.blackColor
|
||||||
|
: ColorsManager.greyColor,
|
||||||
|
fontWeight: currentStep == step
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (step != 3)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(5.0),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 12),
|
||||||
|
child: Container(
|
||||||
|
height: 60,
|
||||||
|
width: 1,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildStep1Indicator(int step, String label, UsersBloc bloc) {
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
// if (bloc.formKey.currentState?.validate() ?? false) {
|
|
||||||
setState(() {
|
setState(() {
|
||||||
currentStep = step;
|
currentStep = step;
|
||||||
if (currentStep == 1) {
|
|
||||||
bloc.numberBasics = 1;
|
|
||||||
} else if (currentStep == 2) {
|
|
||||||
bloc.numberSpaces = 2;
|
|
||||||
} else if (currentStep == 3) {
|
|
||||||
bloc.numberRole = 3;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
// }
|
|
||||||
},
|
},
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@ -170,12 +218,67 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
|||||||
currentStep == step
|
currentStep == step
|
||||||
? Assets.currentProcessIcon
|
? Assets.currentProcessIcon
|
||||||
: bloc.isCompleteBasics == false
|
: bloc.isCompleteBasics == false
|
||||||
&& (bloc.numberBasics != 0 ||
|
? Assets.wrongProcessIcon
|
||||||
bloc.numberRole != 0 ||
|
: bloc.isCompleteBasics == true
|
||||||
bloc.numberSpaces != 0)
|
? Assets.completeProcessIcon
|
||||||
? Assets.wrongProcessIcon
|
|
||||||
: Assets.uncomplete_ProcessIcon,
|
: Assets.uncomplete_ProcessIcon,
|
||||||
|
width: 25,
|
||||||
|
height: 25,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 10),
|
||||||
|
Text(
|
||||||
|
label,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: currentStep == step
|
||||||
|
? ColorsManager.blackColor
|
||||||
|
: ColorsManager.greyColor,
|
||||||
|
fontWeight: currentStep == step
|
||||||
|
? FontWeight.bold
|
||||||
|
: FontWeight.normal,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (step != 3)
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(5.0),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(left: 12),
|
||||||
|
child: Container(
|
||||||
|
height: 60,
|
||||||
|
width: 1,
|
||||||
|
color: Colors.grey,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildStep3Indicator(int step, String label, UsersBloc bloc) {
|
||||||
|
return GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
currentStep = step;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.all(5.0),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
SvgPicture.asset(
|
||||||
|
currentStep == step
|
||||||
|
? Assets.currentProcessIcon
|
||||||
|
: bloc.isCompleteRolePermissions == false
|
||||||
|
? Assets.wrongProcessIcon
|
||||||
|
: Assets.uncomplete_ProcessIcon,
|
||||||
width: 25,
|
width: 25,
|
||||||
height: 25,
|
height: 25,
|
||||||
),
|
),
|
||||||
|
@ -199,6 +199,8 @@ class DeviceManagement extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _DeviceManagementState extends State<DeviceManagement> {
|
class _DeviceManagementState extends State<DeviceManagement> {
|
||||||
|
|
||||||
|
|
||||||
final List<MainRoleOption> options = [
|
final List<MainRoleOption> options = [
|
||||||
MainRoleOption(
|
MainRoleOption(
|
||||||
id: '1',
|
id: '1',
|
||||||
|
@ -2,7 +2,9 @@ import 'package:flutter/material.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:syncrow_web/pages/roles_and_permission/users_page/bloc/users_bloc.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_bloc.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_event.dart';
|
||||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_status.dart';
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_status.dart';
|
||||||
|
import 'package:syncrow_web/pages/roles_and_permission/users_page/model/tree_node_model.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/extension/build_context_x.dart';
|
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||||
@ -68,7 +70,12 @@ class SpacesAccessView extends StatelessWidget {
|
|||||||
child: TextFormField(
|
child: TextFormField(
|
||||||
style:
|
style:
|
||||||
const TextStyle(color: Colors.black),
|
const TextStyle(color: Colors.black),
|
||||||
controller: _blocRole.firstNameController,
|
// controller: _blocRole.firstNameController,
|
||||||
|
onChanged: (value) {
|
||||||
|
_blocRole.add(SearchAnode(
|
||||||
|
nodes: _blocRole.updatedCommunities,
|
||||||
|
searchTerm: value));
|
||||||
|
},
|
||||||
decoration: textBoxDecoration(radios: 20)!
|
decoration: textBoxDecoration(radios: 20)!
|
||||||
.copyWith(
|
.copyWith(
|
||||||
fillColor: Colors.white,
|
fillColor: Colors.white,
|
||||||
@ -102,7 +109,9 @@ class SpacesAccessView extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Container(
|
child: Container(
|
||||||
color: ColorsManager.whiteColors,
|
color: ColorsManager.whiteColors,
|
||||||
child: TreeView())))
|
child: TreeView(
|
||||||
|
bloc: _blocRole,
|
||||||
|
))))
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -115,90 +124,15 @@ class SpacesAccessView extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TreeNode {
|
// ignore: must_be_immutable
|
||||||
String title;
|
|
||||||
bool isChecked;
|
|
||||||
bool isHighlighted;
|
|
||||||
bool isExpanded; // New property to manage expansion
|
|
||||||
List<TreeNode> children;
|
|
||||||
|
|
||||||
TreeNode({
|
|
||||||
required this.title,
|
|
||||||
this.isChecked = false,
|
|
||||||
this.isHighlighted = false,
|
|
||||||
this.isExpanded = false, // Default to collapsed
|
|
||||||
this.children = const [],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
class TreeView extends StatefulWidget {
|
class TreeView extends StatefulWidget {
|
||||||
|
UsersBloc? bloc;
|
||||||
|
TreeView({super.key, this.bloc});
|
||||||
@override
|
@override
|
||||||
_TreeViewState createState() => _TreeViewState();
|
_TreeViewState createState() => _TreeViewState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TreeViewState extends State<TreeView> {
|
class _TreeViewState extends State<TreeView> {
|
||||||
List<TreeNode> treeData = [
|
|
||||||
TreeNode(
|
|
||||||
title: 'Downtown Dubai',
|
|
||||||
),
|
|
||||||
TreeNode(title: 'Dubai Creek Harbour', isHighlighted: true),
|
|
||||||
TreeNode(
|
|
||||||
title: 'Dubai Hills Estate',
|
|
||||||
isHighlighted: true,
|
|
||||||
children: [
|
|
||||||
TreeNode(title: 'North Side'),
|
|
||||||
TreeNode(
|
|
||||||
title: 'South Side',
|
|
||||||
isHighlighted: true,
|
|
||||||
children: [
|
|
||||||
TreeNode(title: 'Hills Business Park'),
|
|
||||||
TreeNode(title: 'Park Point'),
|
|
||||||
TreeNode(title: 'Acacia'),
|
|
||||||
TreeNode(
|
|
||||||
title: 'Executive Residence',
|
|
||||||
children: [
|
|
||||||
TreeNode(title: 'Residence I'),
|
|
||||||
TreeNode(
|
|
||||||
title: 'Residence II',
|
|
||||||
children: [
|
|
||||||
TreeNode(title: 'Ground Floor', isHighlighted: true),
|
|
||||||
TreeNode(title: '1st Floor', isHighlighted: true),
|
|
||||||
TreeNode(title: 'Pool', isHighlighted: true),
|
|
||||||
TreeNode(title: 'Gym', isHighlighted: true),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
TreeNode(
|
|
||||||
title: 'South Side',
|
|
||||||
isHighlighted: true,
|
|
||||||
children: [
|
|
||||||
TreeNode(title: 'Hills Business Park'),
|
|
||||||
TreeNode(title: 'Park Point'),
|
|
||||||
TreeNode(title: 'Acacia'),
|
|
||||||
TreeNode(
|
|
||||||
title: 'Executive Residence',
|
|
||||||
children: [
|
|
||||||
TreeNode(title: 'Residence I'),
|
|
||||||
TreeNode(
|
|
||||||
title: 'Residence II',
|
|
||||||
children: [
|
|
||||||
TreeNode(title: 'Ground Floor', isHighlighted: true),
|
|
||||||
TreeNode(title: '1st Floor', isHighlighted: true),
|
|
||||||
TreeNode(title: 'Pool', isHighlighted: true),
|
|
||||||
TreeNode(title: 'Gym', isHighlighted: true),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
];
|
|
||||||
|
|
||||||
Widget _buildTree(List<TreeNode> nodes, {int level = 0}) {
|
Widget _buildTree(List<TreeNode> nodes, {int level = 0}) {
|
||||||
return Column(
|
return Column(
|
||||||
children: nodes.map((node) => _buildNode(node, level: level)).toList(),
|
children: nodes.map((node) => _buildNode(node, level: level)).toList(),
|
||||||
@ -207,31 +141,14 @@ class _TreeViewState extends State<TreeView> {
|
|||||||
|
|
||||||
Widget _buildNode(TreeNode node, {int level = 0}) {
|
Widget _buildNode(TreeNode node, {int level = 0}) {
|
||||||
return Container(
|
return Container(
|
||||||
color: node.isHighlighted ? Colors.blue.shade100 : Colors.transparent,
|
color: node.isHighlighted ? Colors.blue.shade50 : Colors.transparent,
|
||||||
child: Padding(
|
child: Column(
|
||||||
padding: EdgeInsets.only(left: level * 8.0),
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
child: Column(
|
children: [
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
Padding(
|
||||||
children: [
|
padding: const EdgeInsets.all(5.0),
|
||||||
Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
GestureDetector(
|
|
||||||
onTap: () {
|
|
||||||
setState(() {
|
|
||||||
node.isExpanded = !node.isExpanded; // Toggle expansion
|
|
||||||
});
|
|
||||||
},
|
|
||||||
child: Icon(
|
|
||||||
node.children.isNotEmpty
|
|
||||||
? (node.isExpanded
|
|
||||||
? Icons.arrow_drop_down
|
|
||||||
: Icons.arrow_right)
|
|
||||||
: Icons.arrow_right,
|
|
||||||
color: node.children.isNotEmpty
|
|
||||||
? Colors.black
|
|
||||||
: Colors.transparent,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
@ -246,24 +163,49 @@ class _TreeViewState extends State<TreeView> {
|
|||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(width: 15),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Padding(
|
||||||
node.title,
|
padding: EdgeInsets.only(left: level * 10.0),
|
||||||
style: TextStyle(
|
child: Row(
|
||||||
fontSize: 16,
|
children: [
|
||||||
color: Colors.black87,
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
setState(() {
|
||||||
|
node.isExpanded = !node.isExpanded;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
child: SizedBox(
|
||||||
|
child: SvgPicture.asset(
|
||||||
|
node.children.isNotEmpty
|
||||||
|
? (node.isExpanded
|
||||||
|
? Assets.arrowDown
|
||||||
|
: Assets.arrowForward)
|
||||||
|
: Assets.arrowForward,
|
||||||
|
fit: BoxFit.none,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 20),
|
||||||
|
Text(
|
||||||
|
node.title,
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 16,
|
||||||
|
color: node.isHighlighted
|
||||||
|
? ColorsManager.blackColor
|
||||||
|
: ColorsManager.textGray,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
if (node.isExpanded && node.children.isNotEmpty)
|
),
|
||||||
Padding(
|
if (node.isExpanded && node.children.isNotEmpty)
|
||||||
padding: const EdgeInsets.only(left: 24.0),
|
_buildTree(node.children, level: level + 1),
|
||||||
child: _buildTree(node.children, level: level + 1),
|
],
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -308,7 +250,7 @@ class _TreeViewState extends State<TreeView> {
|
|||||||
|
|
||||||
// Update the checkbox state for parent nodes
|
// Update the checkbox state for parent nodes
|
||||||
void _updateParentCheckStatus(TreeNode node) {
|
void _updateParentCheckStatus(TreeNode node) {
|
||||||
TreeNode? parent = _findParent(treeData, node);
|
TreeNode? parent = _findParent(widget.bloc!.updatedCommunities, node);
|
||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
setState(() {
|
setState(() {
|
||||||
parent.isChecked = _areAllChildrenChecked(parent);
|
parent.isChecked = _areAllChildrenChecked(parent);
|
||||||
@ -332,7 +274,7 @@ class _TreeViewState extends State<TreeView> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SingleChildScrollView(
|
return SingleChildScrollView(
|
||||||
child: _buildTree(treeData),
|
child: _buildTree(widget.bloc!.updatedCommunities),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -252,6 +252,7 @@ class CommunitySpaceManagementApi {
|
|||||||
path: ApiEndpoints.getSpaceHierarchy
|
path: ApiEndpoints.getSpaceHierarchy
|
||||||
.replaceAll('{communityId}', communityId),
|
.replaceAll('{communityId}', communityId),
|
||||||
expectedResponseModel: (json) {
|
expectedResponseModel: (json) {
|
||||||
|
print('=-=-=-=$json');
|
||||||
final spaceModels = (json['data'] as List)
|
final spaceModels = (json['data'] as List)
|
||||||
.map((spaceJson) => SpaceModel.fromJson(spaceJson))
|
.map((spaceJson) => SpaceModel.fromJson(spaceJson))
|
||||||
.toList();
|
.toList();
|
||||||
|
@ -391,4 +391,8 @@ class Assets {
|
|||||||
'assets/icons/uncompleate_process_icon.svg';
|
'assets/icons/uncompleate_process_icon.svg';
|
||||||
static const String wrongProcessIcon =
|
static const String wrongProcessIcon =
|
||||||
'assets/icons/wrong_process_icon.svg';
|
'assets/icons/wrong_process_icon.svg';
|
||||||
|
static const String arrowForward =
|
||||||
|
'assets/icons/arrow_forward.svg';
|
||||||
|
static const String arrowDown =
|
||||||
|
'assets/icons/arrow_down.svg';
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user