mirror of
https://github.com/SyncrowIOT/web.git
synced 2026-10-24 04:47:55 +00:00
add_user_dialog
This commit is contained in:
@@ -12,7 +12,7 @@ Future<void> showCustomDialog({
|
||||
double? iconWidth,
|
||||
VoidCallback? onOkPressed,
|
||||
bool barrierDismissible = false,
|
||||
required List<Widget> actions,
|
||||
List<Widget>? actions,
|
||||
}) {
|
||||
return showDialog(
|
||||
context: context,
|
||||
|
||||
@@ -16,7 +16,7 @@ class RoleTypeModel {
|
||||
uuid: json['uuid'],
|
||||
createdAt: json['createdAt'],
|
||||
updatedAt: json['updatedAt'],
|
||||
type: json['type'],
|
||||
type: json['type'].toString().toLowerCase().replaceAll("_", " "),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+76
-109
@@ -1,20 +1,19 @@
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/common/custom_dialog.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/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/permission_option_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/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';
|
||||
import 'package:syncrow_web/services/user_permission.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
UsersBloc() : super(UsersInitial()) {
|
||||
on<GetUsers>(_getUsers);
|
||||
on<ChangeUserStatus>(_changeUserStatus);
|
||||
on<CheckStepStatus>(isCompleteBasicsFun);
|
||||
on<LoadCommunityAndSpacesEvent>(_onLoadCommunityAndSpaces);
|
||||
on<SearchAnode>(searchTreeNode);
|
||||
@@ -25,6 +24,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
on<SendInviteUsers>(_sendInvitUser);
|
||||
on<ValidateBasicsStep>(_validateBasicsStep);
|
||||
on<CheckRoleStepStatus>(isCompleteRoleFun);
|
||||
on<CheckEmailEvent>(checkEmail);
|
||||
}
|
||||
void _validateBasicsStep(ValidateBasicsStep event, Emitter<UsersState> emit) {
|
||||
if (formKey.currentState?.validate() ?? false) {
|
||||
@@ -34,74 +34,8 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
}
|
||||
}
|
||||
|
||||
List<RolesUserModel> users = [];
|
||||
String roleSelected = '';
|
||||
|
||||
Future<void> _getUsers(GetUsers event, Emitter<UsersState> emit) async {
|
||||
emit(UsersLoadingState());
|
||||
try {
|
||||
users = [
|
||||
RolesUserModel(
|
||||
id: '1',
|
||||
userName: 'user 1',
|
||||
userEmail: '[email protected]',
|
||||
action: '',
|
||||
createdBy: 'Admin',
|
||||
creationDate: '25/10/2024',
|
||||
creationTime: '10:30 AM',
|
||||
status: 'Invited',
|
||||
),
|
||||
RolesUserModel(
|
||||
id: '2',
|
||||
userName: 'user 2',
|
||||
userEmail: '[email protected]',
|
||||
action: '',
|
||||
createdBy: 'Admin',
|
||||
creationDate: '25/10/2024',
|
||||
creationTime: '10:30 AM',
|
||||
status: 'Active',
|
||||
),
|
||||
RolesUserModel(
|
||||
id: '3',
|
||||
userName: 'user 3',
|
||||
userEmail: '[email protected]',
|
||||
action: '',
|
||||
createdBy: 'Admin',
|
||||
creationDate: '25/10/2024',
|
||||
creationTime: '10:30 AM',
|
||||
status: 'Disabled',
|
||||
),
|
||||
];
|
||||
emit(UsersLoadedState(users: users));
|
||||
} catch (e) {
|
||||
emit(ErrorState(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _changeUserStatus(ChangeUserStatus event, Emitter<UsersState> emit) {
|
||||
try {
|
||||
users = users.map((user) {
|
||||
if (user.id == event.userId) {
|
||||
return RolesUserModel(
|
||||
id: user.id,
|
||||
userName: user.userName,
|
||||
userEmail: user.userEmail,
|
||||
createdBy: user.createdBy,
|
||||
creationDate: user.creationDate,
|
||||
creationTime: user.creationTime,
|
||||
status: event.newStatus,
|
||||
action: user.action,
|
||||
);
|
||||
}
|
||||
return user;
|
||||
}).toList();
|
||||
|
||||
emit(UsersLoadedState(users: users));
|
||||
} catch (e) {
|
||||
emit(ErrorState(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
final formKey = GlobalKey<FormState>();
|
||||
final TextEditingController firstNameController = TextEditingController();
|
||||
final TextEditingController lastNameController = TextEditingController();
|
||||
@@ -109,6 +43,9 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
final TextEditingController phoneController = TextEditingController();
|
||||
final TextEditingController jobTitleController = TextEditingController();
|
||||
|
||||
final TextEditingController roleSearchController = TextEditingController();
|
||||
// final TextEditingController jobTitleController = TextEditingController();
|
||||
|
||||
bool? isCompleteBasics;
|
||||
bool? isCompleteRolePermissions;
|
||||
bool? isCompleteSpaces;
|
||||
@@ -117,30 +54,6 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
int numberSpaces = 0;
|
||||
int numberRole = 0;
|
||||
|
||||
// isCompleteBasicsFun(CheckStepStatus event, Emitter<UsersState> emit) {
|
||||
// emit(UsersLoadingState());
|
||||
// isCompleteBasics = firstNameController.text.isNotEmpty &&
|
||||
// lastNameController.text.isNotEmpty &&
|
||||
// emailController.text.isNotEmpty;
|
||||
// emit(ChangeStatusSteps());
|
||||
// return isCompleteBasics;
|
||||
// }
|
||||
|
||||
bool isCompleteBasicsFun(CheckStepStatus event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
|
||||
final emailRegex = RegExp(
|
||||
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
|
||||
);
|
||||
isCompleteBasics = firstNameController.text.isNotEmpty &&
|
||||
lastNameController.text.isNotEmpty &&
|
||||
emailController.text.isNotEmpty &&
|
||||
emailRegex.hasMatch(emailController.text);
|
||||
|
||||
emit(ChangeStatusSteps());
|
||||
return isCompleteBasics!;
|
||||
}
|
||||
|
||||
void isCompleteSpacesFun(
|
||||
CheckSpacesStepStatus event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
@@ -184,7 +97,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
);
|
||||
}).toList(),
|
||||
);
|
||||
emit(ChangeStatusSteps());
|
||||
emit(SpacesLoadedState());
|
||||
return updatedCommunities;
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||
@@ -239,6 +152,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
}
|
||||
|
||||
List<String> selectedIds = [];
|
||||
|
||||
List<String> getSelectedIds(List<TreeNode> nodes) {
|
||||
List<String> selectedIds = [];
|
||||
for (var node in nodes) {
|
||||
@@ -259,7 +173,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
roles = await UserPermissionApi().fetchRoles();
|
||||
add(PermissionEvent(roleUuid: roles.first.uuid));
|
||||
// add(PermissionEvent(roleUuid: roles.first.uuid));
|
||||
emit(RolePermissionInitial());
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||
@@ -294,18 +208,40 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
_sendInvitUser(SendInviteUsers event, Emitter<UsersState> emit) async {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
await UserPermissionApi().sendInviteUser(
|
||||
email: emailController.text,
|
||||
firstName: firstNameController.text,
|
||||
jobTitle: jobTitleController.text,
|
||||
lastName: lastNameController.text,
|
||||
phoneNumber: phoneController.text,
|
||||
roleUuid: roleSelected,
|
||||
spaceUuids: selectedIds);
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities) ?? [];
|
||||
bool res = await UserPermissionApi().sendInviteUser(
|
||||
email: emailController.text,
|
||||
firstName: firstNameController.text,
|
||||
jobTitle: jobTitleController.text,
|
||||
lastName: lastNameController.text,
|
||||
phoneNumber: phoneController.text,
|
||||
roleUuid: roleSelected,
|
||||
spaceUuids: selectedIds,
|
||||
);
|
||||
if (res == true) {
|
||||
showCustomDialog(
|
||||
barrierDismissible: false,
|
||||
context: event.context,
|
||||
message: "The invite was sent successfully.",
|
||||
iconPath: Assets.deviceNoteIcon,
|
||||
title: "Invite Success",
|
||||
dialogHeight: MediaQuery.of(event.context).size.height * 0.3,
|
||||
actions: <Widget>[
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(event.context).pop();
|
||||
Navigator.of(event.context).pop();
|
||||
},
|
||||
child: const Text('OK'),
|
||||
),
|
||||
],
|
||||
);
|
||||
} else {
|
||||
emit(const ErrorState('Failed to send invite.'));
|
||||
}
|
||||
emit(SaveState());
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error: $e'));
|
||||
emit(ErrorState('Failed to send invite: ${e.toString()}'));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -319,6 +255,37 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
emit(ChangeStatusSteps());
|
||||
}
|
||||
|
||||
String checkEmailValid = '';
|
||||
|
||||
Future<void> checkEmail(
|
||||
CheckEmailEvent event, Emitter<UsersState> emit) async {
|
||||
emit(UsersLoadingState());
|
||||
String? res = await UserPermissionApi().checkEmail(
|
||||
emailController.text,
|
||||
);
|
||||
checkEmailValid = res!;
|
||||
emit(ChangeStatusSteps());
|
||||
}
|
||||
|
||||
bool isCompleteBasicsFun(CheckStepStatus event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
add(const CheckEmailEvent());
|
||||
final emailRegex = RegExp(
|
||||
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
|
||||
);
|
||||
bool isEmailValid = emailRegex.hasMatch(emailController.text);
|
||||
bool isEmailServerValid = checkEmailValid == 'Valid email';
|
||||
isCompleteBasics = firstNameController.text.isNotEmpty &&
|
||||
lastNameController.text.isNotEmpty &&
|
||||
emailController.text.isNotEmpty &&
|
||||
isEmailValid &&
|
||||
isEmailServerValid;
|
||||
|
||||
emit(ChangeStatusSteps());
|
||||
emit(ValidateBasics());
|
||||
return isCompleteBasics!;
|
||||
}
|
||||
|
||||
void _clearHighlightsRolePermission(List<PermissionOption> nodes) {
|
||||
for (var node in nodes) {
|
||||
node.isHighlighted = false;
|
||||
+12
-21
@@ -1,21 +1,17 @@
|
||||
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';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/permission_option_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/tree_node_model.dart';
|
||||
|
||||
sealed class UsersEvent extends Equatable {
|
||||
const UsersEvent();
|
||||
}
|
||||
|
||||
class GetUsers extends UsersEvent {
|
||||
const GetUsers();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class SendInviteUsers extends UsersEvent {
|
||||
const SendInviteUsers();
|
||||
final BuildContext context;
|
||||
const SendInviteUsers({required this.context});
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
List<Object?> get props => [context];
|
||||
}
|
||||
|
||||
class CheckSpacesStepStatus extends UsersEvent {
|
||||
@@ -30,7 +26,6 @@ class CheckRoleStepStatus extends UsersEvent {
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
|
||||
class LoadCommunityAndSpacesEvent extends UsersEvent {
|
||||
const LoadCommunityAndSpacesEvent();
|
||||
@override
|
||||
@@ -57,16 +52,6 @@ class GetBatchStatus extends UsersEvent {
|
||||
List<Object?> get props => [uuids];
|
||||
}
|
||||
|
||||
class ChangeUserStatus extends UsersEvent {
|
||||
final String userId;
|
||||
final String newStatus;
|
||||
|
||||
const ChangeUserStatus({required this.userId, required this.newStatus});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [userId, newStatus];
|
||||
}
|
||||
|
||||
class CheckStepStatus extends UsersEvent {
|
||||
final int? steps;
|
||||
const CheckStepStatus({this.steps});
|
||||
@@ -104,3 +89,9 @@ class ValidateBasicsStep extends UsersEvent {
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class CheckEmailEvent extends UsersEvent {
|
||||
const CheckEmailEvent();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
+7
-4
@@ -30,11 +30,10 @@ final class SaveState extends UsersState {
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class UsersLoadedState extends UsersState {
|
||||
List<RolesUserModel> users = [];
|
||||
UsersLoadedState({required this.users});
|
||||
final class SpacesLoadedState extends UsersState {
|
||||
SpacesLoadedState();
|
||||
@override
|
||||
List<Object> get props => [users];
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class ErrorState extends UsersState {
|
||||
@@ -77,3 +76,7 @@ class BasicsStepInvalidState extends UsersState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
final class ValidateBasics extends UsersState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
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'].toString().toLowerCase().replaceAll("_", " ") ?? '',
|
||||
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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
enum CheckState { none, some, all }
|
||||
+89
-78
@@ -1,12 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
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/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/spaces_access_view.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/basics_view.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/roles_and_permission.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/spaces_access_view.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
@@ -56,7 +56,6 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
Expanded(
|
||||
child: Row(
|
||||
children: [
|
||||
// Sidebar for Steps
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(20),
|
||||
@@ -75,7 +74,6 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
width: 1,
|
||||
color: ColorsManager.grayBorder,
|
||||
),
|
||||
// Main content (Form)
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Padding(
|
||||
@@ -109,6 +107,8 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
_blocRole.add(const CheckEmailEvent());
|
||||
|
||||
setState(() {
|
||||
if (currentStep < 3) {
|
||||
currentStep++;
|
||||
@@ -117,11 +117,10 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
} else if (currentStep == 3) {
|
||||
_blocRole
|
||||
.add(const CheckSpacesStepStatus());
|
||||
_blocRole
|
||||
.add(const CheckSpacesStepStatus());
|
||||
} else {
|
||||
_blocRole.add(const SendInviteUsers());
|
||||
}
|
||||
} else {
|
||||
_blocRole
|
||||
.add(SendInviteUsers(context: context));
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -161,12 +160,84 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
}
|
||||
}
|
||||
|
||||
int step3 = 0;
|
||||
|
||||
Widget _buildStep1Indicator(int step, String label, UsersBloc bloc) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
bloc.add(const CheckSpacesStepStatus());
|
||||
currentStep = step;
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
bloc.add(const ValidateBasicsStep());
|
||||
});
|
||||
});
|
||||
|
||||
if (step3 == 3) {
|
||||
bloc.add(const CheckRoleStepStatus());
|
||||
}
|
||||
},
|
||||
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.isCompleteBasics == false
|
||||
? Assets.wrongProcessIcon
|
||||
: bloc.isCompleteBasics == true
|
||||
? Assets.completeProcessIcon
|
||||
: 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 _buildStep2Indicator(int step, String label, UsersBloc bloc) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
currentStep = step;
|
||||
bloc.add(const CheckStepStatus());
|
||||
if (step3 == 3) {
|
||||
bloc.add(const CheckRoleStepStatus());
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Column(
|
||||
@@ -221,15 +292,14 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStep1Indicator(int step, String label, UsersBloc bloc) {
|
||||
Widget _buildStep3Indicator(int step, String label, UsersBloc bloc) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
bloc.add(const CheckSpacesStepStatus());
|
||||
currentStep = step;
|
||||
});
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
bloc.add(const ValidateBasicsStep());
|
||||
step3 = step;
|
||||
bloc.add(const CheckSpacesStepStatus());
|
||||
bloc.add(const CheckStepStatus());
|
||||
});
|
||||
},
|
||||
child: Column(
|
||||
@@ -243,9 +313,9 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
SvgPicture.asset(
|
||||
currentStep == step
|
||||
? Assets.currentProcessIcon
|
||||
: bloc.isCompleteBasics == false
|
||||
: bloc.isCompleteRolePermissions == false
|
||||
? Assets.wrongProcessIcon
|
||||
: bloc.isCompleteBasics == true
|
||||
: bloc.isCompleteRolePermissions == true
|
||||
? Assets.completeProcessIcon
|
||||
: Assets.uncomplete_ProcessIcon,
|
||||
width: 25,
|
||||
@@ -283,63 +353,4 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildStep3Indicator(int step, String label, UsersBloc bloc) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
currentStep = step;
|
||||
bloc.add(const CheckSpacesStepStatus());
|
||||
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.isCompleteRolePermissions == 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,
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+68
-31
@@ -1,9 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:intl_phone_field/countries.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/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
@@ -30,7 +32,7 @@ class BasicsView extends StatelessWidget {
|
||||
color: Colors.black),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 80,
|
||||
height: 50,
|
||||
),
|
||||
Text(
|
||||
'To get started, fill out some basic information about who you’re adding as a user.',
|
||||
@@ -40,11 +42,10 @@ class BasicsView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 25,
|
||||
height: 35,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
// First Name
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -52,9 +53,6 @@ class BasicsView extends StatelessWidget {
|
||||
SizedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
// SizedBox(
|
||||
// width: 15,
|
||||
// ),
|
||||
const Text(
|
||||
" * ",
|
||||
style: TextStyle(
|
||||
@@ -75,7 +73,14 @@ class BasicsView extends StatelessWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(color: Colors.black),
|
||||
style:
|
||||
const TextStyle(color: ColorsManager.blackColor),
|
||||
onChanged: (value) {
|
||||
Future.delayed(const Duration(milliseconds: 200),
|
||||
() {
|
||||
_blocRole.add(ValidateBasicsStep());
|
||||
});
|
||||
},
|
||||
controller: _blocRole.firstNameController,
|
||||
decoration: inputTextFormDeco(
|
||||
hintText: "Enter first name",
|
||||
@@ -96,10 +101,7 @@ class BasicsView extends StatelessWidget {
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(width: 10),
|
||||
|
||||
// Last Name
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -125,8 +127,14 @@ class BasicsView extends StatelessWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
onChanged: (value) {
|
||||
Future.delayed(const Duration(milliseconds: 200),
|
||||
() {
|
||||
_blocRole.add(ValidateBasicsStep());
|
||||
});
|
||||
},
|
||||
controller: _blocRole.lastNameController,
|
||||
style: TextStyle(color: Colors.black),
|
||||
style: const TextStyle(color: Colors.black),
|
||||
decoration:
|
||||
inputTextFormDeco(hintText: "Enter last name")
|
||||
.copyWith(
|
||||
@@ -149,7 +157,7 @@ class BasicsView extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
const SizedBox(height: 10),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -176,8 +184,14 @@ class BasicsView extends StatelessWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
onChanged: (value) {
|
||||
Future.delayed(const Duration(milliseconds: 200), () {
|
||||
_blocRole.add(const CheckStepStatus());
|
||||
_blocRole.add(ValidateBasicsStep());
|
||||
});
|
||||
},
|
||||
controller: _blocRole.emailController,
|
||||
style: TextStyle(color: Colors.black),
|
||||
style: const TextStyle(color: ColorsManager.blackColor),
|
||||
decoration: inputTextFormDeco(hintText: "[email protected]")
|
||||
.copyWith(
|
||||
hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||
@@ -189,24 +203,24 @@ class BasicsView extends StatelessWidget {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Enter Email Address';
|
||||
}
|
||||
// Regular expression for email validation
|
||||
final emailRegex = RegExp(
|
||||
r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$',
|
||||
);
|
||||
if (!emailRegex.hasMatch(value)) {
|
||||
return 'Enter a valid Email Address';
|
||||
}
|
||||
if (_blocRole.checkEmailValid != "Valid email") {
|
||||
return _blocRole.checkEmailValid;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
// Phone Number
|
||||
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -227,7 +241,8 @@ class BasicsView extends StatelessWidget {
|
||||
pickerDialogStyle: PickerDialogStyle(),
|
||||
dropdownIconPosition: IconPosition.leading,
|
||||
disableLengthCheck: true,
|
||||
dropdownTextStyle: TextStyle(color: Colors.black),
|
||||
dropdownTextStyle:
|
||||
const TextStyle(color: ColorsManager.blackColor),
|
||||
textInputAction: TextInputAction.done,
|
||||
decoration: inputTextFormDeco(
|
||||
hintText: "05x xxx xxxx",
|
||||
@@ -238,18 +253,39 @@ class BasicsView extends StatelessWidget {
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
initialCountryCode: 'AE',
|
||||
style: TextStyle(color: Colors.black),
|
||||
onChanged: (phone) {
|
||||
print(phone.completeNumber);
|
||||
},
|
||||
countries: const [
|
||||
Country(
|
||||
name: "United Arab Emirates",
|
||||
nameTranslations: {
|
||||
"en": "United Arab Emirates",
|
||||
"ar": "الإمارات العربية المتحدة",
|
||||
},
|
||||
flag: "🇦🇪",
|
||||
code: "AE",
|
||||
dialCode: "971",
|
||||
minLength: 9,
|
||||
maxLength: 9,
|
||||
),
|
||||
Country(
|
||||
name: "Saudi Arabia",
|
||||
nameTranslations: {
|
||||
"en": "Saudi Arabia",
|
||||
"ar": "السعودية",
|
||||
},
|
||||
flag: "🇸🇦",
|
||||
code: "SA",
|
||||
dialCode: "966",
|
||||
minLength: 9,
|
||||
maxLength: 9,
|
||||
),
|
||||
],
|
||||
style: const TextStyle(color: Colors.black),
|
||||
controller: _blocRole.phoneController,
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
SizedBox(width: 10),
|
||||
|
||||
// Job Title
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -270,7 +306,8 @@ class BasicsView extends StatelessWidget {
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
controller: _blocRole.jobTitleController,
|
||||
style: TextStyle(color: Colors.black),
|
||||
style:
|
||||
const TextStyle(color: ColorsManager.blackColor),
|
||||
decoration: inputTextFormDeco(
|
||||
hintText: "Job Title (Optional)")
|
||||
.copyWith(
|
||||
@@ -287,7 +324,7 @@ class BasicsView extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 20),
|
||||
const SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
);
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_bloc/flutter_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_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class DeleteUserDialog extends StatefulWidget {
|
||||
+239
@@ -0,0 +1,239 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/permission_option_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
|
||||
class PermissionManagement extends StatefulWidget {
|
||||
final UsersBloc? bloc;
|
||||
const PermissionManagement({Key? key, this.bloc}) : super(key: key);
|
||||
|
||||
@override
|
||||
_PermissionManagementState createState() => _PermissionManagementState();
|
||||
}
|
||||
|
||||
class _PermissionManagementState extends State<PermissionManagement> {
|
||||
void toggleOptionById(String id) {
|
||||
setState(() {
|
||||
for (var mainOption in widget.bloc!.permissions) {
|
||||
if (mainOption.id == id) {
|
||||
final isChecked =
|
||||
checkifOneOfthemChecked(mainOption) == CheckState.all;
|
||||
mainOption.isChecked = !isChecked;
|
||||
|
||||
for (var subOption in mainOption.subOptions) {
|
||||
subOption.isChecked = !isChecked;
|
||||
for (var child in subOption.subOptions) {
|
||||
child.isChecked = !isChecked;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (var subOption in mainOption.subOptions) {
|
||||
if (subOption.id == id) {
|
||||
subOption.isChecked = !subOption.isChecked;
|
||||
for (var child in subOption.subOptions) {
|
||||
child.isChecked = subOption.isChecked;
|
||||
}
|
||||
mainOption.isChecked =
|
||||
mainOption.subOptions.every((sub) => sub.isChecked);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var child in subOption.subOptions) {
|
||||
if (child.id == id) {
|
||||
child.isChecked = !child.isChecked;
|
||||
subOption.isChecked =
|
||||
subOption.subOptions.every((child) => child.isChecked);
|
||||
mainOption.isChecked =
|
||||
mainOption.subOptions.every((sub) => sub.isChecked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CheckState checkifOneOfthemChecked(PermissionOption mainOption) {
|
||||
bool allSelected = true;
|
||||
bool someSelected = false;
|
||||
|
||||
for (var subOption in mainOption.subOptions) {
|
||||
if (subOption.isChecked) {
|
||||
someSelected = true;
|
||||
} else {
|
||||
allSelected = false;
|
||||
}
|
||||
|
||||
for (var child in subOption.subOptions) {
|
||||
if (child.isChecked) {
|
||||
someSelected = true;
|
||||
} else {
|
||||
allSelected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allSelected) {
|
||||
return CheckState.all;
|
||||
} else if (someSelected) {
|
||||
return CheckState.some;
|
||||
} else {
|
||||
return CheckState.none;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(8),
|
||||
itemCount: widget.bloc!.permissions.length,
|
||||
itemBuilder: (context, index) {
|
||||
final option = widget.bloc!.permissions[index];
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
InkWell(
|
||||
// onTap: () => toggleOptionById(option.id),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final checkState = checkifOneOfthemChecked(option);
|
||||
|
||||
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(
|
||||
option.title,
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.blackColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
...option.subOptions.map((subOption) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
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,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
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),
|
||||
child: GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: 2.0,
|
||||
crossAxisSpacing: 0.2,
|
||||
childAspectRatio: 5,
|
||||
),
|
||||
itemCount: subOption.subOptions.length,
|
||||
itemBuilder: (context, index) {
|
||||
final child = subOption.subOptions[index];
|
||||
return CheckboxListTile(
|
||||
selectedTileColor: child.isHighlighted
|
||||
? Colors.blue.shade50
|
||||
: Colors.white,
|
||||
dense: true,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
title: Text(
|
||||
child.title,
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.lightGreyColor),
|
||||
),
|
||||
value: child.isChecked,
|
||||
onChanged: (value) => toggleOptionById(child.id),
|
||||
enabled: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class RoleDropdown extends StatefulWidget {
|
||||
final UsersBloc? bloc;
|
||||
const RoleDropdown({super.key, this.bloc});
|
||||
|
||||
@override
|
||||
_RoleDropdownState createState() => _RoleDropdownState();
|
||||
}
|
||||
|
||||
class _RoleDropdownState extends State<RoleDropdown> {
|
||||
late String selectedRole;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
selectedRole = widget.bloc!.roleSelected;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Row(
|
||||
children: [
|
||||
Text(
|
||||
" * ",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
fontWeight: FontWeight.w900,
|
||||
fontSize: 15,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
"Role",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
child: DropdownButtonFormField<String>(
|
||||
dropdownColor: ColorsManager.whiteColors,
|
||||
alignment: Alignment.center,
|
||||
focusColor: Colors.white,
|
||||
autofocus: true,
|
||||
value: selectedRole.isNotEmpty ? selectedRole : null,
|
||||
items: widget.bloc!.roles.map((role) {
|
||||
return DropdownMenuItem<String>(
|
||||
value: role.uuid,
|
||||
child: Text(role.type),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
selectedRole = value!;
|
||||
});
|
||||
widget.bloc!.roleSelected = selectedRole;
|
||||
widget.bloc!
|
||||
.add(PermissionEvent(roleUuid: widget.bloc!.roleSelected));
|
||||
},
|
||||
icon: const SizedBox.shrink(),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||
hint: const Padding(
|
||||
padding: EdgeInsets.only(left: 10),
|
||||
child: Text(
|
||||
"Please Select",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
),
|
||||
decoration: inputTextFormDeco().copyWith(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
suffixIcon: Container(
|
||||
padding: EdgeInsets.zero,
|
||||
width: 70,
|
||||
height: 45,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[200],
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomRight: Radius.circular(10),
|
||||
topRight: Radius.circular(10),
|
||||
),
|
||||
border: Border.all(
|
||||
color: ColorsManager.textGray,
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
child: const Center(
|
||||
child: Icon(
|
||||
Icons.keyboard_arrow_down,
|
||||
color: ColorsManager.textGray,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
+127
@@ -0,0 +1,127 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/permission_management.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/role_dropdown.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class RolesAndPermission extends StatelessWidget {
|
||||
const RolesAndPermission({super.key});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final size = MediaQuery.of(context).size;
|
||||
|
||||
return BlocBuilder<UsersBloc, UsersState>(builder: (context, state) {
|
||||
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: Form(
|
||||
key: _blocRole.formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Role & Permissions',
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 20,
|
||||
color: Colors.black),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
SizedBox(
|
||||
width: 350,
|
||||
height: 100,
|
||||
child: RoleDropdown(
|
||||
bloc: _blocRole,
|
||||
)),
|
||||
const SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: ColorsManager.CircleRolesBackground,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(20),
|
||||
topLeft: Radius.circular(20)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(20)),
|
||||
border: Border.all(
|
||||
color: ColorsManager.grayBorder)),
|
||||
child: TextFormField(
|
||||
style:
|
||||
const TextStyle(color: Colors.black),
|
||||
controller:
|
||||
_blocRole.roleSearchController,
|
||||
onChanged: (value) {
|
||||
_blocRole.add(SearchPermission(
|
||||
nodes: _blocRole.permissions,
|
||||
searchTerm: value));
|
||||
},
|
||||
decoration: textBoxDecoration(radios: 20)!
|
||||
.copyWith(
|
||||
fillColor: Colors.white,
|
||||
suffixIcon: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(right: 16),
|
||||
child: SvgPicture.asset(
|
||||
Assets.textFieldSearch,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
hintStyle: context.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 7,
|
||||
child: Container(
|
||||
color: ColorsManager.CircleRolesBackground,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: PermissionManagement(
|
||||
bloc: _blocRole,
|
||||
))))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
+4
-4
@@ -1,10 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.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_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/add_user_dialog/bloc/users_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/bloc/users_status.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/model/tree_node_model.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
@@ -0,0 +1,185 @@
|
||||
import 'dart:async';
|
||||
import 'package:bloc/bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_state.dart';
|
||||
|
||||
class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
UserTableBloc() : super(TableInitial()) {
|
||||
on<GetUsers>(_getUsers);
|
||||
on<ChangeUserStatus>(_changeUserStatus);
|
||||
on<SortUsersByNameAsc>(_toggleSortUsersByNameAsc);
|
||||
on<SortUsersByNameDesc>(_toggleSortUsersByNameDesc);
|
||||
on<DateOldestToNewestEvent>(_toggleSortUsersByDateOldestToNewest);
|
||||
on<DateNewestToOldestEvent>(_toggleSortUsersByDateNewestToOldest);
|
||||
}
|
||||
|
||||
List<RolesUserModel> users = [];
|
||||
List<RolesUserModel> initialUsers = []; // Save the initial state
|
||||
String currentSortOrder = ''; // Keeps track of the current sorting order
|
||||
String currentSortOrderDate = ''; // Keeps track of the current sorting order
|
||||
|
||||
Future<void> _getUsers(GetUsers event, Emitter<UserTableState> emit) async {
|
||||
emit(UsersLoadingState());
|
||||
try {
|
||||
users = [
|
||||
RolesUserModel(
|
||||
id: '1',
|
||||
userName: 'b 1',
|
||||
userEmail: '[email protected]',
|
||||
action: '',
|
||||
createdBy: 'Admin',
|
||||
creationDate: '25/10/2024',
|
||||
creationTime: '10:30 AM',
|
||||
status: 'Invited',
|
||||
),
|
||||
RolesUserModel(
|
||||
id: '2',
|
||||
userName: 'a 2',
|
||||
userEmail: '[email protected]',
|
||||
action: '',
|
||||
createdBy: 'Admin',
|
||||
creationDate: '24/10/2024',
|
||||
creationTime: '2:30 PM',
|
||||
status: 'Active',
|
||||
),
|
||||
RolesUserModel(
|
||||
id: '3',
|
||||
userName: 'c 3',
|
||||
userEmail: '[email protected]',
|
||||
action: '',
|
||||
createdBy: 'Admin',
|
||||
creationDate: '23/10/2024',
|
||||
creationTime: '9:00 AM',
|
||||
status: 'Disabled',
|
||||
),
|
||||
];
|
||||
// Sort users by newest to oldest as default
|
||||
users.sort((a, b) {
|
||||
final dateA = _parseDateTime(a.creationDate!);
|
||||
final dateB = _parseDateTime(b.creationDate!);
|
||||
return dateB.compareTo(dateA); // Newest to oldest
|
||||
});
|
||||
initialUsers = List.from(users); // Save the initial state
|
||||
emit(UsersLoadedState(users: users));
|
||||
} catch (e) {
|
||||
emit(ErrorState(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _changeUserStatus(ChangeUserStatus event, Emitter<UserTableState> emit) {
|
||||
try {
|
||||
users = users.map((user) {
|
||||
if (user.id == event.userId) {
|
||||
return RolesUserModel(
|
||||
id: user.id,
|
||||
userName: user.userName,
|
||||
userEmail: user.userEmail,
|
||||
createdBy: user.createdBy,
|
||||
creationDate: user.creationDate,
|
||||
creationTime: user.creationTime,
|
||||
status: event.newStatus,
|
||||
action: user.action,
|
||||
);
|
||||
}
|
||||
return user;
|
||||
}).toList();
|
||||
|
||||
emit(UsersLoadedState(users: users));
|
||||
} catch (e) {
|
||||
emit(ErrorState(e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
void _toggleSortUsersByNameAsc(
|
||||
SortUsersByNameAsc event, Emitter<UserTableState> emit) {
|
||||
if (currentSortOrder == "Asc") {
|
||||
// If already sorted ascending, reset to the initial state
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "";
|
||||
users = List.from(initialUsers); // Reset to saved initial state
|
||||
emit(UsersLoadedState(users: users));
|
||||
} else {
|
||||
// Sort ascending
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "Asc";
|
||||
users.sort((a, b) => a.userName!.compareTo(b.userName!));
|
||||
emit(UsersLoadedState(users: users));
|
||||
}
|
||||
}
|
||||
|
||||
void _toggleSortUsersByNameDesc(
|
||||
SortUsersByNameDesc event, Emitter<UserTableState> emit) {
|
||||
if (currentSortOrder == "Desc") {
|
||||
// If already sorted descending, reset to the initial state
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "";
|
||||
users = List.from(initialUsers); // Reset to saved initial state
|
||||
emit(UsersLoadedState(users: users));
|
||||
} else {
|
||||
// Sort descending
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "Desc";
|
||||
users.sort((a, b) => b.userName!.compareTo(a.userName!));
|
||||
emit(UsersLoadedState(users: users));
|
||||
}
|
||||
}
|
||||
|
||||
void _toggleSortUsersByDateNewestToOldest(
|
||||
DateNewestToOldestEvent event, Emitter<UserTableState> emit) {
|
||||
if (currentSortOrderDate == "NewestToOldest") {
|
||||
// If already sorted ascending, reset to the initial state
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "";
|
||||
currentSortOrderDate = "";
|
||||
users = List.from(initialUsers); // Reset to saved initial state
|
||||
emit(UsersLoadedState(users: users));
|
||||
} else {
|
||||
// Sort ascending
|
||||
emit(UsersLoadingState());
|
||||
users.sort((a, b) {
|
||||
final dateA = _parseDateTime(a.creationDate!);
|
||||
final dateB = _parseDateTime(b.creationDate!);
|
||||
return dateB.compareTo(dateA); // Newest to oldest
|
||||
});
|
||||
emit(UsersLoadedState(users: users));
|
||||
}
|
||||
}
|
||||
|
||||
void _toggleSortUsersByDateOldestToNewest(
|
||||
DateOldestToNewestEvent event, Emitter<UserTableState> emit) {
|
||||
if (currentSortOrderDate == "OldestToNewest") {
|
||||
// If already sorted ascending, reset to the initial state
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "";
|
||||
currentSortOrderDate = "";
|
||||
users = List.from(initialUsers); // Reset to saved initial state
|
||||
emit(UsersLoadedState(users: users));
|
||||
} else {
|
||||
// Sort ascending
|
||||
emit(UsersLoadingState());
|
||||
users.sort((a, b) {
|
||||
final dateA = _parseDateTime(a.creationDate!);
|
||||
final dateB = _parseDateTime(b.creationDate!);
|
||||
return dateA.compareTo(dateB); // Newest to oldest
|
||||
});
|
||||
emit(UsersLoadedState(users: users));
|
||||
}
|
||||
}
|
||||
|
||||
DateTime _parseDateTime(String date) {
|
||||
try {
|
||||
// Split the date into day, month, and year
|
||||
final dateParts = date.split('/');
|
||||
final day = int.parse(dateParts[0]);
|
||||
final month = int.parse(dateParts[1]);
|
||||
final year = int.parse(dateParts[2]);
|
||||
|
||||
// Split the time into hours and minutes
|
||||
|
||||
return DateTime(year, month, day);
|
||||
} catch (e) {
|
||||
throw FormatException('Invalid date or time format: $date ');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
|
||||
sealed class UserTableEvent extends Equatable {
|
||||
const UserTableEvent();
|
||||
}
|
||||
|
||||
class GetRoles extends UserTableEvent {
|
||||
const GetRoles();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class GetUsers extends UserTableEvent {
|
||||
const GetUsers();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class ChangeUserStatus extends UserTableEvent {
|
||||
final String userId;
|
||||
final String newStatus;
|
||||
|
||||
const ChangeUserStatus({required this.userId, required this.newStatus});
|
||||
|
||||
@override
|
||||
List<Object?> get props => [userId, newStatus];
|
||||
}
|
||||
|
||||
class SortUsersByNameAsc extends UserTableEvent {
|
||||
const SortUsersByNameAsc();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class SortUsersByNameDesc extends UserTableEvent {
|
||||
const SortUsersByNameDesc();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class StoreUsersEvent extends UserTableEvent {
|
||||
const StoreUsersEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
|
||||
class DateNewestToOldestEvent extends UserTableEvent {
|
||||
const DateNewestToOldestEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class DateOldestToNewestEvent extends UserTableEvent {
|
||||
const DateOldestToNewestEvent();
|
||||
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
import 'package:equatable/equatable.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/model/roles_user_model.dart';
|
||||
|
||||
sealed class UserTableState extends Equatable {
|
||||
const UserTableState();
|
||||
}
|
||||
|
||||
final class TableInitial extends UserTableState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class RolesLoadingState extends UserTableState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class UsersLoadingState extends UserTableState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class RolesLoadedState extends UserTableState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class UsersLoadedState extends UserTableState {
|
||||
List<RolesUserModel> users = [];
|
||||
UsersLoadedState({required this.users});
|
||||
@override
|
||||
List<Object> get props => [users];
|
||||
}
|
||||
|
||||
final class ErrorState extends UserTableState {
|
||||
final String message;
|
||||
|
||||
const ErrorState(this.message);
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
|
||||
/// report state
|
||||
final class SosReportLoadingState extends UserTableState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class RolesErrorState extends UserTableState {
|
||||
final String message;
|
||||
|
||||
const RolesErrorState(this.message);
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
|
||||
/// automation reports
|
||||
|
||||
final class SosAutomationReportLoadingState extends UserTableState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class SosAutomationReportErrorState extends UserTableState {
|
||||
final String message;
|
||||
|
||||
const SosAutomationReportErrorState(this.message);
|
||||
|
||||
@override
|
||||
List<Object> get props => [message];
|
||||
}
|
||||
|
||||
final class ChangeTapStatus extends UserTableState {
|
||||
bool select = true;
|
||||
|
||||
ChangeTapStatus({required this.select});
|
||||
|
||||
@override
|
||||
List<Object> get props => [select];
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
Future<void> showDateFilterMenu({
|
||||
required BuildContext context,
|
||||
Function()? aToZTap,
|
||||
Function()? zToaTap,
|
||||
String? isSelected,
|
||||
}) async {
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
final RelativeRect position = RelativeRect.fromRect(
|
||||
Rect.fromLTRB(
|
||||
overlay.size.width / 2,
|
||||
240,
|
||||
0,
|
||||
overlay.size.height,
|
||||
),
|
||||
Offset.zero & overlay.size,
|
||||
);
|
||||
|
||||
await showMenu(
|
||||
context: context,
|
||||
position: position,
|
||||
color: ColorsManager.whiteColors,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomRight: Radius.circular(10),
|
||||
bottomLeft: Radius.circular(10),
|
||||
),
|
||||
),
|
||||
items: <PopupMenuEntry>[
|
||||
PopupMenuItem(
|
||||
onTap: aToZTap,
|
||||
child: ListTile(
|
||||
leading: Image.asset(
|
||||
Assets.AtoZIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: Text(
|
||||
"Sort from newest to oldest",
|
||||
// style: context.textTheme.bodyMedium,
|
||||
style: TextStyle(
|
||||
color: isSelected == "NewestToOldest"
|
||||
? Colors.black
|
||||
: Colors.blueGrey),
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: zToaTap,
|
||||
child: ListTile(
|
||||
leading: Image.asset(
|
||||
Assets.ZtoAIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: Text(
|
||||
"Sort from oldest to newest",
|
||||
style: TextStyle(
|
||||
color: isSelected == "OldestToNewest"
|
||||
? Colors.black
|
||||
: Colors.blueGrey),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
).then((value) {
|
||||
// setState(() {
|
||||
// _isDropdownOpen = false;
|
||||
// });
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
Future<void> showDeActivateFilterMenu({
|
||||
required BuildContext context,
|
||||
Function()? aToZTap,
|
||||
Function()? zToaTap,
|
||||
String? isSelected,
|
||||
}) async {
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
final RelativeRect position = RelativeRect.fromRect(
|
||||
Rect.fromLTRB(
|
||||
overlay.size.width / 2,
|
||||
240,
|
||||
0,
|
||||
overlay.size.height,
|
||||
),
|
||||
Offset.zero & overlay.size,
|
||||
);
|
||||
|
||||
await showMenu(
|
||||
context: context,
|
||||
position: position,
|
||||
color: ColorsManager.whiteColors,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomRight: Radius.circular(10),
|
||||
bottomLeft: Radius.circular(10),
|
||||
),
|
||||
),
|
||||
items: <PopupMenuEntry>[
|
||||
PopupMenuItem(
|
||||
onTap: aToZTap,
|
||||
child: ListTile(
|
||||
leading: Image.asset(
|
||||
Assets.AtoZIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: Text(
|
||||
"Sort A to Z",
|
||||
// style: context.textTheme.bodyMedium,
|
||||
style: TextStyle(
|
||||
color: isSelected == "NewestToOldest"
|
||||
? Colors.black
|
||||
: Colors.blueGrey),
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: zToaTap,
|
||||
child: ListTile(
|
||||
leading: Image.asset(
|
||||
Assets.ZtoAIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: Text(
|
||||
"Sort Z to A",
|
||||
style: TextStyle(
|
||||
color: isSelected == "OldestToNewest"
|
||||
? Colors.black
|
||||
: Colors.blueGrey),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
).then((value) {
|
||||
// setState(() {
|
||||
// _isDropdownOpen = false;
|
||||
// });
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
|
||||
Future<void> showNameMenu({
|
||||
required BuildContext context,
|
||||
Function()? aToZTap,
|
||||
Function()? zToaTap,
|
||||
String? isSelected,
|
||||
}) async {
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
final RelativeRect position = RelativeRect.fromRect(
|
||||
Rect.fromLTRB(
|
||||
overlay.size.width / 25,
|
||||
240,
|
||||
0,
|
||||
overlay.size.height,
|
||||
),
|
||||
Offset.zero & overlay.size,
|
||||
);
|
||||
|
||||
await showMenu(
|
||||
context: context,
|
||||
position: position,
|
||||
color: ColorsManager.whiteColors,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomRight: Radius.circular(10),
|
||||
bottomLeft: Radius.circular(10),
|
||||
),
|
||||
),
|
||||
items: <PopupMenuEntry>[
|
||||
PopupMenuItem(
|
||||
onTap: aToZTap,
|
||||
child: ListTile(
|
||||
leading: Image.asset(
|
||||
Assets.AtoZIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: Text(
|
||||
"Sort A to Z",
|
||||
// style: context.textTheme.bodyMedium,
|
||||
style: TextStyle(
|
||||
color: isSelected == "Asc" ? Colors.black : Colors.blueGrey),
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: zToaTap,
|
||||
child: ListTile(
|
||||
leading: Image.asset(
|
||||
Assets.ZtoAIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: Text(
|
||||
"Sort Z to A",
|
||||
style: TextStyle(
|
||||
color: isSelected == "Desc" ? Colors.black : Colors.blueGrey),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
).then((value) {
|
||||
// setState(() {
|
||||
// _isDropdownOpen = false;
|
||||
// });
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,299 @@
|
||||
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/utils/style.dart';
|
||||
|
||||
class DynamicTableScreen extends StatefulWidget {
|
||||
final List<String> titles;
|
||||
final List<List<Widget>> rows;
|
||||
final void Function(int columnIndex)? onFilter;
|
||||
|
||||
DynamicTableScreen(
|
||||
{required this.titles, required this.rows, required this.onFilter});
|
||||
|
||||
@override
|
||||
_DynamicTableScreenState createState() => _DynamicTableScreenState();
|
||||
}
|
||||
|
||||
class _DynamicTableScreenState extends State<DynamicTableScreen>
|
||||
with WidgetsBindingObserver {
|
||||
late List<double> columnWidths;
|
||||
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
// // Initialize column widths with default sizes proportional to the screen width
|
||||
// // Assigning placeholder values here. The actual sizes will be updated in `build`.
|
||||
// }
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
columnWidths = List<double>.filled(widget.titles.length, 150.0);
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
super.didChangeMetrics();
|
||||
// Screen size might have changed
|
||||
final newScreenWidth = MediaQuery.of(context).size.width;
|
||||
setState(() {
|
||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
||||
if (index == 1) {
|
||||
return newScreenWidth *
|
||||
0.12; // 20% of screen width for the second column
|
||||
} else if (index == 9) {
|
||||
return newScreenWidth *
|
||||
0.2; // 25% of screen width for the tenth column
|
||||
}
|
||||
return newScreenWidth *
|
||||
0.09; // Default to 10% of screen width for other columns
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
// Initialize column widths if they are still set to placeholder values
|
||||
if (columnWidths.every((width) => width == 120.0)) {
|
||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
||||
if (index == 1) {
|
||||
return screenWidth * 0.11;
|
||||
} else if (index == 9) {
|
||||
return screenWidth * 0.2;
|
||||
}
|
||||
return screenWidth * 0.11;
|
||||
});
|
||||
setState(() {});
|
||||
}
|
||||
return Container(
|
||||
child: SingleChildScrollView(
|
||||
clipBehavior: Clip.none,
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(20))),
|
||||
child: FittedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
// Header Row with Resizable Columns
|
||||
Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.CircleRolesBackground,
|
||||
borderRadius: BorderRadius.only(
|
||||
topLeft: Radius.circular(15),
|
||||
topRight: Radius.circular(15))),
|
||||
child: Row(
|
||||
children: List.generate(widget.titles.length, (index) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
FittedBox(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 5, right: 5),
|
||||
width: columnWidths[index],
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: Text(
|
||||
widget.titles[index],
|
||||
maxLines: 2,
|
||||
style: const TextStyle(
|
||||
overflow: TextOverflow.ellipsis,
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 13,
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (index != 1 &&
|
||||
index != 9 &&
|
||||
index != 7 &&
|
||||
index != 5)
|
||||
FittedBox(
|
||||
child: IconButton(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.filterTableIcon,
|
||||
fit: BoxFit.none,
|
||||
),
|
||||
onPressed: () {
|
||||
if (widget.onFilter != null) {
|
||||
widget.onFilter!(index);
|
||||
}
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onHorizontalDragUpdate: (details) {
|
||||
setState(() {
|
||||
columnWidths[index] = (columnWidths[index] +
|
||||
details.delta.dx)
|
||||
.clamp(
|
||||
150.0, 300.0); // Minimum & Maximum size
|
||||
});
|
||||
},
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors
|
||||
.resizeColumn, // Set the cursor to resize
|
||||
child: Container(
|
||||
color: Colors.green,
|
||||
child: Container(
|
||||
color: ColorsManager.boxDivider,
|
||||
width: 1,
|
||||
height: 50, // Height of the header cell
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
// Data Rows with Dividers
|
||||
Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(15),
|
||||
bottomRight: Radius.circular(15))),
|
||||
child: Column(
|
||||
children: widget.rows.map((row) {
|
||||
int rowIndex = widget.rows.indexOf(row);
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 5, top: 10, right: 5, bottom: 10),
|
||||
child: Row(
|
||||
children: List.generate(row.length, (index) {
|
||||
return SizedBox(
|
||||
width: columnWidths[index],
|
||||
child: SizedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 15, right: 10),
|
||||
child: row[index],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (rowIndex < widget.rows.length - 1)
|
||||
Row(
|
||||
children: List.generate(widget.titles.length,
|
||||
(index) {
|
||||
return SizedBox(
|
||||
width: columnWidths[index],
|
||||
child: const Divider(
|
||||
color: ColorsManager.boxDivider,
|
||||
thickness: 1,
|
||||
height: 1,
|
||||
),
|
||||
);
|
||||
}))
|
||||
// Add a Divider below each row except the last one
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Widget build(BuildContext context) {
|
||||
// return Scaffold(
|
||||
// body: SingleChildScrollView(
|
||||
// scrollDirection: Axis.horizontal,
|
||||
// child: SingleChildScrollView(
|
||||
// scrollDirection: Axis.vertical,
|
||||
// child: Column(
|
||||
// children: [
|
||||
// // Header Row with Resizable Columns
|
||||
// Container(
|
||||
// color: Colors.green,
|
||||
// child: Row(
|
||||
// children: List.generate(widget.titles.length, (index) {
|
||||
// return Row(
|
||||
// children: [
|
||||
// Container(
|
||||
// width: columnWidths[index],
|
||||
// decoration: const BoxDecoration(
|
||||
// color: Colors.green,
|
||||
// ),
|
||||
// child: Text(
|
||||
// widget.titles[index],
|
||||
// style: TextStyle(fontWeight: FontWeight.bold),
|
||||
// textAlign: TextAlign.center,
|
||||
// ),
|
||||
// ),
|
||||
// GestureDetector(
|
||||
// onHorizontalDragUpdate: (details) {
|
||||
// setState(() {
|
||||
// columnWidths[index] = (columnWidths[index] +
|
||||
// details.delta.dx)
|
||||
// .clamp(50.0, 300.0); // Minimum & Maximum size
|
||||
// });
|
||||
// },
|
||||
// child: MouseRegion(
|
||||
// cursor: SystemMouseCursors
|
||||
// .resizeColumn, // Set the cursor to resize
|
||||
// child: Container(
|
||||
// color: Colors.green,
|
||||
// child: Container(
|
||||
// color: Colors.black,
|
||||
// width: 1,
|
||||
// height: 50, // Height of the header cell
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }),
|
||||
// ),
|
||||
// ),
|
||||
// // Data Rows
|
||||
// ...widget.rows.map((row) {
|
||||
// return Row(
|
||||
// children: List.generate(row.length, (index) {
|
||||
// return Container(
|
||||
// width: columnWidths[index],
|
||||
// child: row[index],
|
||||
// );
|
||||
// }),
|
||||
// );
|
||||
// }).toList(),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
+68
-15
@@ -1,11 +1,14 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart'; // Import Bloc package
|
||||
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/pages/roles_and_permission/users_page/view/add_user_dialog.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/view/user_table.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/add_user_dialog/view/add_user_dialog.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_state.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/creation_date_filter.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/de_activate_filter.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/name_filter.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/user_table.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/assets.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
@@ -85,7 +88,7 @@ class UsersPage extends StatelessWidget {
|
||||
? 'Invited'
|
||||
: 'Active';
|
||||
context
|
||||
.read<UsersBloc>()
|
||||
.read<UserTableBloc>()
|
||||
.add(ChangeUserStatus(userId: userId, newStatus: newStatus));
|
||||
},
|
||||
child: Padding(
|
||||
@@ -104,12 +107,10 @@ class UsersPage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
// return RolesAndPermission();
|
||||
// }
|
||||
// }
|
||||
return BlocBuilder<UsersBloc, UsersState>(
|
||||
return BlocBuilder<UserTableBloc, UserTableState>(
|
||||
builder: (context, state) {
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final _blocRole = BlocProvider.of<UserTableBloc>(context);
|
||||
|
||||
if (state is UsersLoadingState) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
@@ -158,7 +159,9 @@ class UsersPage extends StatelessWidget {
|
||||
return const AddNewUserDialog();
|
||||
},
|
||||
).then((listDevice) {
|
||||
if (listDevice != null) {}
|
||||
if (listDevice != null) {
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Container(
|
||||
@@ -181,6 +184,56 @@ class UsersPage extends StatelessWidget {
|
||||
),
|
||||
const SizedBox(height: 25),
|
||||
DynamicTableScreen(
|
||||
onFilter: (columnIndex) {
|
||||
if (columnIndex == 0) {
|
||||
showNameMenu(
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameAsc());
|
||||
},
|
||||
zToaTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameDesc());
|
||||
},
|
||||
);
|
||||
}
|
||||
if (columnIndex == 4) {
|
||||
showDateFilterMenu(
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrderDate,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateNewestToOldestEvent());
|
||||
},
|
||||
zToaTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateOldestToNewestEvent());
|
||||
},
|
||||
);
|
||||
}
|
||||
if (columnIndex == 8) {
|
||||
showDeActivateFilterMenu(
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrderDate,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateNewestToOldestEvent());
|
||||
},
|
||||
zToaTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const DateOldestToNewestEvent());
|
||||
},
|
||||
);
|
||||
}
|
||||
},
|
||||
titles: const [
|
||||
"Full Name",
|
||||
"Email Address",
|
||||
@@ -210,10 +263,10 @@ class UsersPage extends StatelessWidget {
|
||||
status(status: user.status!),
|
||||
Row(
|
||||
children: [
|
||||
actionButton(
|
||||
title: "Activity Log",
|
||||
onTap: () {},
|
||||
),
|
||||
// actionButton(
|
||||
// title: "Activity Log",
|
||||
// onTap: () {},
|
||||
// ),
|
||||
actionButton(
|
||||
title: "Edit",
|
||||
onTap: () {},
|
||||
@@ -1,489 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
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';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
class RolesAndPermission extends StatelessWidget {
|
||||
const RolesAndPermission({super.key});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final size = MediaQuery.of(context).size;
|
||||
|
||||
return BlocBuilder<UsersBloc, UsersState>(builder: (context, state) {
|
||||
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
||||
return Container(
|
||||
color: Colors.white,
|
||||
child: Form(
|
||||
key: _blocRole.formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Role & Permissions',
|
||||
style: context.textTheme.bodyLarge?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 20,
|
||||
color: Colors.black),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
SizedBox(
|
||||
width: 300,
|
||||
height: 110,
|
||||
child: DropdownExample(
|
||||
bloc: _blocRole,
|
||||
)),
|
||||
const SizedBox(height: 10),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: Container(
|
||||
decoration: const BoxDecoration(
|
||||
color: ColorsManager.CircleRolesBackground,
|
||||
borderRadius: BorderRadius.only(
|
||||
topRight: Radius.circular(20),
|
||||
topLeft: Radius.circular(20)),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: const BorderRadius.all(
|
||||
Radius.circular(20)),
|
||||
border: Border.all(
|
||||
color: ColorsManager.grayBorder)),
|
||||
child: TextFormField(
|
||||
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,
|
||||
suffixIcon: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(right: 16),
|
||||
child: SvgPicture.asset(
|
||||
Assets.textFieldSearch,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
hintStyle: context.textTheme.bodyMedium
|
||||
?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
flex: 7,
|
||||
child: Container(
|
||||
color: ColorsManager.CircleRolesBackground,
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: DeviceManagement(
|
||||
bloc: _blocRole,
|
||||
))))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class DropdownExample extends StatefulWidget {
|
||||
final UsersBloc? bloc;
|
||||
const DropdownExample({super.key, this.bloc});
|
||||
|
||||
@override
|
||||
_DropdownExampleState createState() => _DropdownExampleState();
|
||||
}
|
||||
|
||||
class _DropdownExampleState extends State<DropdownExample> {
|
||||
String? selectedRole;
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
if (widget.bloc != null && widget.bloc!.roles.isNotEmpty) {
|
||||
selectedRole = widget.bloc!.roles.first.uuid;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(10.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
"Role",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
SizedBox(
|
||||
child: DropdownButtonFormField<String>(
|
||||
alignment: Alignment.center,
|
||||
focusColor: Colors.white,
|
||||
autofocus: true,
|
||||
value: selectedRole,
|
||||
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(),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(10)),
|
||||
hint: const Padding(
|
||||
padding: EdgeInsets.only(left: 20),
|
||||
child: Text("Please Select"),
|
||||
),
|
||||
decoration: inputTextFormDeco().copyWith(
|
||||
contentPadding: EdgeInsets.zero,
|
||||
suffixIcon: Container(
|
||||
padding: EdgeInsets.zero,
|
||||
width: 70,
|
||||
height: 50,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[200],
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomRight: Radius.circular(10),
|
||||
topRight: Radius.circular(10),
|
||||
),
|
||||
border: Border.all(
|
||||
color: Colors.grey,
|
||||
width: 1.0,
|
||||
),
|
||||
),
|
||||
child: const Center(
|
||||
child: Icon(Icons.keyboard_arrow_down),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DeviceManagement extends StatefulWidget {
|
||||
final UsersBloc? bloc;
|
||||
const DeviceManagement({Key? key, this.bloc}) : super(key: key);
|
||||
|
||||
@override
|
||||
_DeviceManagementState createState() => _DeviceManagementState();
|
||||
}
|
||||
|
||||
class _DeviceManagementState extends State<DeviceManagement> {
|
||||
void toggleOptionById(String id) {
|
||||
setState(() {
|
||||
for (var mainOption in widget.bloc!.permissions) {
|
||||
if (mainOption.id == id) {
|
||||
final isChecked =
|
||||
checkifOneOfthemChecked(mainOption) == CheckState.all;
|
||||
mainOption.isChecked = !isChecked;
|
||||
|
||||
for (var subOption in mainOption.subOptions) {
|
||||
subOption.isChecked = !isChecked;
|
||||
for (var child in subOption.subOptions) {
|
||||
child.isChecked = !isChecked;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (var subOption in mainOption.subOptions) {
|
||||
if (subOption.id == id) {
|
||||
subOption.isChecked = !subOption.isChecked;
|
||||
for (var child in subOption.subOptions) {
|
||||
child.isChecked = subOption.isChecked;
|
||||
}
|
||||
mainOption.isChecked =
|
||||
mainOption.subOptions.every((sub) => sub.isChecked);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var child in subOption.subOptions) {
|
||||
if (child.id == id) {
|
||||
child.isChecked = !child.isChecked;
|
||||
subOption.isChecked =
|
||||
subOption.subOptions.every((child) => child.isChecked);
|
||||
mainOption.isChecked =
|
||||
mainOption.subOptions.every((sub) => sub.isChecked);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
CheckState checkifOneOfthemChecked(PermissionOption mainOption) {
|
||||
bool allSelected = true;
|
||||
bool someSelected = false;
|
||||
|
||||
for (var subOption in mainOption.subOptions) {
|
||||
if (subOption.isChecked) {
|
||||
someSelected = true;
|
||||
} else {
|
||||
allSelected = false;
|
||||
}
|
||||
|
||||
for (var child in subOption.subOptions) {
|
||||
if (child.isChecked) {
|
||||
someSelected = true;
|
||||
} else {
|
||||
allSelected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allSelected) {
|
||||
return CheckState.all;
|
||||
} else if (someSelected) {
|
||||
return CheckState.some;
|
||||
} else {
|
||||
return CheckState.none;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListView.builder(
|
||||
padding: const EdgeInsets.all(8),
|
||||
itemCount: widget.bloc!.permissions.length,
|
||||
itemBuilder: (context, index) {
|
||||
final option = widget.bloc!.permissions[index];
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
InkWell(
|
||||
// onTap: () => toggleOptionById(option.id),
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
final checkState = checkifOneOfthemChecked(option);
|
||||
|
||||
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(
|
||||
option.title,
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.blackColor),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
...option.subOptions.map((subOption) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
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,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
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),
|
||||
child: GridView.builder(
|
||||
shrinkWrap: true,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
mainAxisSpacing: 2.0,
|
||||
crossAxisSpacing: 0.2,
|
||||
childAspectRatio: 5,
|
||||
),
|
||||
itemCount: subOption.subOptions.length,
|
||||
itemBuilder: (context, index) {
|
||||
final child = subOption.subOptions[index];
|
||||
return CheckboxListTile(
|
||||
selectedTileColor: child.isHighlighted
|
||||
? Colors.blue.shade50
|
||||
: Colors.white,
|
||||
dense: true,
|
||||
controlAffinity: ListTileControlAffinity.leading,
|
||||
title: Text(
|
||||
child.title,
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
color: ColorsManager.lightGreyColor),
|
||||
),
|
||||
value: child.isChecked,
|
||||
onChanged: (value) => toggleOptionById(child.id),
|
||||
enabled: false,
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
|
||||
class DynamicTableScreen extends StatefulWidget {
|
||||
final List<String> titles;
|
||||
final List<List<Widget>> rows;
|
||||
|
||||
DynamicTableScreen({required this.titles, required this.rows});
|
||||
|
||||
@override
|
||||
_DynamicTableScreenState createState() => _DynamicTableScreenState();
|
||||
}
|
||||
|
||||
class _DynamicTableScreenState extends State<DynamicTableScreen>
|
||||
with WidgetsBindingObserver {
|
||||
late List<double> columnWidths;
|
||||
|
||||
// @override
|
||||
// void initState() {
|
||||
// super.initState();
|
||||
// // Initialize column widths with default sizes proportional to the screen width
|
||||
// // Assigning placeholder values here. The actual sizes will be updated in `build`.
|
||||
// }
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
columnWidths = List<double>.filled(widget.titles.length, 150.0);
|
||||
|
||||
WidgetsBinding.instance.addObserver(this);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.removeObserver(this);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void didChangeMetrics() {
|
||||
super.didChangeMetrics();
|
||||
// Screen size might have changed
|
||||
final newScreenWidth = MediaQuery.of(context).size.width;
|
||||
setState(() {
|
||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
||||
if (index == 1) {
|
||||
return newScreenWidth *
|
||||
0.12; // 20% of screen width for the second column
|
||||
} else if (index == 9) {
|
||||
return newScreenWidth *
|
||||
0.2; // 25% of screen width for the tenth column
|
||||
}
|
||||
return newScreenWidth *
|
||||
0.09; // Default to 10% of screen width for other columns
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final screenWidth = MediaQuery.of(context).size.width;
|
||||
|
||||
// Initialize column widths if they are still set to placeholder values
|
||||
if (columnWidths.every((width) => width == 150.0)) {
|
||||
columnWidths = List<double>.generate(widget.titles.length, (index) {
|
||||
if (index == 1) {
|
||||
return screenWidth *
|
||||
0.12; // 20% of screen width for the second column
|
||||
} else if (index == 9) {
|
||||
return screenWidth * 0.2; // 25% of screen width for the tenth column
|
||||
}
|
||||
return screenWidth *
|
||||
0.09; // Default to 10% of screen width for other columns
|
||||
});
|
||||
setState(() {});
|
||||
}
|
||||
return SizedBox(
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: FittedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
// Header Row with Resizable Columns
|
||||
Container(
|
||||
color: ColorsManager.CircleRolesBackground,
|
||||
child: Row(
|
||||
children: List.generate(widget.titles.length, (index) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
FittedBox(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.only(left: 10, right: 10),
|
||||
width: columnWidths[index],
|
||||
child: Text(
|
||||
widget.titles[index],
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 13,
|
||||
color: ColorsManager.grayColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
GestureDetector(
|
||||
onHorizontalDragUpdate: (details) {
|
||||
setState(() {
|
||||
columnWidths[index] = (columnWidths[index] +
|
||||
details.delta.dx)
|
||||
.clamp(
|
||||
150.0, 300.0); // Minimum & Maximum size
|
||||
});
|
||||
},
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors
|
||||
.resizeColumn, // Set the cursor to resize
|
||||
child: Container(
|
||||
color: Colors.green,
|
||||
child: Container(
|
||||
color: ColorsManager.boxDivider,
|
||||
width: 1,
|
||||
height: 50, // Height of the header cell
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
// Data Rows with Dividers
|
||||
Container(
|
||||
color: ColorsManager.whiteColors,
|
||||
child: Column(
|
||||
children: widget.rows.map((row) {
|
||||
int rowIndex = widget.rows.indexOf(row);
|
||||
return Column(
|
||||
children: [
|
||||
Container(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 5, top: 10, right: 5, bottom: 10),
|
||||
child: Row(
|
||||
children: List.generate(row.length, (index) {
|
||||
return SizedBox(
|
||||
width: columnWidths[index],
|
||||
child: SizedBox(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 15, right: 10),
|
||||
child: row[index],
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (rowIndex < widget.rows.length - 1)
|
||||
Row(
|
||||
children:
|
||||
List.generate(widget.titles.length, (index) {
|
||||
return SizedBox(
|
||||
width: columnWidths[index],
|
||||
child: const Divider(
|
||||
color: ColorsManager.boxDivider,
|
||||
thickness: 1,
|
||||
height: 1,
|
||||
),
|
||||
);
|
||||
}))
|
||||
// Add a Divider below each row except the last one
|
||||
],
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Widget build(BuildContext context) {
|
||||
// return Scaffold(
|
||||
// body: SingleChildScrollView(
|
||||
// scrollDirection: Axis.horizontal,
|
||||
// child: SingleChildScrollView(
|
||||
// scrollDirection: Axis.vertical,
|
||||
// child: Column(
|
||||
// children: [
|
||||
// // Header Row with Resizable Columns
|
||||
// Container(
|
||||
// color: Colors.green,
|
||||
// child: Row(
|
||||
// children: List.generate(widget.titles.length, (index) {
|
||||
// return Row(
|
||||
// children: [
|
||||
// Container(
|
||||
// width: columnWidths[index],
|
||||
// decoration: const BoxDecoration(
|
||||
// color: Colors.green,
|
||||
// ),
|
||||
// child: Text(
|
||||
// widget.titles[index],
|
||||
// style: TextStyle(fontWeight: FontWeight.bold),
|
||||
// textAlign: TextAlign.center,
|
||||
// ),
|
||||
// ),
|
||||
// GestureDetector(
|
||||
// onHorizontalDragUpdate: (details) {
|
||||
// setState(() {
|
||||
// columnWidths[index] = (columnWidths[index] +
|
||||
// details.delta.dx)
|
||||
// .clamp(50.0, 300.0); // Minimum & Maximum size
|
||||
// });
|
||||
// },
|
||||
// child: MouseRegion(
|
||||
// cursor: SystemMouseCursors
|
||||
// .resizeColumn, // Set the cursor to resize
|
||||
// child: Container(
|
||||
// color: Colors.green,
|
||||
// child: Container(
|
||||
// color: Colors.black,
|
||||
// width: 1,
|
||||
// height: 50, // Height of the header cell
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// );
|
||||
// }),
|
||||
// ),
|
||||
// ),
|
||||
// // Data Rows
|
||||
// ...widget.rows.map((row) {
|
||||
// return Row(
|
||||
// children: List.generate(row.length, (index) {
|
||||
// return Container(
|
||||
// width: columnWidths[index],
|
||||
// child: row[index],
|
||||
// );
|
||||
// }),
|
||||
// );
|
||||
// }).toList(),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
@@ -2,11 +2,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:syncrow_web/pages/device_managment/shared/navigate_home_grid_view.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/bloc/roles_permission_state.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/view/users_page.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_bloc.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/bloc/user_table_event.dart';
|
||||
import 'package:syncrow_web/pages/roles_and_permission/users_page/users_table/view/users_page.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/extension/build_context_x.dart';
|
||||
import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||
@@ -17,8 +16,7 @@ class RolesAndPermissionPage extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return BlocProvider(
|
||||
create: (BuildContext context) =>
|
||||
RolesPermissionBloc()..add(const GetRoles()),
|
||||
create: (BuildContext context) => RolesPermissionBloc(),
|
||||
child: BlocConsumer<RolesPermissionBloc, RolesPermissionState>(
|
||||
listener: (context, state) {},
|
||||
builder: (context, state) {
|
||||
@@ -77,8 +75,8 @@ class RolesAndPermissionPage extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
scaffoldBody: BlocProvider<UsersBloc>(
|
||||
create: (context) => UsersBloc()..add(const GetUsers()),
|
||||
scaffoldBody: BlocProvider<UserTableBloc>(
|
||||
create: (context) => UserTableBloc()..add(const GetUsers()),
|
||||
child: const UsersPage(),
|
||||
)
|
||||
// _blocRole.tapSelect == false
|
||||
|
||||
@@ -252,7 +252,6 @@ class CommunitySpaceManagementApi {
|
||||
path: ApiEndpoints.getSpaceHierarchy
|
||||
.replaceAll('{communityId}', communityId),
|
||||
expectedResponseModel: (json) {
|
||||
print('=-=-=-=$json');
|
||||
final spaceModels = (json['data'] as List)
|
||||
.map((spaceJson) => SpaceModel.fromJson(spaceJson))
|
||||
.toList();
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'package:dio/dio.dart';
|
||||
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/pages/roles_and_permission/users_page/add_user_dialog/model/permission_option_model.dart';
|
||||
import 'package:syncrow_web/services/api/http_service.dart';
|
||||
import 'package:syncrow_web/utils/constants/api_const.dart';
|
||||
|
||||
@@ -33,7 +35,7 @@ class UserPermissionApi {
|
||||
return response ?? [];
|
||||
}
|
||||
|
||||
Future sendInviteUser({
|
||||
Future<bool> sendInviteUser({
|
||||
String? firstName,
|
||||
String? lastName,
|
||||
String? email,
|
||||
@@ -42,22 +44,58 @@ class UserPermissionApi {
|
||||
String? roleUuid,
|
||||
List<String>? spaceUuids,
|
||||
}) async {
|
||||
final response = await _httpService.post(
|
||||
path: ApiEndpoints.permission,
|
||||
showServerMessage: true,
|
||||
body: {
|
||||
try {
|
||||
final body = <String, dynamic>{
|
||||
"firstName": firstName,
|
||||
"lastName": lastName,
|
||||
"email": email,
|
||||
"jobTitle": jobTitle,
|
||||
"phoneNumber": phoneNumber,
|
||||
"jobTitle": jobTitle != '' ? jobTitle : " ",
|
||||
"phoneNumber": phoneNumber != '' ? phoneNumber : " ",
|
||||
"roleUuid": roleUuid,
|
||||
"spaceUuids": spaceUuids
|
||||
},
|
||||
expectedResponseModel: (json) {
|
||||
print(json);
|
||||
},
|
||||
);
|
||||
return response ?? [];
|
||||
"projectUuid": "0e62577c-06fa-41b9-8a92-99a21fbaf51c",
|
||||
"spaceUuids": spaceUuids,
|
||||
};
|
||||
final response = await _httpService.post(
|
||||
path: ApiEndpoints.inviteUser,
|
||||
showServerMessage: true,
|
||||
body: jsonEncode(body),
|
||||
expectedResponseModel: (json) {
|
||||
if (json['statusCode'] != 400) {
|
||||
return json["success"];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return response ?? [];
|
||||
} on DioException catch (e) {
|
||||
return false;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> checkEmail(email) async {
|
||||
try {
|
||||
final response = await _httpService.post(
|
||||
path: ApiEndpoints.checkEmail,
|
||||
showServerMessage: true,
|
||||
body: {"email": email},
|
||||
expectedResponseModel: (json) {
|
||||
if (json['statusCode'] != 400) {
|
||||
return json["message"];
|
||||
}
|
||||
},
|
||||
);
|
||||
return response ?? [];
|
||||
} on DioException catch (e) {
|
||||
if (e.response != null) {
|
||||
final errorMessage = e.response?.data['error'];
|
||||
return errorMessage;
|
||||
}
|
||||
} catch (e) {
|
||||
return e.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
|
||||
abstract class ApiEndpoints {
|
||||
static const String projectUuid = "0e62577c-06fa-41b9-8a92-99a21fbaf51c";
|
||||
static String baseUrl = dotenv.env['BASE_URL'] ?? '';
|
||||
static const String signUp = '/authentication/user/signup';
|
||||
static const String login = '/authentication/user/login';
|
||||
@@ -38,23 +39,32 @@ abstract class ApiEndpoints {
|
||||
static const String getDeviceLogs = '/device/report-logs/{uuid}?code={code}';
|
||||
|
||||
// Space Module
|
||||
static const String createSpace = '/communities/{communityId}/spaces';
|
||||
static const String listSpaces = '/communities/{communityId}/spaces';
|
||||
static const String createSpace =
|
||||
'/projects/${projectUuid}/communities/{communityId}/spaces';
|
||||
static const String listSpaces =
|
||||
'/projects/${projectUuid}/communities/{communityId}/spaces';
|
||||
static const String deleteSpace =
|
||||
'/communities/{communityId}/spaces/{spaceId}';
|
||||
'/projects/${projectUuid}/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';
|
||||
'/projects/${projectUuid}/communities/{communityId}/spaces/{spaceId}';
|
||||
static const String getSpace =
|
||||
'/projects/${projectUuid}/communities/{communityId}/spaces/{spaceId}';
|
||||
static const String getSpaceHierarchy =
|
||||
'/projects/${projectUuid}/communities/{communityId}/spaces';
|
||||
|
||||
// Community Module
|
||||
static const String createCommunity = '/communities';
|
||||
static const String getCommunityList = '/communities';
|
||||
static const String getCommunityById = '/communities/{communityId}';
|
||||
static const String updateCommunity = '/communities/{communityId}';
|
||||
static const String deleteCommunity = '/communities/{communityId}';
|
||||
static const String getUserCommunities = '/communities/user/{userUuid}';
|
||||
static const String createUserCommunity = '/communities/user';
|
||||
static const String createCommunity = '/projects/${projectUuid}/communities';
|
||||
static const String getCommunityList = '/projects/${projectUuid}/communities';
|
||||
static const String getCommunityById =
|
||||
'/projects/${projectUuid}/communities/{communityId}';
|
||||
static const String updateCommunity =
|
||||
'/projects/${projectUuid}/communities/{communityId}';
|
||||
static const String deleteCommunity =
|
||||
'/projects/${projectUuid}/communities/{communityId}';
|
||||
static const String getUserCommunities =
|
||||
'/projects/${projectUuid}/communities/user/{userUuid}';
|
||||
static const String createUserCommunity =
|
||||
'/projects/${projectUuid}/communities/user';
|
||||
static const String getDeviceLogsByDate =
|
||||
'/device/report-logs/{uuid}?code={code}&startTime={startTime}&endTime={endTime}';
|
||||
|
||||
@@ -90,5 +100,7 @@ abstract class ApiEndpoints {
|
||||
static const String roleTypes = '/role/types';
|
||||
static const String permission = '/permission/{roleUuid}';
|
||||
static const String inviteUser = '/invite-user';
|
||||
static const String checkEmail = '/invite-user/check-email';
|
||||
// static const String updateAutomation = '/automation/{automationId}';
|
||||
// https://syncrow-dev.azurewebsites.net/invite-user/check-email
|
||||
}
|
||||
|
||||
@@ -394,5 +394,8 @@ class Assets {
|
||||
static const String arrowDown = 'assets/icons/arrow_down.svg';
|
||||
|
||||
static const String userManagement = 'assets/icons/user_management.svg';
|
||||
static const String filterTableIcon = 'assets/icons/filter_table_icon.svg';
|
||||
static const String ZtoAIcon = 'assets/icons/ztoa_icon.png';
|
||||
static const String AtoZIcon = 'assets/icons/atoz_icon.png';
|
||||
}
|
||||
//user_management.svg
|
||||
|
||||
Reference in New Issue
Block a user