fixes filter and table view and add user dialog

This commit is contained in:
mohammad
2025-01-12 15:32:03 +03:00
parent f8efc07fdb
commit 15023e5882
10 changed files with 496 additions and 488 deletions

View File

@ -42,7 +42,7 @@ class RolesUserModel {
invitedBy: invitedBy:
json['invitedBy'].toString().toLowerCase().replaceAll("_", " "), json['invitedBy'].toString().toLowerCase().replaceAll("_", " "),
phoneNumber: json['phoneNumber'], phoneNumber: json['phoneNumber'],
jobTitle: json['jobTitle'].toString(), jobTitle: json['jobTitle'] ?? "-",
createdDate: json['createdDate'], createdDate: json['createdDate'],
createdTime: json['createdTime'], createdTime: json['createdTime'],
); );

View File

@ -114,7 +114,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
currentStep++; currentStep++;
if (currentStep == 2) { if (currentStep == 2) {
_blocRole.add( _blocRole.add(
CheckStepStatus(isEditUser: false)); const CheckStepStatus(isEditUser: false));
} else if (currentStep == 3) { } else if (currentStep == 3) {
_blocRole _blocRole
.add(const CheckSpacesStepStatus()); .add(const CheckSpacesStepStatus());
@ -151,7 +151,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
Widget _getFormContent() { Widget _getFormContent() {
switch (currentStep) { switch (currentStep) {
case 1: case 1:
return BasicsView( return const BasicsView(
userId: '', userId: '',
); );
case 2: case 2:
@ -172,7 +172,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
bloc.add(const CheckSpacesStepStatus()); bloc.add(const CheckSpacesStepStatus());
currentStep = step; currentStep = step;
Future.delayed(const Duration(milliseconds: 500), () { Future.delayed(const Duration(milliseconds: 500), () {
bloc.add(ValidateBasicsStep()); bloc.add(const ValidateBasicsStep());
}); });
}); });

View File

@ -11,7 +11,14 @@ class DeleteUserDialog extends StatefulWidget {
} }
class _DeleteUserDialogState extends State<DeleteUserDialog> { class _DeleteUserDialogState extends State<DeleteUserDialog> {
int currentStep = 1; bool isLoading = false;
bool _isDisposed = false;
@override
void dispose() {
_isDisposed = true;
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -56,7 +63,7 @@ class _DeleteUserDialogState extends State<DeleteUserDialog> {
Expanded( Expanded(
child: InkWell( child: InkWell(
onTap: () { onTap: () {
Navigator.of(context).pop(true); Navigator.of(context).pop(false); // Return false if canceled
}, },
child: Container( child: Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
@ -76,7 +83,26 @@ class _DeleteUserDialogState extends State<DeleteUserDialog> {
)), )),
Expanded( Expanded(
child: InkWell( child: InkWell(
onTap: widget.onTapDelete, onTap: isLoading
? null
: () async {
setState(() {
isLoading = true;
});
try {
if (widget.onTapDelete != null) {
await widget.onTapDelete!();
}
} finally {
if (!_isDisposed) {
setState(() {
isLoading = false;
});
}
}
Navigator.of(context).pop(true);
},
child: Container( child: Container(
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
decoration: const BoxDecoration( decoration: const BoxDecoration(
@ -91,8 +117,17 @@ class _DeleteUserDialogState extends State<DeleteUserDialog> {
), ),
), ),
), ),
child: const Center( child: Center(
child: Text( child: isLoading
? const SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
color: ColorsManager.red,
strokeWidth: 2.0,
),
)
: const Text(
'Delete', 'Delete',
style: TextStyle( style: TextStyle(
color: ColorsManager.red, color: ColorsManager.red,

View File

@ -5,94 +5,91 @@ import 'package:syncrow_web/utils/style.dart';
Future<void> showPopUpFilterMenu({ Future<void> showPopUpFilterMenu({
required BuildContext context, required BuildContext context,
Function()? onSortAtoZ, required Function(String value)? onSortAtoZ, // Accept a parameter
Function()? onSortZtoA, required Function(String value)? onSortZtoA, // Accept a parameter
Function()? cancelButton, Function()? cancelButton,
required Map<String, bool> checkboxStates, required Map<String, bool> checkboxStates,
required RelativeRect position, required RelativeRect position,
Function()? onOkPressed, Function()? onOkPressed,
List<String>? list, List<String>? list,
String? isSelected,
}) async { }) async {
await showMenu( await showMenu(
context: context, context: context,
position: position, position: position,
color: ColorsManager.whiteColors, color: ColorsManager.whiteColors,
shape: const RoundedRectangleBorder( shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10)), borderRadius: BorderRadius.all(Radius.circular(10)),
), ),
items: <PopupMenuEntry>[ items: <PopupMenuEntry>[
PopupMenuItem( PopupMenuItem(
onTap: onSortAtoZ, enabled: false,
child: StatefulBuilder(
builder: (context, setState) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
child: ListTile( child: ListTile(
onTap: () {
setState(() {
if (isSelected == 'Asc') {
isSelected = null;
onSortAtoZ?.call('');
} else {
onSortAtoZ?.call('Asc');
isSelected = 'Asc';
}
});
},
leading: Image.asset( leading: Image.asset(
Assets.AtoZIcon, Assets.AtoZIcon,
width: 25, width: 25,
), ),
title: const Text( title: Text(
"Sort A to Z", "Sort A to Z",
style: TextStyle(color: Colors.blueGrey), style: TextStyle(
color: isSelected == "Asc"
? ColorsManager.blackColor
: ColorsManager.grayColor),
), ),
), ),
), ),
PopupMenuItem( ListTile(
onTap: onSortZtoA, onTap: () {
child: ListTile( setState(() {
if (isSelected == 'Desc') {
isSelected = null;
onSortZtoA?.call('');
} else {
onSortZtoA?.call('Desc');
isSelected = 'Desc';
}
});
},
leading: Image.asset( leading: Image.asset(
Assets.ZtoAIcon, Assets.ZtoAIcon,
width: 25, width: 25,
), ),
title: const Text( title: Text(
"Sort Z to A", "Sort Z to A",
style: TextStyle(color: Colors.blueGrey), style: TextStyle(
color: isSelected == "Desc"
? ColorsManager.blackColor
: ColorsManager.grayColor),
), ),
), ),
), const Divider(),
const PopupMenuDivider(), const Text(
const PopupMenuItem(
child: Text(
"Filter by Status", "Filter by Status",
style: TextStyle(fontWeight: FontWeight.bold), style: TextStyle(fontWeight: FontWeight.bold),
)
// Container(
// decoration: containerDecoration.copyWith(
// boxShadow: [],
// borderRadius: const BorderRadius.only(
// topLeft: Radius.circular(10), topRight: Radius.circular(10))),
// child: Padding(
// padding: const EdgeInsets.all(8.0),
// child: TextFormField(
// onChanged: onTextFieldChanged,
// style: const TextStyle(color: Colors.black),
// decoration: textBoxDecoration(radios: 15)!.copyWith(
// fillColor: ColorsManager.whiteColors,
// errorStyle: const TextStyle(height: 0),
// hintStyle: context.textTheme.titleSmall?.copyWith(
// color: Colors.grey,
// fontSize: 12,
// ),
// hintText: 'Search',
// suffixIcon: SizedBox(
// child: SvgPicture.asset(
// Assets.searchIconUser,
// fit: BoxFit.none,
// ),
// ),
// ),
// // "Filter by Status",
// // style: TextStyle(fontWeight: FontWeight.bold),
// ),
// ),
// ),
), ),
PopupMenuItem( Container(
child: Container(
decoration: containerDecoration.copyWith( decoration: containerDecoration.copyWith(
boxShadow: [], boxShadow: [],
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10),
bottomLeft: Radius.circular(10), bottomLeft: Radius.circular(10),
bottomRight: Radius.circular(10))), bottomRight: Radius.circular(10))),
padding: const EdgeInsets.all(10), padding: const EdgeInsets.all(10),
@ -105,22 +102,33 @@ Future<void> showPopUpFilterMenu({
itemCount: list?.length ?? 0, itemCount: list?.length ?? 0,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final item = list![index]; final item = list![index];
return CheckboxListTile( return Row(
dense: true, children: [
title: Text(item), Checkbox(
value: checkboxStates[item], value: checkboxStates[item],
onChanged: (bool? newValue) { onChanged: (bool? newValue) {
checkboxStates[item] = newValue ?? false; checkboxStates[item] = newValue ?? false;
(context as Element).markNeedsBuild(); (context as Element).markNeedsBuild();
}, },
),
Text(
item,
style: TextStyle(color: ColorsManager.grayColor),
),
],
); );
}, },
), ),
), ),
), ),
const SizedBox(
height: 10,
), ),
PopupMenuItem( const Divider(),
child: Row( const SizedBox(
height: 10,
),
Row(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
@ -141,6 +149,13 @@ Future<void> showPopUpFilterMenu({
), ),
], ],
), ),
const SizedBox(
height: 10,
),
],
);
},
),
), ),
], ],
); );

View File

@ -52,14 +52,16 @@ class _RoleDropdownState extends State<RoleDropdown> {
SizedBox( SizedBox(
child: DropdownButtonFormField<String>( child: DropdownButtonFormField<String>(
dropdownColor: ColorsManager.whiteColors, dropdownColor: ColorsManager.whiteColors,
alignment: Alignment.center, // alignment: Alignment.,
focusColor: Colors.white, focusColor: Colors.white,
autofocus: true, autofocus: true,
value: selectedRole.isNotEmpty ? selectedRole : null, value: selectedRole.isNotEmpty ? selectedRole : null,
items: widget.bloc!.roles.map((role) { items: widget.bloc!.roles.map((role) {
return DropdownMenuItem<String>( return DropdownMenuItem<String>(
value: role.uuid, value: role.uuid,
child: Text(role.type), child: Text(
' ${role.type[0].toUpperCase()}${role.type.substring(1)}',
),
); );
}).toList(), }).toList(),
onChanged: (value) { onChanged: (value) {

View File

@ -133,7 +133,10 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
} else { } else {
emit(UsersLoadingState()); emit(UsersLoadingState());
currentSortOrder = "Asc"; currentSortOrder = "Asc";
users.sort((a, b) => a.firstName!.compareTo(b.firstName!)); users.sort((a, b) => a.firstName
.toString()
.toLowerCase()
.compareTo(b.firstName.toString().toLowerCase()));
emit(UsersLoadedState(users: users)); emit(UsersLoadedState(users: users));
} }
} }
@ -164,6 +167,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
emit(UsersLoadedState(users: users)); emit(UsersLoadedState(users: users));
} else { } else {
emit(UsersLoadingState()); emit(UsersLoadingState());
currentSortOrder = "NewestToOldest";
users.sort((a, b) { users.sort((a, b) {
final dateA = _parseDateTime(a.createdDate); final dateA = _parseDateTime(a.createdDate);
final dateB = _parseDateTime(b.createdDate); final dateB = _parseDateTime(b.createdDate);
@ -188,6 +192,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
final dateB = _parseDateTime(b.createdDate); final dateB = _parseDateTime(b.createdDate);
return dateA.compareTo(dateB); return dateA.compareTo(dateB);
}); });
currentSortOrder = "OldestToNewest";
emit(UsersLoadedState(users: users)); emit(UsersLoadedState(users: users));
} }
} }
@ -256,49 +261,96 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
void _filterUsersByRole( void _filterUsersByRole(
FilterUsersByRoleEvent event, Emitter<UserTableState> emit) { FilterUsersByRoleEvent event, Emitter<UserTableState> emit) {
selectedRoles = event.selectedRoles.toSet(); selectedRoles = event.selectedRoles!.toSet();
final filteredUsers = initialUsers.where((user) { final filteredUsers = initialUsers.where((user) {
if (selectedRoles.isEmpty) return true; if (selectedRoles.isEmpty) return true;
return selectedRoles.contains(user.roleType); return selectedRoles.contains(user.roleType);
}).toList(); }).toList();
if (event.sortOrder == "Asc") {
currentSortOrder = "Asc";
filteredUsers.sort((a, b) => a.firstName
.toString()
.toLowerCase()
.compareTo(b.firstName.toString().toLowerCase()));
} else if (event.sortOrder == "Desc") {
currentSortOrder = "Desc";
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
} else {
currentSortOrder = "";
}
emit(UsersLoadedState(users: filteredUsers)); emit(UsersLoadedState(users: filteredUsers));
} }
void _filterUsersByJobTitle( void _filterUsersByJobTitle(
FilterUsersByJobEvent event, Emitter<UserTableState> emit) { FilterUsersByJobEvent event, Emitter<UserTableState> emit) {
selectedJobTitles = event.selectedJob.toSet(); selectedJobTitles = event.selectedJob!.toSet();
emit(UsersLoadingState());
final filteredUsers = initialUsers.where((user) { final filteredUsers = initialUsers.where((user) {
if (selectedJobTitles.isEmpty) return true; if (selectedJobTitles.isEmpty) return true;
return selectedJobTitles.contains(user.jobTitle); return selectedJobTitles.contains(user.jobTitle);
}).toList(); }).toList();
if (event.sortOrder == "Asc") {
currentSortOrder = "Asc";
filteredUsers.sort((a, b) => a.firstName
.toString()
.toLowerCase()
.compareTo(b.firstName.toString().toLowerCase()));
} else if (event.sortOrder == "Desc") {
currentSortOrder = "Desc";
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
} else {
currentSortOrder = "";
}
emit(UsersLoadedState(users: filteredUsers)); emit(UsersLoadedState(users: filteredUsers));
} }
void _filterUsersByCreated( void _filterUsersByCreated(
FilterUsersByCreatedEvent event, Emitter<UserTableState> emit) { FilterUsersByCreatedEvent event, Emitter<UserTableState> emit) {
selectedCreatedBy = event.selectedCreatedBy.toSet(); selectedCreatedBy = event.selectedCreatedBy!.toSet();
final filteredUsers = initialUsers.where((user) { final filteredUsers = initialUsers.where((user) {
if (selectedCreatedBy.isEmpty) return true; if (selectedCreatedBy.isEmpty) return true;
return selectedCreatedBy.contains(user.invitedBy); return selectedCreatedBy.contains(user.invitedBy);
}).toList(); }).toList();
if (event.sortOrder == "Asc") {
currentSortOrder = "Asc";
filteredUsers.sort((a, b) => a.firstName
.toString()
.toLowerCase()
.compareTo(b.firstName.toString().toLowerCase()));
} else if (event.sortOrder == "Desc") {
currentSortOrder = "Desc";
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
} else {
currentSortOrder = "";
}
emit(UsersLoadedState(users: filteredUsers)); emit(UsersLoadedState(users: filteredUsers));
} }
void _filterUserStatus( void _filterUserStatus(
FilterUsersByDeActevateEvent event, Emitter<UserTableState> emit) { FilterUsersByDeActevateEvent event, Emitter<UserTableState> emit) {
selectedStatuses = event.selectedActivate.toSet(); selectedStatuses = event.selectedActivate!.toSet();
final filteredUsers = initialUsers.where((user) { final filteredUsers = initialUsers.where((user) {
if (selectedStatuses.isEmpty) return true; if (selectedStatuses.isEmpty) return true;
return selectedStatuses.contains(user.status); return selectedStatuses.contains(user.status);
}).toList(); }).toList();
if (event.sortOrder == "Asc") {
currentSortOrder = "Asc";
filteredUsers.sort((a, b) => a.firstName
.toString()
.toLowerCase()
.compareTo(b.firstName.toString().toLowerCase()));
} else if (event.sortOrder == "Desc") {
currentSortOrder = "Desc";
filteredUsers.sort((a, b) => b.firstName!.compareTo(a.firstName!));
} else {
currentSortOrder = "";
}
emit(UsersLoadedState(users: filteredUsers)); emit(UsersLoadedState(users: filteredUsers));
} }

View File

@ -89,35 +89,36 @@ class DeleteUserEvent extends UserTableEvent {
} }
class FilterUsersByRoleEvent extends UserTableEvent { class FilterUsersByRoleEvent extends UserTableEvent {
final List<String> selectedRoles; final List<String>? selectedRoles;
final String? sortOrder;
FilterUsersByRoleEvent(this.selectedRoles); const FilterUsersByRoleEvent({this.selectedRoles, this.sortOrder});
@override List<Object?> get props => [selectedRoles, sortOrder];
List<Object?> get props => [selectedRoles];
} }
class FilterUsersByJobEvent extends UserTableEvent { class FilterUsersByJobEvent extends UserTableEvent {
final List<String> selectedJob; final List<String>? selectedJob;
final String? sortOrder;
FilterUsersByJobEvent(this.selectedJob); const FilterUsersByJobEvent({this.selectedJob, this.sortOrder});
@override List<Object?> get props => [selectedJob, sortOrder];
List<Object?> get props => [selectedJob];
} }
class FilterUsersByCreatedEvent extends UserTableEvent { class FilterUsersByCreatedEvent extends UserTableEvent {
final List<String> selectedCreatedBy; final List<String>? selectedCreatedBy;
FilterUsersByCreatedEvent(this.selectedCreatedBy); final String? sortOrder;
@override
List<Object?> get props => [selectedCreatedBy]; const FilterUsersByCreatedEvent({this.selectedCreatedBy, this.sortOrder});
List<Object?> get props => [selectedCreatedBy, sortOrder];
} }
class FilterUsersByDeActevateEvent extends UserTableEvent { class FilterUsersByDeActevateEvent extends UserTableEvent {
final List<String> selectedActivate; final List<String>? selectedActivate;
final String? sortOrder;
FilterUsersByDeActevateEvent(this.selectedActivate); const FilterUsersByDeActevateEvent({this.selectedActivate, this.sortOrder});
@override List<Object?> get props => [selectedActivate, sortOrder];
List<Object?> get props => [selectedActivate];
} }
class FilterOptionsEvent extends UserTableEvent { class FilterOptionsEvent extends UserTableEvent {

View File

@ -19,19 +19,13 @@ class DynamicTableScreen extends StatefulWidget {
class _DynamicTableScreenState extends State<DynamicTableScreen> class _DynamicTableScreenState extends State<DynamicTableScreen>
with WidgetsBindingObserver { with WidgetsBindingObserver {
late List<double> columnWidths; late List<double> columnWidths;
late double totalWidth;
// @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 @override
void initState() { void initState() {
super.initState(); super.initState();
setState(() {
columnWidths = List<double>.filled(widget.titles.length, 150.0); columnWidths = List<double>.filled(widget.titles.length, 150.0);
}); totalWidth = columnWidths.reduce((a, b) => a + b);
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
} }
@ -44,7 +38,6 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
@override @override
void didChangeMetrics() { void didChangeMetrics() {
super.didChangeMetrics(); super.didChangeMetrics();
// Screen size might have changed
final newScreenWidth = MediaQuery.of(context).size.width; final newScreenWidth = MediaQuery.of(context).size.width;
setState(() { setState(() {
columnWidths = List<double>.generate(widget.titles.length, (index) { columnWidths = List<double>.generate(widget.titles.length, (index) {
@ -64,8 +57,6 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width; 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)) { if (columnWidths.every((width) => width == 120.0)) {
columnWidths = List<double>.generate(widget.titles.length, (index) { columnWidths = List<double>.generate(widget.titles.length, (index) {
if (index == 1) { if (index == 1) {
@ -77,8 +68,7 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
}); });
setState(() {}); setState(() {});
} }
return Container( return SingleChildScrollView(
child: SingleChildScrollView(
clipBehavior: Clip.none, clipBehavior: Clip.none,
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
child: Container( child: Container(
@ -88,9 +78,8 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
child: FittedBox( child: FittedBox(
child: Column( child: Column(
children: [ children: [
// Header Row with Resizable Columns
Container( Container(
width: MediaQuery.of(context).size.width, width: totalWidth,
decoration: containerDecoration.copyWith( decoration: containerDecoration.copyWith(
color: ColorsManager.circleRolesBackground, color: ColorsManager.circleRolesBackground,
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
@ -106,8 +95,7 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
padding: const EdgeInsets.only(left: 5, right: 5), padding: const EdgeInsets.only(left: 5, right: 5),
width: columnWidths[index], width: columnWidths[index],
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.spaceBetween,
MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
SizedBox( SizedBox(
@ -146,21 +134,20 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
GestureDetector( GestureDetector(
onHorizontalDragUpdate: (details) { onHorizontalDragUpdate: (details) {
setState(() { setState(() {
columnWidths[index] = (columnWidths[index] + columnWidths[index] =
details.delta.dx) (columnWidths[index] + details.delta.dx)
.clamp( .clamp(150.0, 300.0);
150.0, 300.0); // Minimum & Maximum size totalWidth = columnWidths.reduce((a, b) => a + b);
}); });
}, },
child: MouseRegion( child: MouseRegion(
cursor: SystemMouseCursors cursor: SystemMouseCursors.resizeColumn,
.resizeColumn, // Set the cursor to resize
child: Container( child: Container(
color: Colors.green, color: Colors.green,
child: Container( child: Container(
color: ColorsManager.boxDivider, color: ColorsManager.boxDivider,
width: 1, width: 1,
height: 50, // Height of the header cell height: 50,
), ),
), ),
), ),
@ -170,12 +157,9 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
}), }),
), ),
), ),
// Data Rows with Dividers
widget.rows.isEmpty widget.rows.isEmpty
? Container( ? SizedBox(
child: SizedBox(
height: MediaQuery.of(context).size.height / 2, height: MediaQuery.of(context).size.height / 2,
child: Container(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
@ -197,13 +181,10 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
), ),
], ],
), ),
),
),
) )
: Center( : Center(
child: Container( child: Container(
// height: MediaQuery.of(context).size.height * 0.59, width: totalWidth,
width: MediaQuery.of(context).size.width,
decoration: containerDecoration.copyWith( decoration: containerDecoration.copyWith(
color: ColorsManager.whiteColors, color: ColorsManager.whiteColors,
borderRadius: const BorderRadius.only( borderRadius: const BorderRadius.only(
@ -214,8 +195,7 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
shrinkWrap: true, shrinkWrap: true,
itemCount: widget.rows.length, itemCount: widget.rows.length,
itemBuilder: (context, rowIndex) { itemBuilder: (context, rowIndex) {
if (columnWidths if (columnWidths.every((width) => width == 120.0)) {
.every((width) => width == 120.0)) {
columnWidths = List<double>.generate( columnWidths = List<double>.generate(
widget.titles.length, (index) { widget.titles.length, (index) {
if (index == 1) { if (index == 1) {
@ -233,10 +213,7 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
Container( Container(
child: Padding( child: Padding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: 5, left: 5, top: 10, right: 5, bottom: 10),
top: 10,
right: 5,
bottom: 10),
child: Row( child: Row(
children: children:
List.generate(row.length, (index) { List.generate(row.length, (index) {
@ -278,79 +255,6 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
), ),
), ),
), ),
),
); );
} }
} }
// 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(),
// ],
// ),
// ),
// ),
// );
// }

View File

@ -107,7 +107,6 @@ class UsersPage extends StatelessWidget {
builder: (context, state) { builder: (context, state) {
final screenSize = MediaQuery.of(context).size; final screenSize = MediaQuery.of(context).size;
final _blocRole = BlocProvider.of<UserTableBloc>(context); final _blocRole = BlocProvider.of<UserTableBloc>(context);
if (state is UsersLoadingState) { if (state is UsersLoadingState) {
_blocRole.add(ChangePage(_blocRole.currentPage)); _blocRole.add(ChangePage(_blocRole.currentPage));
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
@ -189,8 +188,6 @@ class UsersPage extends StatelessWidget {
const SizedBox(height: 25), const SizedBox(height: 25),
DynamicTableScreen( DynamicTableScreen(
onFilter: (columnIndex) { onFilter: (columnIndex) {
_blocRole.add(FilterClearEvent());
if (columnIndex == 0) { if (columnIndex == 0) {
showNameMenu( showNameMenu(
context: context, context: context,
@ -210,11 +207,12 @@ class UsersPage extends StatelessWidget {
if (columnIndex == 2) { if (columnIndex == 2) {
final Map<String, bool> checkboxStates = { final Map<String, bool> checkboxStates = {
for (var item in _blocRole.jobTitle) for (var item in _blocRole.jobTitle)
item: false, // Initialize with false item: _blocRole.selectedJobTitles.contains(item),
}; };
final RenderBox overlay = Overlay.of(context) final RenderBox overlay = Overlay.of(context)
.context .context
.findRenderObject() as RenderBox; .findRenderObject() as RenderBox;
showPopUpFilterMenu( showPopUpFilterMenu(
position: RelativeRect.fromLTRB( position: RelativeRect.fromLTRB(
overlay.size.width / 4, overlay.size.width / 4,
@ -225,26 +223,28 @@ class UsersPage extends StatelessWidget {
list: _blocRole.jobTitle, list: _blocRole.jobTitle,
context: context, context: context,
checkboxStates: checkboxStates, checkboxStates: checkboxStates,
isSelected: _blocRole.currentSortOrder,
onOkPressed: () { onOkPressed: () {
_blocRole.add(FilterClearEvent());
final selectedItems = checkboxStates.entries final selectedItems = checkboxStates.entries
.where((entry) => entry.value) .where((entry) => entry.value)
.map((entry) => entry.key) .map((entry) => entry.key)
.toList(); .toList();
Navigator.of(context).pop(); Navigator.of(context).pop();
_blocRole.add(FilterUsersByJobEvent(selectedItems)); _blocRole.add(FilterUsersByJobEvent(
selectedJob: selectedItems,
sortOrder: _blocRole.currentSortOrder,
));
}, },
onSortAtoZ: () { onSortAtoZ: (v) {
context _blocRole.currentSortOrder = v;
.read<UserTableBloc>()
.add(const SortUsersByNameAsc());
}, },
onSortZtoA: () { onSortZtoA: (v) {
context _blocRole.currentSortOrder = v;
.read<UserTableBloc>()
.add(const SortUsersByNameDesc());
}, },
); );
} }
if (columnIndex == 3) { if (columnIndex == 3) {
final Map<String, bool> checkboxStates = { final Map<String, bool> checkboxStates = {
for (var item in _blocRole.roleTypes) for (var item in _blocRole.roleTypes)
@ -263,32 +263,31 @@ class UsersPage extends StatelessWidget {
list: _blocRole.roleTypes, list: _blocRole.roleTypes,
context: context, context: context,
checkboxStates: checkboxStates, checkboxStates: checkboxStates,
isSelected: _blocRole.currentSortOrder,
onOkPressed: () { onOkPressed: () {
_blocRole.add(FilterClearEvent());
final selectedItems = checkboxStates.entries final selectedItems = checkboxStates.entries
.where((entry) => entry.value) .where((entry) => entry.value)
.map((entry) => entry.key) .map((entry) => entry.key)
.toList(); .toList();
Navigator.of(context).pop(); Navigator.of(context).pop();
context context.read<UserTableBloc>().add(
.read<UserTableBloc>() FilterUsersByRoleEvent(
.add(FilterUsersByRoleEvent(selectedItems)); selectedRoles: selectedItems,
sortOrder: _blocRole.currentSortOrder));
}, },
onSortAtoZ: () { onSortAtoZ: (v) {
context _blocRole.currentSortOrder = v;
.read<UserTableBloc>()
.add(const SortUsersByNameAsc());
}, },
onSortZtoA: () { onSortZtoA: (v) {
context _blocRole.currentSortOrder = v;
.read<UserTableBloc>()
.add(const SortUsersByNameDesc());
}, },
); );
} }
if (columnIndex == 4) { if (columnIndex == 4) {
showDateFilterMenu( showDateFilterMenu(
context: context, context: context,
isSelected: _blocRole.currentSortOrderDate, isSelected: _blocRole.currentSortOrder,
aToZTap: () { aToZTap: () {
context context
.read<UserTableBloc>() .read<UserTableBloc>()
@ -319,32 +318,30 @@ class UsersPage extends StatelessWidget {
list: _blocRole.createdBy, list: _blocRole.createdBy,
context: context, context: context,
checkboxStates: checkboxStates, checkboxStates: checkboxStates,
isSelected: _blocRole.currentSortOrder,
onOkPressed: () { onOkPressed: () {
_blocRole.add(FilterClearEvent());
final selectedItems = checkboxStates.entries final selectedItems = checkboxStates.entries
.where((entry) => entry.value) .where((entry) => entry.value)
.map((entry) => entry.key) .map((entry) => entry.key)
.toList(); .toList();
Navigator.of(context).pop(); Navigator.of(context).pop();
_blocRole _blocRole.add(FilterUsersByCreatedEvent(
.add(FilterUsersByCreatedEvent(selectedItems)); selectedCreatedBy: selectedItems,
sortOrder: _blocRole.currentSortOrder));
}, },
onSortAtoZ: () { onSortAtoZ: (v) {
context _blocRole.currentSortOrder = v;
.read<UserTableBloc>()
.add(const SortUsersByNameAsc());
}, },
onSortZtoA: () { onSortZtoA: (v) {
context _blocRole.currentSortOrder = v;
.read<UserTableBloc>()
.add(const SortUsersByNameDesc());
}, },
); );
} }
if (columnIndex == 7) { if (columnIndex == 7) {
final Map<String, bool> checkboxStates = { final Map<String, bool> checkboxStates = {
for (var item in _blocRole.status) for (var item in _blocRole.status)
item: _blocRole.selectedCreatedBy.contains(item), item: _blocRole.selectedStatuses.contains(item),
}; };
final RenderBox overlay = Overlay.of(context) final RenderBox overlay = Overlay.of(context)
.context .context
@ -359,24 +356,24 @@ class UsersPage extends StatelessWidget {
list: _blocRole.status, list: _blocRole.status,
context: context, context: context,
checkboxStates: checkboxStates, checkboxStates: checkboxStates,
isSelected: _blocRole.currentSortOrder,
onOkPressed: () { onOkPressed: () {
_blocRole.add(FilterClearEvent());
final selectedItems = checkboxStates.entries final selectedItems = checkboxStates.entries
.where((entry) => entry.value) .where((entry) => entry.value)
.map((entry) => entry.key) .map((entry) => entry.key)
.toList(); .toList();
Navigator.of(context).pop(); Navigator.of(context).pop();
_blocRole _blocRole.add(FilterUsersByDeActevateEvent(
.add(FilterUsersByCreatedEvent(selectedItems)); selectedActivate: selectedItems,
sortOrder: _blocRole.currentSortOrder));
}, },
onSortAtoZ: () { onSortAtoZ: (v) {
context _blocRole.currentSortOrder = v;
.read<UserTableBloc>()
.add(const SortUsersByNameAsc());
}, },
onSortZtoA: () { onSortZtoA: (v) {
context _blocRole.currentSortOrder = v;
.read<UserTableBloc>()
.add(const SortUsersByNameDesc());
}, },
); );
} }
@ -413,7 +410,7 @@ class UsersPage extends StatelessWidget {
return [ return [
Text('${user.firstName} ${user.lastName}'), Text('${user.firstName} ${user.lastName}'),
Text(user.email), Text(user.email),
Text(user.jobTitle ?? ''), Text(user.jobTitle ?? '-'),
Text(user.roleType ?? ''), Text(user.roleType ?? ''),
Text(user.createdDate ?? ''), Text(user.createdDate ?? ''),
Text(user.createdTime ?? ''), Text(user.createdTime ?? ''),
@ -476,11 +473,17 @@ class UsersPage extends StatelessWidget {
barrierDismissible: false, barrierDismissible: false,
builder: (BuildContext context) { builder: (BuildContext context) {
return DeleteUserDialog( return DeleteUserDialog(
onTapDelete: () { onTapDelete: () async {
try {
_blocRole.add(DeleteUserEvent( _blocRole.add(DeleteUserEvent(
user.uuid, context)); user.uuid, context));
}, await Future.delayed(
); const Duration(seconds: 2));
return true;
} catch (e) {
return false;
}
});
}, },
).then((v) { ).then((v) {
if (v != null) { if (v != null) {
@ -504,6 +507,7 @@ class UsersPage extends StatelessWidget {
SizedBox( SizedBox(
width: 500, width: 500,
child: NumberPagination( child: NumberPagination(
visiblePagesCount: 4,
buttonRadius: 10, buttonRadius: 10,
selectedButtonColor: ColorsManager.secondaryColor, selectedButtonColor: ColorsManager.secondaryColor,
buttonUnSelectedBorderColor: buttonUnSelectedBorderColor:

View File

@ -71,8 +71,8 @@ class UserPermissionApi {
"firstName": firstName, "firstName": firstName,
"lastName": lastName, "lastName": lastName,
"email": email, "email": email,
"jobTitle": jobTitle != '' ? jobTitle : " ", "jobTitle": jobTitle != '' ? jobTitle : null,
"phoneNumber": phoneNumber != '' ? phoneNumber : " ", "phoneNumber": phoneNumber != '' ? phoneNumber : null,
"roleUuid": roleUuid, "roleUuid": roleUuid,
"projectUuid": "0e62577c-06fa-41b9-8a92-99a21fbaf51c", "projectUuid": "0e62577c-06fa-41b9-8a92-99a21fbaf51c",
"spaceUuids": spaceUuids, "spaceUuids": spaceUuids,
@ -119,13 +119,8 @@ class UserPermissionApi {
); );
return response ?? 'Unknown error occurred'; return response ?? 'Unknown error occurred';
} on DioException catch (e) { } on DioException catch (e) {
if (e.response != null) {
final errorMessage = e.response?.data['error']; final errorMessage = e.response?.data['error'];
return errorMessage is String return errorMessage;
? errorMessage
: 'Error occurred while checking email';
}
return 'Error occurred while checking email';
} catch (e) { } catch (e) {
return e.toString(); return e.toString();
} }