mirror of
https://github.com/SyncrowIOT/web.git
synced 2025-07-10 07:07:19 +00:00
add_user_dialog
This commit is contained in:
22
lib/pages/roles_and_permission/model/role_type_model.dart
Normal file
22
lib/pages/roles_and_permission/model/role_type_model.dart
Normal file
@ -0,0 +1,22 @@
|
||||
class RoleTypeModel {
|
||||
final String uuid;
|
||||
final String createdAt;
|
||||
final String updatedAt;
|
||||
final String type;
|
||||
|
||||
RoleTypeModel({
|
||||
required this.uuid,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
factory RoleTypeModel.fromJson(Map<String, dynamic> json) {
|
||||
return RoleTypeModel(
|
||||
uuid: json['uuid'],
|
||||
createdAt: json['createdAt'],
|
||||
updatedAt: json['updatedAt'],
|
||||
type: json['type'],
|
||||
);
|
||||
}
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/model/role_type_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_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/model/tree_node_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/view/roles_and_permission.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';
|
||||
import 'package:syncrow_web/services/user_permission.dart';
|
||||
|
||||
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
UsersBloc() : super(UsersInitial()) {
|
||||
@ -16,6 +19,9 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
|
||||
on<SearchAnode>(searchTreeNode);
|
||||
on<CheckSpacesStepStatus>(isCompleteSpacesFun);
|
||||
on<RoleEvent>(_getRolePermission);
|
||||
on<PermissionEvent>(_getPermissions);
|
||||
on<SearchPermission>(searchRolePermission);
|
||||
}
|
||||
|
||||
List<RolesUserModel> users = [];
|
||||
@ -112,7 +118,6 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
void isCompleteSpacesFun(
|
||||
CheckSpacesStepStatus event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
|
||||
try {
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
isCompleteSpaces = selectedIds.isNotEmpty;
|
||||
@ -224,4 +229,61 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
}
|
||||
return selectedIds;
|
||||
}
|
||||
|
||||
List<RoleTypeModel> roles = [];
|
||||
List<PermissionOption> permissions = [];
|
||||
|
||||
_getRolePermission(RoleEvent event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
roles = await UserPermissionApi().fetchRoles();
|
||||
add(PermissionEvent(roleUuid: roles.first.uuid));
|
||||
emit(RolePermissionInitial());
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
_getPermissions(PermissionEvent event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
permissions = await UserPermissionApi().fetchPermission(
|
||||
event.roleUuid == "" ? roles.first.uuid : event.roleUuid);
|
||||
emit(RolePermissionInitial());
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
bool _searchRolePermission(List<PermissionOption> nodes, String searchTerm) {
|
||||
bool anyMatch = false;
|
||||
for (var node in nodes) {
|
||||
bool isMatch =
|
||||
node.title.toLowerCase().contains(searchTerm.toLowerCase());
|
||||
bool childMatch = _searchRolePermission(node.subOptions, searchTerm);
|
||||
node.isHighlighted = isMatch || childMatch;
|
||||
|
||||
anyMatch = anyMatch || node.isHighlighted;
|
||||
}
|
||||
return anyMatch;
|
||||
}
|
||||
|
||||
void searchRolePermission(SearchPermission event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
if (event.searchTerm!.isEmpty) {
|
||||
_clearHighlightsRolePermission(permissions);
|
||||
} else {
|
||||
_searchRolePermission(permissions, event.searchTerm!);
|
||||
}
|
||||
emit(ChangeStatusSteps());
|
||||
}
|
||||
|
||||
void _clearHighlightsRolePermission(List<PermissionOption> nodes) {
|
||||
for (var node in nodes) {
|
||||
node.isHighlighted = false;
|
||||
if (node.subOptions.isNotEmpty) {
|
||||
_clearHighlightsRolePermission(node.subOptions);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/model/tree_node_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/view/roles_and_permission.dart';
|
||||
|
||||
sealed class UsersEvent extends Equatable {
|
||||
const UsersEvent();
|
||||
@ -10,6 +11,7 @@ class GetUsers extends UsersEvent {
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class CheckSpacesStepStatus extends UsersEvent {
|
||||
const CheckSpacesStepStatus();
|
||||
@override
|
||||
@ -22,6 +24,19 @@ class LoadCommunityAndSpacesEvent extends UsersEvent {
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class RoleEvent extends UsersEvent {
|
||||
const RoleEvent();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class PermissionEvent extends UsersEvent {
|
||||
final String? roleUuid;
|
||||
const PermissionEvent({this.roleUuid = ""});
|
||||
@override
|
||||
List<Object?> get props => [roleUuid];
|
||||
}
|
||||
|
||||
class GetBatchStatus extends UsersEvent {
|
||||
final List<String> uuids;
|
||||
const GetBatchStatus(this.uuids);
|
||||
@ -29,7 +44,6 @@ class GetBatchStatus extends UsersEvent {
|
||||
List<Object?> get props => [uuids];
|
||||
}
|
||||
|
||||
//LoadCommunityAndSpacesEvent
|
||||
class ChangeUserStatus extends UsersEvent {
|
||||
final String userId;
|
||||
final String newStatus;
|
||||
@ -54,9 +68,20 @@ class SearchAnode extends UsersEvent {
|
||||
@override
|
||||
List<Object?> get props => [nodes, searchTerm];
|
||||
}
|
||||
|
||||
class SearchPermission extends UsersEvent {
|
||||
List<PermissionOption>? nodes;
|
||||
String? searchTerm;
|
||||
SearchPermission({this.nodes, this.searchTerm});
|
||||
@override
|
||||
List<Object?> get props => [nodes, searchTerm];
|
||||
}
|
||||
|
||||
class SelecteId extends UsersEvent {
|
||||
List<TreeNode>? nodes;
|
||||
SelecteId({this.nodes,});
|
||||
SelecteId({
|
||||
this.nodes,
|
||||
});
|
||||
@override
|
||||
List<Object?> get props => [nodes];
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ final class UsersInitial extends UsersState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
final class RolePermissionInitial extends UsersState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class ChangeStatusSteps extends UsersState {
|
||||
@override
|
||||
|
@ -23,8 +23,9 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (BuildContext context) =>
|
||||
UsersBloc()..add(LoadCommunityAndSpacesEvent()),
|
||||
create: (BuildContext context) => UsersBloc()
|
||||
..add(const LoadCommunityAndSpacesEvent())
|
||||
..add(const RoleEvent()),
|
||||
child: BlocConsumer<UsersBloc, UsersState>(
|
||||
listener: (context, state) {},
|
||||
builder: (context, state) {
|
||||
@ -45,7 +46,9 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
child: Text(
|
||||
"Add New User",
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.bold),
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: ColorsManager.secondaryColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -1,5 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart'; // Import Bloc package
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl_phone_field/country_picker_dialog.dart';
|
||||
import 'package:intl_phone_field/intl_phone_field.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_status.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
@ -47,9 +49,16 @@ class BasicsView extends StatelessWidget {
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"*",
|
||||
style: TextStyle(color: ColorsManager.red),
|
||||
// SizedBox(
|
||||
// width: 15,
|
||||
// ),
|
||||
const Text(
|
||||
" * ",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'First Name',
|
||||
@ -96,8 +105,12 @@ class BasicsView extends StatelessWidget {
|
||||
child: Row(
|
||||
children: [
|
||||
const Text(
|
||||
"*",
|
||||
style: TextStyle(color: ColorsManager.red),
|
||||
" * ",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text('Last Name',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
@ -140,9 +153,13 @@ class BasicsView extends StatelessWidget {
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"*",
|
||||
style: TextStyle(color: ColorsManager.red),
|
||||
const Text(
|
||||
" * ",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
'Email Address',
|
||||
@ -187,10 +204,6 @@ class BasicsView extends StatelessWidget {
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"*",
|
||||
style: TextStyle(color: ColorsManager.red),
|
||||
),
|
||||
Text(
|
||||
'Mobile Number',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
@ -200,28 +213,93 @@ class BasicsView extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
style: const TextStyle(color: Colors.black),
|
||||
controller: _blocRole.phoneController,
|
||||
decoration: inputTextFormDeco(
|
||||
hintText: "05x xxx xxxx",
|
||||
).copyWith(
|
||||
hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Please enter a phone number';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
keyboardType: TextInputType.phone,
|
||||
// InternationalPhoneNumberInput(
|
||||
// spaceBetweenSelectorAndTextField: 50,
|
||||
// initialValue: PhoneNumber(isoCode: 'AE'),
|
||||
// inputDecoration: inputTextFormDeco(
|
||||
// hintText: "x xxx xxxx",
|
||||
// ).copyWith(
|
||||
// hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||
// fontWeight: FontWeight.w400,
|
||||
// fontSize: 12,
|
||||
// color: ColorsManager.textGray),
|
||||
// ),
|
||||
// onInputChanged: (PhoneNumber number) {
|
||||
// print(number.phoneNumber);
|
||||
// },
|
||||
// onInputValidated: (bool value) {
|
||||
// print(value);
|
||||
// },
|
||||
// selectorConfig: const SelectorConfig(
|
||||
// selectorType: PhoneInputSelectorType.BOTTOM_SHEET,
|
||||
// useBottomSheetSafeArea: true,
|
||||
// leadingPadding: 15,
|
||||
// trailingSpace: false,
|
||||
// setSelectorButtonAsPrefixIcon: true),
|
||||
// ignoreBlank: true,
|
||||
// autoValidateMode: AutovalidateMode.disabled,
|
||||
|
||||
// selectorTextStyle:
|
||||
// TextStyle(color: ColorsManager.blackColor),
|
||||
// // initialValue: number,
|
||||
// // textFieldController: controller,
|
||||
// formatInput: true,
|
||||
// keyboardType: const TextInputType.numberWithOptions(
|
||||
// signed: true, decimal: true),
|
||||
// // inputBorder: OutlineInputBorder(
|
||||
// // borderSide:
|
||||
// // BorderSide(color: Colors.black,)),
|
||||
// onSaved: (PhoneNumber number) {
|
||||
// print('On Saved: $number');
|
||||
// },
|
||||
// textStyle:
|
||||
// const TextStyle(color: ColorsManager.blackColor),
|
||||
// ),
|
||||
|
||||
IntlPhoneField(
|
||||
pickerDialogStyle: PickerDialogStyle(),
|
||||
dropdownIconPosition: IconPosition.leading,
|
||||
disableLengthCheck: true,
|
||||
dropdownTextStyle: TextStyle(color: Colors.black),
|
||||
textInputAction: TextInputAction.done,
|
||||
decoration: inputTextFormDeco(
|
||||
hintText: "05x xxx xxxx",
|
||||
).copyWith(
|
||||
hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
),
|
||||
|
||||
initialCountryCode: 'AE',
|
||||
style: TextStyle(color: Colors.black),
|
||||
onChanged: (phone) {
|
||||
print(phone.completeNumber);
|
||||
},
|
||||
)
|
||||
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: TextFormField(
|
||||
// style: const TextStyle(color: Colors.black),
|
||||
// controller: _blocRole.phoneController,
|
||||
// decoration: inputTextFormDeco(
|
||||
// hintText: "05x xxx xxxx",
|
||||
// ).copyWith(
|
||||
// hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||
// fontWeight: FontWeight.w400,
|
||||
// fontSize: 12,
|
||||
// color: ColorsManager.textGray),
|
||||
// ),
|
||||
// validator: (value) {
|
||||
// if (value == null || value.isEmpty) {
|
||||
// return 'Please enter a phone number';
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
// keyboardType: TextInputType.phone,
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -236,10 +314,6 @@ class BasicsView extends StatelessWidget {
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"*",
|
||||
style: TextStyle(color: ColorsManager.red),
|
||||
),
|
||||
Text(
|
||||
'Job Title',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
|
@ -5,14 +5,14 @@ import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_blo
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class AddNewUserDialog extends StatefulWidget {
|
||||
const AddNewUserDialog({super.key});
|
||||
class DeleteUserDialog extends StatefulWidget {
|
||||
const DeleteUserDialog({super.key});
|
||||
|
||||
@override
|
||||
_AddNewUserDialogState createState() => _AddNewUserDialogState();
|
||||
_DeleteUserDialogState createState() => _DeleteUserDialogState();
|
||||
}
|
||||
|
||||
class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
class _DeleteUserDialogState extends State<DeleteUserDialog> {
|
||||
int currentStep = 1;
|
||||
|
||||
@override
|
||||
|
@ -1,7 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart'; // Import Bloc package
|
||||
import 'package:flutter_bloc/flutter_bloc.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_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
@ -34,7 +35,12 @@ class RolesAndPermission extends StatelessWidget {
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const SizedBox(width: 300, height: 110, child: DropdownExample()),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 110,
|
||||
child: DropdownExample(
|
||||
bloc: _blocRole,
|
||||
)),
|
||||
const SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
@ -64,6 +70,11 @@ class RolesAndPermission extends StatelessWidget {
|
||||
style:
|
||||
const TextStyle(color: Colors.black),
|
||||
controller: _blocRole.firstNameController,
|
||||
onChanged: (value) {
|
||||
_blocRole.add(SearchPermission(
|
||||
nodes: _blocRole.permissions,
|
||||
searchTerm: value));
|
||||
},
|
||||
decoration: textBoxDecoration(radios: 20)!
|
||||
.copyWith(
|
||||
fillColor: Colors.white,
|
||||
@ -97,7 +108,9 @@ class RolesAndPermission extends StatelessWidget {
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: const DeviceManagement())))
|
||||
child: DeviceManagement(
|
||||
bloc: _blocRole,
|
||||
))))
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -111,7 +124,8 @@ class RolesAndPermission extends StatelessWidget {
|
||||
}
|
||||
|
||||
class DropdownExample extends StatefulWidget {
|
||||
const DropdownExample({super.key});
|
||||
final UsersBloc? bloc;
|
||||
const DropdownExample({super.key, this.bloc});
|
||||
|
||||
@override
|
||||
_DropdownExampleState createState() => _DropdownExampleState();
|
||||
@ -119,7 +133,13 @@ class DropdownExample extends StatefulWidget {
|
||||
|
||||
class _DropdownExampleState extends State<DropdownExample> {
|
||||
String? selectedRole;
|
||||
List<String> roles = ['Admin', 'User', 'Guest', 'Moderator'];
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.bloc != null && widget.bloc!.roles.isNotEmpty) {
|
||||
selectedRole = widget.bloc!.roles.first.uuid;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -140,19 +160,20 @@ class _DropdownExampleState extends State<DropdownExample> {
|
||||
SizedBox(
|
||||
child: DropdownButtonFormField<String>(
|
||||
alignment: Alignment.center,
|
||||
focusColor: ColorsManager.whiteColors,
|
||||
focusColor: Colors.white,
|
||||
autofocus: true,
|
||||
value: selectedRole,
|
||||
items: roles.map((role) {
|
||||
return DropdownMenuItem(
|
||||
value: role,
|
||||
child: Text(role),
|
||||
items: widget.bloc!.roles.map((role) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: role.uuid,
|
||||
child: Text(role.type),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedRole = value;
|
||||
});
|
||||
widget.bloc!.add(PermissionEvent(roleUuid: selectedRole));
|
||||
},
|
||||
padding: EdgeInsets.zero,
|
||||
icon: const SizedBox.shrink(),
|
||||
@ -168,13 +189,13 @@ class _DropdownExampleState extends State<DropdownExample> {
|
||||
width: 70,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: ColorsManager.graysColor,
|
||||
color: Colors.grey[200],
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomRight: Radius.circular(10),
|
||||
topRight: Radius.circular(10),
|
||||
),
|
||||
border: Border.all(
|
||||
color: ColorsManager.grayBorder,
|
||||
color: Colors.grey,
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
@ -192,60 +213,17 @@ class _DropdownExampleState extends State<DropdownExample> {
|
||||
}
|
||||
|
||||
class DeviceManagement extends StatefulWidget {
|
||||
const DeviceManagement({Key? key}) : super(key: key);
|
||||
final UsersBloc? bloc;
|
||||
const DeviceManagement({Key? key, this.bloc}) : super(key: key);
|
||||
|
||||
@override
|
||||
_DeviceManagementState createState() => _DeviceManagementState();
|
||||
}
|
||||
|
||||
class _DeviceManagementState extends State<DeviceManagement> {
|
||||
|
||||
|
||||
final List<MainRoleOption> options = [
|
||||
MainRoleOption(
|
||||
id: '1',
|
||||
title: "Device Management",
|
||||
subOptions: [
|
||||
SubRoleOption(
|
||||
id: '11',
|
||||
title: "Manage devices in private spaces",
|
||||
children: [
|
||||
ChildRoleOption(id: '111', title: "Control"),
|
||||
ChildRoleOption(id: '112', title: "Assign device"),
|
||||
ChildRoleOption(id: '113', title: "View"),
|
||||
],
|
||||
),
|
||||
SubRoleOption(
|
||||
id: '12',
|
||||
title: "Manage",
|
||||
children: [
|
||||
ChildRoleOption(id: '121', title: "cc"),
|
||||
ChildRoleOption(id: '122', title: "Assign"),
|
||||
ChildRoleOption(id: '123', title: "s"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
MainRoleOption(
|
||||
id: '2',
|
||||
title: "Device Management",
|
||||
subOptions: [
|
||||
SubRoleOption(
|
||||
id: '22',
|
||||
title: "Manage devices in private spaces",
|
||||
children: [
|
||||
ChildRoleOption(id: '211', title: "Control"),
|
||||
ChildRoleOption(id: '212', title: "Assign device"),
|
||||
ChildRoleOption(id: '213', title: "View"),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
];
|
||||
|
||||
void toggleOptionById(String id) {
|
||||
setState(() {
|
||||
for (var mainOption in options) {
|
||||
for (var mainOption in widget.bloc!.permissions) {
|
||||
if (mainOption.id == id) {
|
||||
final isChecked =
|
||||
checkifOneOfthemChecked(mainOption) == CheckState.all;
|
||||
@ -253,7 +231,7 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
|
||||
for (var subOption in mainOption.subOptions) {
|
||||
subOption.isChecked = !isChecked;
|
||||
for (var child in subOption.children) {
|
||||
for (var child in subOption.subOptions) {
|
||||
child.isChecked = !isChecked;
|
||||
}
|
||||
}
|
||||
@ -263,7 +241,7 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
for (var subOption in mainOption.subOptions) {
|
||||
if (subOption.id == id) {
|
||||
subOption.isChecked = !subOption.isChecked;
|
||||
for (var child in subOption.children) {
|
||||
for (var child in subOption.subOptions) {
|
||||
child.isChecked = subOption.isChecked;
|
||||
}
|
||||
mainOption.isChecked =
|
||||
@ -271,11 +249,11 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
return;
|
||||
}
|
||||
|
||||
for (var child in subOption.children) {
|
||||
for (var child in subOption.subOptions) {
|
||||
if (child.id == id) {
|
||||
child.isChecked = !child.isChecked;
|
||||
subOption.isChecked =
|
||||
subOption.children.every((child) => child.isChecked);
|
||||
subOption.subOptions.every((child) => child.isChecked);
|
||||
mainOption.isChecked =
|
||||
mainOption.subOptions.every((sub) => sub.isChecked);
|
||||
return;
|
||||
@ -286,7 +264,7 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
});
|
||||
}
|
||||
|
||||
CheckState checkifOneOfthemChecked(MainRoleOption mainOption) {
|
||||
CheckState checkifOneOfthemChecked(PermissionOption mainOption) {
|
||||
bool allSelected = true;
|
||||
bool someSelected = false;
|
||||
|
||||
@ -297,7 +275,7 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
allSelected = false;
|
||||
}
|
||||
|
||||
for (var child in subOption.children) {
|
||||
for (var child in subOption.subOptions) {
|
||||
if (child.isChecked) {
|
||||
someSelected = true;
|
||||
} else {
|
||||
@ -319,16 +297,16 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(8),
|
||||
itemCount: options.length,
|
||||
itemCount: widget.bloc!.permissions.length,
|
||||
itemBuilder: (context, index) {
|
||||
final option = options[index];
|
||||
final option = widget.bloc!.permissions[index];
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => toggleOptionById(option.id),
|
||||
// onTap: () => toggleOptionById(option.id),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final checkState = checkifOneOfthemChecked(option);
|
||||
@ -372,50 +350,55 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () => toggleOptionById(subOption.id),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final checkState =
|
||||
checkifOneOfthemChecked(MainRoleOption(
|
||||
id: subOption.id,
|
||||
title: subOption.title,
|
||||
subOptions: [subOption],
|
||||
));
|
||||
Container(
|
||||
color: option.isHighlighted
|
||||
? Colors.blue.shade50
|
||||
: Colors.white,
|
||||
child: Row(
|
||||
children: [
|
||||
InkWell(
|
||||
// onTap: () => toggleOptionById(subOption.id),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final checkState =
|
||||
checkifOneOfthemChecked(PermissionOption(
|
||||
id: subOption.id,
|
||||
title: subOption.title,
|
||||
subOptions: [subOption],
|
||||
));
|
||||
|
||||
if (checkState == CheckState.all) {
|
||||
return Image.asset(
|
||||
Assets.CheckBoxChecked,
|
||||
width: 20,
|
||||
height: 20,
|
||||
);
|
||||
} else if (checkState == CheckState.some) {
|
||||
return Image.asset(
|
||||
Assets.rectangleCheckBox,
|
||||
width: 20,
|
||||
height: 20,
|
||||
);
|
||||
} else {
|
||||
return Image.asset(
|
||||
Assets.emptyBox,
|
||||
width: 20,
|
||||
height: 20,
|
||||
);
|
||||
}
|
||||
},
|
||||
if (checkState == CheckState.all) {
|
||||
return Image.asset(
|
||||
Assets.CheckBoxChecked,
|
||||
width: 20,
|
||||
height: 20,
|
||||
);
|
||||
} else if (checkState == CheckState.some) {
|
||||
return Image.asset(
|
||||
Assets.rectangleCheckBox,
|
||||
width: 20,
|
||||
height: 20,
|
||||
);
|
||||
} else {
|
||||
return Image.asset(
|
||||
Assets.emptyBox,
|
||||
width: 20,
|
||||
height: 20,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
subOption.title,
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.lightGreyColor),
|
||||
),
|
||||
],
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
subOption.title,
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.lightGreyColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 50.0),
|
||||
@ -424,15 +407,18 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2, // 2 items per row
|
||||
mainAxisSpacing: 2.0, // Space between rows
|
||||
crossAxisSpacing: 0.2, // Space between columns
|
||||
childAspectRatio: 5, // Adjust aspect ratio as needed
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: 2.0,
|
||||
crossAxisSpacing: 0.2,
|
||||
childAspectRatio: 5,
|
||||
),
|
||||
itemCount: subOption.children.length,
|
||||
itemCount: subOption.subOptions.length,
|
||||
itemBuilder: (context, index) {
|
||||
final child = subOption.children[index];
|
||||
final child = subOption.subOptions[index];
|
||||
return CheckboxListTile(
|
||||
selectedTileColor: child.isHighlighted
|
||||
? Colors.blue.shade50
|
||||
: Colors.white,
|
||||
dense: true,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
title: Text(
|
||||
@ -444,6 +430,7 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
),
|
||||
value: child.isChecked,
|
||||
onChanged: (value) => toggleOptionById(child.id),
|
||||
enabled: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
@ -458,43 +445,44 @@ class _DeviceManagementState extends State<DeviceManagement> {
|
||||
}
|
||||
}
|
||||
|
||||
class MainRoleOption {
|
||||
String id;
|
||||
String title;
|
||||
bool isChecked;
|
||||
List<SubRoleOption> subOptions;
|
||||
MainRoleOption({
|
||||
required this.id,
|
||||
required this.title,
|
||||
this.isChecked = false,
|
||||
this.subOptions = const [],
|
||||
});
|
||||
}
|
||||
|
||||
class SubRoleOption {
|
||||
String id;
|
||||
String title;
|
||||
bool isChecked;
|
||||
List<ChildRoleOption> children;
|
||||
|
||||
SubRoleOption({
|
||||
required this.id,
|
||||
required this.title,
|
||||
this.isChecked = false,
|
||||
this.children = const [],
|
||||
});
|
||||
}
|
||||
|
||||
class ChildRoleOption {
|
||||
String id;
|
||||
String title;
|
||||
bool isChecked;
|
||||
|
||||
ChildRoleOption({
|
||||
required this.id,
|
||||
required this.title,
|
||||
this.isChecked = false,
|
||||
});
|
||||
}
|
||||
|
||||
enum CheckState { none, some, all }
|
||||
|
||||
class PermissionOption {
|
||||
String id;
|
||||
String title;
|
||||
bool isChecked;
|
||||
bool isHighlighted;
|
||||
List<PermissionOption> subOptions;
|
||||
|
||||
PermissionOption({
|
||||
required this.id,
|
||||
required this.title,
|
||||
this.isChecked = false,
|
||||
this.isHighlighted = false,
|
||||
this.subOptions = const [],
|
||||
});
|
||||
|
||||
factory PermissionOption.fromJson(Map<String, dynamic> json) {
|
||||
return PermissionOption(
|
||||
id: json['id'] ?? '',
|
||||
title: json['title'] ?? '',
|
||||
isChecked: json['isChecked'] ?? false,
|
||||
isHighlighted: json['isHighlighted'] ?? false,
|
||||
subOptions: (json['subOptions'] as List?)
|
||||
?.map((sub) => PermissionOption.fromJson(sub))
|
||||
.toList() ??
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {
|
||||
'id': id,
|
||||
'title': title,
|
||||
'isChecked': isChecked,
|
||||
'isHighlighted': isHighlighted,
|
||||
'subOptions': subOptions.map((sub) => sub.toJson()).toList(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
36
lib/services/user_permission.dart
Normal file
36
lib/services/user_permission.dart
Normal file
@ -0,0 +1,36 @@
|
||||
|
||||
import 'package:syncrow_web/pages/roles_and_permission/model/role_type_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/view/roles_and_permission.dart';
|
||||
import 'package:syncrow_web/services/api/http_service.dart';
|
||||
import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||
|
||||
class UserPermissionApi {
|
||||
static final HTTPService _httpService = HTTPService();
|
||||
|
||||
fetchRoles() async {
|
||||
final response = await _httpService.get(
|
||||
path: ApiEndpoints.roleTypes,
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
final List<RoleTypeModel> fetchedRoles = (json['data'] as List)
|
||||
.map((item) => RoleTypeModel.fromJson(item))
|
||||
.toList();
|
||||
return fetchedRoles;
|
||||
},
|
||||
);
|
||||
return response;
|
||||
}
|
||||
|
||||
Future<List<PermissionOption>> fetchPermission(roleUuid) async {
|
||||
final response = await _httpService.get(
|
||||
path: ApiEndpoints.permission.replaceAll("roleUuid", roleUuid),
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return (json as List)
|
||||
.map((data) => PermissionOption.fromJson(data))
|
||||
.toList();
|
||||
},
|
||||
);
|
||||
return response ?? [];
|
||||
}
|
||||
}
|
@ -11,12 +11,14 @@ abstract class ApiEndpoints {
|
||||
static const String visitorPassword = '/visitor-password';
|
||||
static const String getDevices = '/visitor-password/devices';
|
||||
|
||||
static const String sendOnlineOneTime = '/visitor-password/temporary-password/online/one-time';
|
||||
static const String sendOnlineOneTime =
|
||||
'/visitor-password/temporary-password/online/one-time';
|
||||
static const String sendOnlineMultipleTime =
|
||||
'/visitor-password/temporary-password/online/multiple-time';
|
||||
|
||||
//offline Password
|
||||
static const String sendOffLineOneTime = '/visitor-password/temporary-password/offline/one-time';
|
||||
static const String sendOffLineOneTime =
|
||||
'/visitor-password/temporary-password/offline/one-time';
|
||||
static const String sendOffLineMultipleTime =
|
||||
'/visitor-password/temporary-password/offline/multiple-time';
|
||||
|
||||
@ -38,8 +40,10 @@ abstract class ApiEndpoints {
|
||||
// Space Module
|
||||
static const String createSpace = '/communities/{communityId}/spaces';
|
||||
static const String listSpaces = '/communities/{communityId}/spaces';
|
||||
static const String deleteSpace = '/communities/{communityId}/spaces/{spaceId}';
|
||||
static const String updateSpace = '/communities/{communityId}/spaces/{spaceId}';
|
||||
static const String deleteSpace =
|
||||
'/communities/{communityId}/spaces/{spaceId}';
|
||||
static const String updateSpace =
|
||||
'/communities/{communityId}/spaces/{spaceId}';
|
||||
static const String getSpace = '/communities/{communityId}/spaces/{spaceId}';
|
||||
static const String getSpaceHierarchy = '/communities/{communityId}/spaces';
|
||||
|
||||
@ -55,11 +59,15 @@ abstract class ApiEndpoints {
|
||||
'/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}';
|
||||
|
||||
static const String scheduleByDeviceId = '/schedule/{deviceUuid}';
|
||||
static const String getScheduleByDeviceId = '/schedule/{deviceUuid}?category={category}';
|
||||
static const String deleteScheduleByDeviceId = '/schedule/{deviceUuid}/{scheduleUuid}';
|
||||
static const String updateScheduleByDeviceId = '/schedule/enable/{deviceUuid}';
|
||||
static const String getScheduleByDeviceId =
|
||||
'/schedule/{deviceUuid}?category={category}';
|
||||
static const String deleteScheduleByDeviceId =
|
||||
'/schedule/{deviceUuid}/{scheduleUuid}';
|
||||
static const String updateScheduleByDeviceId =
|
||||
'/schedule/enable/{deviceUuid}';
|
||||
static const String factoryReset = '/device/factory/reset/{deviceUuid}';
|
||||
static const String powerClamp = '/device/{powerClampUuid}/power-clamp/status';
|
||||
static const String powerClamp =
|
||||
'/device/{powerClampUuid}/power-clamp/status';
|
||||
|
||||
//product
|
||||
static const String listProducts = '/products';
|
||||
@ -68,13 +76,18 @@ abstract class ApiEndpoints {
|
||||
static const String getIconScene = '/scene/icon';
|
||||
static const String createScene = '/scene/tap-to-run';
|
||||
static const String createAutomation = '/automation';
|
||||
static const String getUnitScenes = '/communities/{communityUuid}/spaces/{spaceUuid}/scenes';
|
||||
static const String getAutomationDetails = '/automation/details/{automationId}';
|
||||
static const String getUnitScenes =
|
||||
'/communities/{communityUuid}/spaces/{spaceUuid}/scenes';
|
||||
static const String getAutomationDetails =
|
||||
'/automation/details/{automationId}';
|
||||
static const String getScene = '/scene/tap-to-run/{sceneId}';
|
||||
static const String deleteScene = '/scene/tap-to-run/{sceneId}';
|
||||
|
||||
static const String deleteAutomation = '/automation/{automationId}';
|
||||
static const String updateScene = '/scene/tap-to-run/{sceneId}';
|
||||
static const String updateScene = '/scene/tap-to-run/{sceneId}';
|
||||
|
||||
static const String updateAutomation = '/automation/{automationId}';
|
||||
static const String roleTypes = '/role/types';
|
||||
static const String permission = '/permission/{roleUuid}';
|
||||
// static const String updateAutomation = '/automation/{automationId}';
|
||||
}
|
||||
|
40
pubspec.lock
40
pubspec.lock
@ -304,6 +304,22 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.19.0"
|
||||
intl_phone_field:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl_phone_field
|
||||
sha256: "73819d3dfcb68d2c85663606f6842597c3ddf6688ac777f051b17814fe767bbf"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
intl_phone_number_input:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: intl_phone_number_input
|
||||
sha256: "1c4328713a9503ab26a1fdbb6b00b4cada68c18aac922b35bedbc72eff1297c3"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.4"
|
||||
js:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -336,6 +352,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
libphonenumber_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: libphonenumber_platform_interface
|
||||
sha256: f801f6c65523f56504b83f0890e6dad584ab3a7507dca65fec0eed640afea40f
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.4.2"
|
||||
libphonenumber_plugin:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: libphonenumber_plugin
|
||||
sha256: c615021d9816fbda2b2587881019ed595ecdf54d999652d7e4cce0e1f026368c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.3"
|
||||
libphonenumber_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: libphonenumber_web
|
||||
sha256: "8186f420dbe97c3132283e52819daff1e55d60d6db46f7ea5ac42f42a28cc2ef"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.2"
|
||||
lints:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -52,6 +52,8 @@ dependencies:
|
||||
fl_chart: ^0.69.0
|
||||
uuid: ^4.4.2
|
||||
time_picker_spinner: ^1.0.0
|
||||
intl_phone_field: ^3.2.0
|
||||
intl_phone_number_input: ^0.7.4
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Reference in New Issue
Block a user