mirror of
https://github.com/SyncrowIOT/web.git
synced 2026-10-23 11:47:57 +00:00
user_invite
This commit is contained in:
@@ -95,9 +95,7 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
title: 'Move in',
|
||||
icon: Assets.moveinIcon,
|
||||
active: true,
|
||||
onPress: (context) {
|
||||
context.go(RoutesConst.rolesAndPermissions);
|
||||
},
|
||||
onPress: (context) {},
|
||||
color: ColorsManager.primaryColor,
|
||||
),
|
||||
HomeItemModel(
|
||||
|
||||
@@ -22,9 +22,20 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
on<RoleEvent>(_getRolePermission);
|
||||
on<PermissionEvent>(_getPermissions);
|
||||
on<SearchPermission>(searchRolePermission);
|
||||
on<SendInviteUsers>(_sendInvitUser);
|
||||
on<ValidateBasicsStep>(_validateBasicsStep);
|
||||
on<CheckRoleStepStatus>(isCompleteRoleFun);
|
||||
}
|
||||
void _validateBasicsStep(ValidateBasicsStep event, Emitter<UsersState> emit) {
|
||||
if (formKey.currentState?.validate() ?? false) {
|
||||
emit(const BasicsStepValidState());
|
||||
} else {
|
||||
emit(const BasicsStepInvalidState());
|
||||
}
|
||||
}
|
||||
|
||||
List<RolesUserModel> users = [];
|
||||
String roleSelected = '';
|
||||
|
||||
Future<void> _getUsers(GetUsers event, Emitter<UsersState> emit) async {
|
||||
emit(UsersLoadingState());
|
||||
@@ -106,31 +117,42 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
int numberSpaces = 0;
|
||||
int numberRole = 0;
|
||||
|
||||
isCompleteBasicsFun(CheckStepStatus event, Emitter<UsersState> emit) {
|
||||
// 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;
|
||||
emailController.text.isNotEmpty &&
|
||||
emailRegex.hasMatch(emailController.text);
|
||||
|
||||
emit(ChangeStatusSteps());
|
||||
return isCompleteBasics;
|
||||
return isCompleteBasics!;
|
||||
}
|
||||
|
||||
void isCompleteSpacesFun(
|
||||
CheckSpacesStepStatus event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
try {
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
isCompleteSpaces = selectedIds.isNotEmpty;
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error while retrieving selected IDs: $e'));
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> selectedIds = getSelectedIds(updatedCommunities);
|
||||
isCompleteSpaces = selectedIds.isNotEmpty;
|
||||
emit(ChangeStatusSteps());
|
||||
}
|
||||
|
||||
bool checkRolePermissions() {
|
||||
return true;
|
||||
void isCompleteRoleFun(CheckRoleStepStatus event, Emitter<UsersState> emit) {
|
||||
emit(UsersLoadingState());
|
||||
isCompleteRolePermissions = roleSelected != '';
|
||||
emit(ChangeStatusSteps());
|
||||
}
|
||||
|
||||
Future<List<SpaceModel>> _fetchSpacesForCommunity(
|
||||
@@ -249,6 +271,7 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
emit(UsersLoadingState());
|
||||
permissions = await UserPermissionApi().fetchPermission(
|
||||
event.roleUuid == "" ? roles.first.uuid : event.roleUuid);
|
||||
roleSelected = event.roleUuid!;
|
||||
emit(RolePermissionInitial());
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error loading communities and spaces: $e'));
|
||||
@@ -268,17 +291,22 @@ class UsersBloc extends Bloc<UsersEvent, UsersState> {
|
||||
return anyMatch;
|
||||
}
|
||||
|
||||
_sendInvitUser(List<PermissionOption> nodes, String searchTerm) async {
|
||||
emit(UsersLoadingState());
|
||||
await UserPermissionApi().sendInviteUser(
|
||||
email: emailController.text,
|
||||
firstName: firstNameController.text,
|
||||
jobTitle: jobTitleController.text,
|
||||
lastName: lastNameController.text,
|
||||
phoneNumber: phoneController.text,
|
||||
roleUuid: '',
|
||||
spaceUuids: selectedIds);
|
||||
emit(RolePermissionInitial());
|
||||
_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);
|
||||
emit(SaveState());
|
||||
} catch (e) {
|
||||
emit(ErrorState('Error: $e'));
|
||||
}
|
||||
}
|
||||
|
||||
void searchRolePermission(SearchPermission event, Emitter<UsersState> emit) {
|
||||
|
||||
@@ -12,12 +12,25 @@ class GetUsers extends UsersEvent {
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class SendInviteUsers extends UsersEvent {
|
||||
const SendInviteUsers();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class CheckSpacesStepStatus extends UsersEvent {
|
||||
const CheckSpacesStepStatus();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
class CheckRoleStepStatus extends UsersEvent {
|
||||
const CheckRoleStepStatus();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
|
||||
class LoadCommunityAndSpacesEvent extends UsersEvent {
|
||||
const LoadCommunityAndSpacesEvent();
|
||||
@override
|
||||
@@ -85,3 +98,9 @@ class SelecteId extends UsersEvent {
|
||||
@override
|
||||
List<Object?> get props => [nodes];
|
||||
}
|
||||
|
||||
class ValidateBasicsStep extends UsersEvent {
|
||||
const ValidateBasicsStep();
|
||||
@override
|
||||
List<Object?> get props => [];
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ final class UsersInitial extends UsersState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class RolePermissionInitial extends UsersState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
@@ -24,6 +25,11 @@ final class UsersLoadingState extends UsersState {
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class SaveState extends UsersState {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
final class UsersLoadedState extends UsersState {
|
||||
List<RolesUserModel> users = [];
|
||||
UsersLoadedState({required this.users});
|
||||
@@ -59,3 +65,15 @@ final class ChangeTapStatus extends UsersState {
|
||||
@override
|
||||
List<Object> get props => [select];
|
||||
}
|
||||
|
||||
final class BasicsStepValidState extends UsersState {
|
||||
const BasicsStepValidState();
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
class BasicsStepInvalidState extends UsersState {
|
||||
const BasicsStepInvalidState();
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
|
||||
@@ -88,37 +88,6 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
child: _getFormContent(),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
ElevatedButton(
|
||||
onPressed: () {
|
||||
if (_blocRole.formKey.currentState
|
||||
?.validate() ??
|
||||
false) {
|
||||
// Proceed to next step or finish
|
||||
setState(() {
|
||||
if (currentStep < 3) {
|
||||
currentStep++;
|
||||
} else {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
child: Text(currentStep < 3
|
||||
? "Next"
|
||||
: "Finish"),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
@@ -126,6 +95,53 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
],
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
InkWell(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (currentStep < 3) {
|
||||
currentStep++;
|
||||
if (currentStep == 2) {
|
||||
_blocRole.add(const CheckStepStatus());
|
||||
} else if (currentStep == 3) {
|
||||
_blocRole
|
||||
.add(const CheckSpacesStepStatus());
|
||||
_blocRole
|
||||
.add(const CheckSpacesStepStatus());
|
||||
} else {
|
||||
_blocRole.add(const SendInviteUsers());
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
child: Text(
|
||||
currentStep < 3 ? "Next" : "Save",
|
||||
style: TextStyle(
|
||||
color: (_blocRole.isCompleteSpaces == false ||
|
||||
_blocRole.isCompleteBasics ==
|
||||
false ||
|
||||
_blocRole
|
||||
.isCompleteRolePermissions ==
|
||||
false) &&
|
||||
currentStep == 3
|
||||
? ColorsManager.grayColor
|
||||
: ColorsManager.secondaryColor),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
));
|
||||
@@ -209,8 +225,12 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
bloc.add(const CheckSpacesStepStatus());
|
||||
currentStep = step;
|
||||
});
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
bloc.add(const ValidateBasicsStep());
|
||||
});
|
||||
},
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
@@ -270,6 +290,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
setState(() {
|
||||
currentStep = step;
|
||||
bloc.add(const CheckSpacesStepStatus());
|
||||
bloc.add(const CheckStepStatus());
|
||||
});
|
||||
},
|
||||
child: Column(
|
||||
|
||||
@@ -14,6 +14,9 @@ class BasicsView extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
return BlocBuilder<UsersBloc, UsersState>(builder: (context, state) {
|
||||
final _blocRole = BlocProvider.of<UsersBloc>(context);
|
||||
if (state is BasicsStepInvalidState) {
|
||||
_blocRole.formKey.currentState?.validate();
|
||||
}
|
||||
return Form(
|
||||
key: _blocRole.formKey,
|
||||
child: ListView(
|
||||
@@ -184,7 +187,14 @@ class BasicsView extends StatelessWidget {
|
||||
),
|
||||
validator: (value) {
|
||||
if (value == null || value.isEmpty) {
|
||||
return 'Enter last name';
|
||||
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';
|
||||
}
|
||||
return null;
|
||||
},
|
||||
@@ -213,49 +223,6 @@ class BasicsView extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
)),
|
||||
// InternationalPhoneNumberInput(
|
||||
// spaceBetweenSelectorAndTextField: 50,
|
||||
// initialValue: PhoneNumber(isoCode: 'AE'),
|
||||
// inputDecoration: inputTextFormDeco(
|
||||
// hintText: "x xxx xxxx",
|
||||
// ).copyWith(
|
||||
// hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||
// fontWeight: FontWeight.w400,
|
||||
// fontSize: 12,
|
||||
// color: ColorsManager.textGray),
|
||||
// ),
|
||||
// onInputChanged: (PhoneNumber number) {
|
||||
// print(number.phoneNumber);
|
||||
// },
|
||||
// onInputValidated: (bool value) {
|
||||
// print(value);
|
||||
// },
|
||||
// selectorConfig: const SelectorConfig(
|
||||
// selectorType: PhoneInputSelectorType.BOTTOM_SHEET,
|
||||
// useBottomSheetSafeArea: true,
|
||||
// leadingPadding: 15,
|
||||
// trailingSpace: false,
|
||||
// setSelectorButtonAsPrefixIcon: true),
|
||||
// ignoreBlank: true,
|
||||
// autoValidateMode: AutovalidateMode.disabled,
|
||||
|
||||
// selectorTextStyle:
|
||||
// TextStyle(color: ColorsManager.blackColor),
|
||||
// // initialValue: number,
|
||||
// // textFieldController: controller,
|
||||
// formatInput: true,
|
||||
// keyboardType: const TextInputType.numberWithOptions(
|
||||
// signed: true, decimal: true),
|
||||
// // inputBorder: OutlineInputBorder(
|
||||
// // borderSide:
|
||||
// // BorderSide(color: Colors.black,)),
|
||||
// onSaved: (PhoneNumber number) {
|
||||
// print('On Saved: $number');
|
||||
// },
|
||||
// textStyle:
|
||||
// const TextStyle(color: ColorsManager.blackColor),
|
||||
// ),
|
||||
|
||||
IntlPhoneField(
|
||||
pickerDialogStyle: PickerDialogStyle(),
|
||||
dropdownIconPosition: IconPosition.leading,
|
||||
@@ -270,36 +237,12 @@ class BasicsView extends StatelessWidget {
|
||||
fontSize: 12,
|
||||
color: ColorsManager.textGray),
|
||||
),
|
||||
|
||||
initialCountryCode: 'AE',
|
||||
style: TextStyle(color: Colors.black),
|
||||
onChanged: (phone) {
|
||||
print(phone.completeNumber);
|
||||
},
|
||||
)
|
||||
|
||||
// Padding(
|
||||
// padding: const EdgeInsets.all(8.0),
|
||||
// child: TextFormField(
|
||||
// style: const TextStyle(color: Colors.black),
|
||||
// controller: _blocRole.phoneController,
|
||||
// decoration: inputTextFormDeco(
|
||||
// hintText: "05x xxx xxxx",
|
||||
// ).copyWith(
|
||||
// hintStyle: context.textTheme.bodyMedium?.copyWith(
|
||||
// fontWeight: FontWeight.w400,
|
||||
// fontSize: 12,
|
||||
// color: ColorsManager.textGray),
|
||||
// ),
|
||||
// validator: (value) {
|
||||
// if (value == null || value.isEmpty) {
|
||||
// return 'Please enter a phone number';
|
||||
// }
|
||||
// return null;
|
||||
// },
|
||||
// keyboardType: TextInputType.phone,
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -71,6 +71,7 @@ class RolesAndPermission extends StatelessWidget {
|
||||
const TextStyle(color: Colors.black),
|
||||
controller: _blocRole.firstNameController,
|
||||
onChanged: (value) {
|
||||
|
||||
_blocRole.add(SearchPermission(
|
||||
nodes: _blocRole.permissions,
|
||||
searchTerm: value));
|
||||
|
||||
@@ -389,10 +389,10 @@ class Assets {
|
||||
'assets/icons/current_process_icon.svg';
|
||||
static const String uncomplete_ProcessIcon =
|
||||
'assets/icons/uncompleate_process_icon.svg';
|
||||
static const String wrongProcessIcon =
|
||||
'assets/icons/wrong_process_icon.svg';
|
||||
static const String arrowForward =
|
||||
'assets/icons/arrow_forward.svg';
|
||||
static const String arrowDown =
|
||||
'assets/icons/arrow_down.svg';
|
||||
static const String wrongProcessIcon = 'assets/icons/wrong_process_icon.svg';
|
||||
static const String arrowForward = 'assets/icons/arrow_forward.svg';
|
||||
static const String arrowDown = 'assets/icons/arrow_down.svg';
|
||||
|
||||
static const String userManagement = 'assets/icons/user_management.svg';
|
||||
}
|
||||
//user_management.svg
|
||||
|
||||
@@ -53,7 +53,8 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
}
|
||||
|
||||
Future<void> _showPopupMenu(BuildContext context) async {
|
||||
final RenderBox overlay = Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
final RenderBox overlay =
|
||||
Overlay.of(context).context.findRenderObject() as RenderBox;
|
||||
final RelativeRect position = RelativeRect.fromRect(
|
||||
Rect.fromLTRB(
|
||||
overlay.size.width,
|
||||
@@ -86,11 +87,13 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: () {},
|
||||
onTap: () {
|
||||
context.go(RoutesConst.rolesAndPermissions);
|
||||
},
|
||||
child: ListTile(
|
||||
leading: SvgPicture.asset(Assets.settings),
|
||||
leading: SvgPicture.asset(Assets.userManagement),
|
||||
title: Text(
|
||||
"Settings",
|
||||
"User Management",
|
||||
style: context.textTheme.bodyMedium,
|
||||
),
|
||||
),
|
||||
@@ -107,7 +110,8 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
height: 200,
|
||||
width: 400,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 24, left: 24, right: 24),
|
||||
padding:
|
||||
const EdgeInsets.only(top: 24, left: 24, right: 24),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
@@ -120,7 +124,10 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Text(
|
||||
'Log out of your Syncrow account',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black,
|
||||
@@ -151,11 +158,15 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'${widget.user?.firstName ?? ''} ${widget.user?.lastName}',
|
||||
style: Theme.of(context).textTheme.titleMedium!.copyWith(
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleMedium!
|
||||
.copyWith(
|
||||
color: Colors.black,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
@@ -163,7 +174,10 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
),
|
||||
Text(
|
||||
' ${widget.user?.email}',
|
||||
style: Theme.of(context).textTheme.bodySmall!.copyWith(
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodySmall!
|
||||
.copyWith(
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
@@ -189,7 +203,10 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
elevation: 1,
|
||||
child: Text(
|
||||
'Cancel',
|
||||
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
),
|
||||
@@ -211,8 +228,10 @@ class _UserDropdownMenuState extends State<UserDropdownMenu> {
|
||||
elevation: 1,
|
||||
child: Text(
|
||||
'Logout',
|
||||
style:
|
||||
Theme.of(context).textTheme.bodyMedium!.copyWith(fontSize: 12, color: Colors.white),
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.copyWith(fontSize: 12, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user