mirror of
https://github.com/SyncrowIOT/web.git
synced 2026-03-11 03:01:45 +00:00
Compare commits
8 Commits
Roles_&_Pe
...
user_agree
| Author | SHA1 | Date | |
|---|---|---|---|
| bc4af6a237 | |||
| 513175ed1e | |||
| 59eafc99a5 | |||
| db7eaa53af | |||
| 20a9f19480 | |||
| eb7eeebf18 | |||
| 15023e5882 | |||
| f8efc07fdb |
@ -10,6 +10,10 @@ class UserModel {
|
||||
final String? phoneNumber;
|
||||
final bool? isEmailVerified;
|
||||
final bool? isAgreementAccepted;
|
||||
final bool? hasAcceptedWebAgreement;
|
||||
final DateTime? webAgreementAcceptedAt;
|
||||
final UserRole? role;
|
||||
|
||||
UserModel({
|
||||
required this.uuid,
|
||||
required this.email,
|
||||
@ -19,6 +23,9 @@ class UserModel {
|
||||
required this.phoneNumber,
|
||||
required this.isEmailVerified,
|
||||
required this.isAgreementAccepted,
|
||||
required this.hasAcceptedWebAgreement,
|
||||
required this.webAgreementAcceptedAt,
|
||||
required this.role,
|
||||
});
|
||||
|
||||
factory UserModel.fromJson(Map<String, dynamic> json) {
|
||||
@ -31,6 +38,11 @@ class UserModel {
|
||||
phoneNumber: json['phoneNumber'],
|
||||
isEmailVerified: json['isEmailVerified'],
|
||||
isAgreementAccepted: json['isAgreementAccepted'],
|
||||
hasAcceptedWebAgreement: json['hasAcceptedWebAgreement'],
|
||||
webAgreementAcceptedAt: json['webAgreementAcceptedAt'] != null
|
||||
? DateTime.parse(json['webAgreementAcceptedAt'])
|
||||
: null,
|
||||
role: json['role'] != null ? UserRole.fromJson(json['role']) : null,
|
||||
);
|
||||
}
|
||||
|
||||
@ -41,6 +53,9 @@ class UserModel {
|
||||
Map<String, dynamic> tempJson = Token.decodeToken(token.accessToken);
|
||||
|
||||
return UserModel(
|
||||
hasAcceptedWebAgreement: null,
|
||||
role: null,
|
||||
webAgreementAcceptedAt: null,
|
||||
uuid: tempJson['uuid'].toString(),
|
||||
email: tempJson['email'],
|
||||
firstName: null,
|
||||
@ -65,3 +80,26 @@ class UserModel {
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
class UserRole {
|
||||
final String uuid;
|
||||
final DateTime createdAt;
|
||||
final DateTime updatedAt;
|
||||
final String type;
|
||||
|
||||
UserRole({
|
||||
required this.uuid,
|
||||
required this.createdAt,
|
||||
required this.updatedAt,
|
||||
required this.type,
|
||||
});
|
||||
|
||||
factory UserRole.fromJson(Map<String, dynamic> json) {
|
||||
return UserRole(
|
||||
uuid: json['uuid'],
|
||||
createdAt: DateTime.parse(json['createdAt']),
|
||||
updatedAt: DateTime.parse(json['updatedAt']),
|
||||
type: json['type'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,10 +18,15 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
List<Node> sourcesList = [];
|
||||
List<Node> destinationsList = [];
|
||||
UserModel? user;
|
||||
String terms = '';
|
||||
String policy = '';
|
||||
|
||||
HomeBloc() : super((HomeInitial())) {
|
||||
on<CreateNewNode>(_createNode);
|
||||
on<FetchUserInfo>(_fetchUserInfo);
|
||||
on<FetchTermEvent>(_fetchTerms);
|
||||
on<FetchPolicyEvent>(_fetchPolicy);
|
||||
on<ConfirmUserAgreementEvent>(_confirmUserAgreement);
|
||||
}
|
||||
|
||||
void _createNode(CreateNewNode event, Emitter<HomeState> emit) async {
|
||||
@ -45,12 +50,45 @@ class HomeBloc extends Bloc<HomeEvent, HomeState> {
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
user = await HomeApi().fetchUserInfo(uuid);
|
||||
add(FetchTermEvent());
|
||||
emit(HomeInitial());
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future _fetchTerms(FetchTermEvent event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
emit(LoadingHome());
|
||||
terms = await HomeApi().fetchTerms();
|
||||
add(FetchPolicyEvent());
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future _fetchPolicy(FetchPolicyEvent event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
emit(LoadingHome());
|
||||
policy = await HomeApi().fetchPolicy();
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future _confirmUserAgreement(
|
||||
ConfirmUserAgreementEvent event, Emitter<HomeState> emit) async {
|
||||
try {
|
||||
emit(LoadingHome());
|
||||
var uuid =
|
||||
await const FlutterSecureStorage().read(key: UserModel.userUuidKey);
|
||||
policy = await HomeApi().confirmUserAgreements(uuid);
|
||||
emit(PolicyAgreement());
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// static Future fetchUserInfo() async {
|
||||
// try {
|
||||
// var uuid =
|
||||
|
||||
@ -20,4 +20,8 @@ class CreateNewNode extends HomeEvent {
|
||||
|
||||
class FetchUserInfo extends HomeEvent {
|
||||
const FetchUserInfo();
|
||||
}
|
||||
}class FetchTermEvent extends HomeEvent {}
|
||||
|
||||
class FetchPolicyEvent extends HomeEvent {}
|
||||
|
||||
class ConfirmUserAgreementEvent extends HomeEvent {}
|
||||
@ -7,8 +7,12 @@ abstract class HomeState extends Equatable {
|
||||
@override
|
||||
List<Object> get props => [];
|
||||
}
|
||||
class LoadingHome extends HomeState {}
|
||||
|
||||
class HomeInitial extends HomeState {}
|
||||
class TermsAgreement extends HomeState {}
|
||||
|
||||
class PolicyAgreement extends HomeState {}
|
||||
|
||||
class HomeCounterState extends HomeState {
|
||||
final int counter;
|
||||
@ -24,3 +28,5 @@ class HomeUpdateTree extends HomeState {
|
||||
@override
|
||||
List<Object> get props => [graph, builder];
|
||||
}
|
||||
|
||||
//FetchTermEvent
|
||||
176
lib/pages/home/view/agreement_and_privacy_dialog.dart
Normal file
176
lib/pages/home/view/agreement_and_privacy_dialog.dart
Normal file
@ -0,0 +1,176 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_html/flutter_html.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:syncrow_web/pages/auth/bloc/auth_bloc.dart';
|
||||
import 'package:syncrow_web/utils/color_manager.dart';
|
||||
import 'package:syncrow_web/utils/constants/routes_const.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class AgreementAndPrivacyDialog extends StatefulWidget {
|
||||
final String terms;
|
||||
final String policy;
|
||||
|
||||
const AgreementAndPrivacyDialog({
|
||||
super.key,
|
||||
required this.terms,
|
||||
required this.policy,
|
||||
});
|
||||
|
||||
@override
|
||||
_AgreementAndPrivacyDialogState createState() =>
|
||||
_AgreementAndPrivacyDialogState();
|
||||
}
|
||||
|
||||
class _AgreementAndPrivacyDialogState extends State<AgreementAndPrivacyDialog> {
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
bool _isAtEnd = false;
|
||||
int _currentPage = 1;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_scrollController.addListener(_onScroll);
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((_) => _checkScrollRequirement());
|
||||
}
|
||||
|
||||
void _checkScrollRequirement() {
|
||||
final scrollPosition = _scrollController.position;
|
||||
if (scrollPosition.maxScrollExtent <= 0) {
|
||||
setState(() {
|
||||
_isAtEnd = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_scrollController.removeListener(_onScroll);
|
||||
_scrollController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onScroll() {
|
||||
if (_scrollController.position.atEdge) {
|
||||
final isAtBottom = _scrollController.position.pixels ==
|
||||
_scrollController.position.maxScrollExtent;
|
||||
if (isAtBottom && !_isAtEnd) {
|
||||
setState(() {
|
||||
_isAtEnd = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String get _dialogTitle =>
|
||||
_currentPage == 2 ? 'User Agreement' : 'Privacy Policy';
|
||||
|
||||
String get _dialogContent => _currentPage == 2 ? widget.terms : widget.policy;
|
||||
|
||||
Widget _buildScrollableContent() {
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(40),
|
||||
width: MediaQuery.of(context).size.width * 0.8,
|
||||
height: MediaQuery.of(context).size.height * 0.75,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[200],
|
||||
borderRadius: const BorderRadius.all(Radius.circular(20)),
|
||||
),
|
||||
child: Scrollbar(
|
||||
thumbVisibility: true,
|
||||
trackVisibility: true,
|
||||
interactive: true,
|
||||
controller: _scrollController,
|
||||
child: SingleChildScrollView(
|
||||
controller: _scrollController,
|
||||
padding: const EdgeInsets.all(25),
|
||||
child: Html(
|
||||
data: _dialogContent,
|
||||
onLinkTap: (url, attributes, element) async {
|
||||
if (url != null) {
|
||||
final uri = Uri.parse(url);
|
||||
await launchUrl(uri, mode: LaunchMode.externalApplication);
|
||||
}
|
||||
},
|
||||
style: {
|
||||
"body": Style(
|
||||
fontSize: FontSize(14),
|
||||
color: Colors.black87,
|
||||
lineHeight: LineHeight(1.5),
|
||||
),
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildActionButton() {
|
||||
final String buttonText = _currentPage == 2 ? "I Agree" : "Next";
|
||||
|
||||
return InkWell(
|
||||
onTap: _isAtEnd
|
||||
? () {
|
||||
if (_currentPage == 1) {
|
||||
setState(() {
|
||||
_currentPage = 2;
|
||||
_isAtEnd = false;
|
||||
_scrollController.jumpTo(0);
|
||||
WidgetsBinding.instance
|
||||
.addPostFrameCallback((_) => _checkScrollRequirement());
|
||||
});
|
||||
} else {
|
||||
Navigator.of(context).pop(true);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Text(
|
||||
buttonText,
|
||||
style: TextStyle(
|
||||
color: _isAtEnd ? ColorsManager.secondaryColor : Colors.grey,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Dialog(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Text(
|
||||
_dialogTitle,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w700,
|
||||
color: ColorsManager.secondaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
_buildScrollableContent(),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
InkWell(
|
||||
onTap: () {
|
||||
AuthBloc.logout();
|
||||
context.go(RoutesConst.auth);
|
||||
},
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
_buildActionButton(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_event.dart';
|
||||
import 'package:syncrow_web/pages/home/view/agreement_and_privacy_dialog.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_bloc.dart';
|
||||
import 'package:syncrow_web/pages/home/bloc/home_state.dart';
|
||||
import 'package:syncrow_web/pages/home/view/home_card.dart';
|
||||
@ -9,16 +11,40 @@ import 'package:syncrow_web/web_layout/web_scaffold.dart';
|
||||
|
||||
class HomeWebPage extends StatelessWidget {
|
||||
const HomeWebPage({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
Size size = MediaQuery.of(context).size;
|
||||
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||
|
||||
return PopScope(
|
||||
canPop: false,
|
||||
onPopInvoked: (didPop) => false,
|
||||
child: BlocConsumer<HomeBloc, HomeState>(
|
||||
listener: (BuildContext context, state) {},
|
||||
listener: (BuildContext context, state) {
|
||||
if (state is HomeInitial) {
|
||||
if (homeBloc.user!.hasAcceptedWebAgreement == false) {
|
||||
Future.delayed(const Duration(seconds: 1), () {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return AgreementAndPrivacyDialog(
|
||||
terms: homeBloc.terms,
|
||||
policy: homeBloc.policy,
|
||||
);
|
||||
},
|
||||
).then((v) {
|
||||
if (v != null) {
|
||||
homeBloc.add(ConfirmUserAgreementEvent());
|
||||
homeBloc.add(const FetchUserInfo());
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
builder: (context, state) {
|
||||
final homeBloc = BlocProvider.of<HomeBloc>(context);
|
||||
return WebScaffold(
|
||||
enableMenuSidebar: false,
|
||||
appBarTitle: Row(
|
||||
@ -52,7 +78,8 @@ class HomeWebPage extends StatelessWidget {
|
||||
width: size.width * 0.68,
|
||||
child: GridView.builder(
|
||||
itemCount: 3, //8
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
gridDelegate:
|
||||
const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 4,
|
||||
crossAxisSpacing: 20.0,
|
||||
mainAxisSpacing: 20.0,
|
||||
@ -64,7 +91,8 @@ class HomeWebPage extends StatelessWidget {
|
||||
active: homeBloc.homeItems[index].active!,
|
||||
name: homeBloc.homeItems[index].title!,
|
||||
img: homeBloc.homeItems[index].icon!,
|
||||
onTap: () => homeBloc.homeItems[index].onPress(context),
|
||||
onTap: () =>
|
||||
homeBloc.homeItems[index].onPress(context),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
||||
@ -42,7 +42,7 @@ class RolesUserModel {
|
||||
invitedBy:
|
||||
json['invitedBy'].toString().toLowerCase().replaceAll("_", " "),
|
||||
phoneNumber: json['phoneNumber'],
|
||||
jobTitle: json['jobTitle'].toString(),
|
||||
jobTitle: json['jobTitle'] ?? "-",
|
||||
createdDate: json['createdDate'],
|
||||
createdTime: json['createdTime'],
|
||||
);
|
||||
|
||||
@ -114,7 +114,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
currentStep++;
|
||||
if (currentStep == 2) {
|
||||
_blocRole.add(
|
||||
CheckStepStatus(isEditUser: false));
|
||||
const CheckStepStatus(isEditUser: false));
|
||||
} else if (currentStep == 3) {
|
||||
_blocRole
|
||||
.add(const CheckSpacesStepStatus());
|
||||
@ -151,11 +151,11 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
Widget _getFormContent() {
|
||||
switch (currentStep) {
|
||||
case 1:
|
||||
return BasicsView(
|
||||
return const BasicsView(
|
||||
userId: '',
|
||||
);
|
||||
case 2:
|
||||
return SpacesAccessView();
|
||||
return const SpacesAccessView();
|
||||
case 3:
|
||||
return const RolesAndPermission();
|
||||
default:
|
||||
@ -172,7 +172,7 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
bloc.add(const CheckSpacesStepStatus());
|
||||
currentStep = step;
|
||||
Future.delayed(const Duration(milliseconds: 500), () {
|
||||
bloc.add(ValidateBasicsStep());
|
||||
bloc.add(const ValidateBasicsStep());
|
||||
});
|
||||
});
|
||||
|
||||
@ -237,10 +237,11 @@ class _AddNewUserDialogState extends State<AddNewUserDialog> {
|
||||
onTap: () {
|
||||
setState(() {
|
||||
currentStep = step;
|
||||
bloc.add(CheckStepStatus(isEditUser: false));
|
||||
bloc.add(const CheckStepStatus(isEditUser: false));
|
||||
if (step3 == 3) {
|
||||
bloc.add(const CheckRoleStepStatus());
|
||||
}
|
||||
|
||||
});
|
||||
},
|
||||
child: Column(
|
||||
|
||||
@ -4,7 +4,6 @@ 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/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';
|
||||
@ -47,7 +46,9 @@ class BasicsView extends StatelessWidget {
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.18,
|
||||
height: MediaQuery.of(context).size.width * 0.08,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -76,12 +77,12 @@ class BasicsView extends StatelessWidget {
|
||||
child: TextFormField(
|
||||
style:
|
||||
const TextStyle(color: ColorsManager.blackColor),
|
||||
onChanged: (value) {
|
||||
Future.delayed(const Duration(milliseconds: 200),
|
||||
() {
|
||||
_blocRole.add(ValidateBasicsStep());
|
||||
});
|
||||
},
|
||||
// onChanged: (value) {
|
||||
// Future.delayed(const Duration(milliseconds: 200),
|
||||
// () {
|
||||
// _blocRole.add(const ValidateBasicsStep());
|
||||
// });
|
||||
// },
|
||||
controller: _blocRole.firstNameController,
|
||||
decoration: inputTextFormDeco(
|
||||
hintText: "Enter first name",
|
||||
@ -103,7 +104,9 @@ class BasicsView extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.18,
|
||||
height: MediaQuery.of(context).size.width * 0.08,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@ -128,12 +131,12 @@ class BasicsView extends StatelessWidget {
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
onChanged: (value) {
|
||||
Future.delayed(const Duration(milliseconds: 200),
|
||||
() {
|
||||
_blocRole.add(ValidateBasicsStep());
|
||||
});
|
||||
},
|
||||
// onChanged: (value) {
|
||||
// Future.delayed(const Duration(milliseconds: 200),
|
||||
// () {
|
||||
// _blocRole.add(ValidateBasicsStep());
|
||||
// });
|
||||
// },
|
||||
controller: _blocRole.lastNameController,
|
||||
style: const TextStyle(color: Colors.black),
|
||||
decoration:
|
||||
@ -186,13 +189,13 @@ class BasicsView extends StatelessWidget {
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextFormField(
|
||||
enabled: userId != '' ? false : true,
|
||||
onChanged: (value) {
|
||||
Future.delayed(const Duration(milliseconds: 200), () {
|
||||
_blocRole.add(CheckStepStatus(
|
||||
isEditUser: userId != '' ? false : true));
|
||||
_blocRole.add(ValidateBasicsStep());
|
||||
});
|
||||
},
|
||||
// onChanged: (value) {
|
||||
// Future.delayed(const Duration(milliseconds: 200), () {
|
||||
// _blocRole.add(CheckStepStatus(
|
||||
// isEditUser: userId != '' ? false : true));
|
||||
// _blocRole.add(ValidateBasicsStep());
|
||||
// });
|
||||
// },
|
||||
controller: _blocRole.emailController,
|
||||
style: const TextStyle(color: ColorsManager.blackColor),
|
||||
decoration: inputTextFormDeco(hintText: "name@example.com")
|
||||
|
||||
@ -11,7 +11,14 @@ class DeleteUserDialog extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _DeleteUserDialogState extends State<DeleteUserDialog> {
|
||||
int currentStep = 1;
|
||||
bool isLoading = false;
|
||||
bool _isDisposed = false;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_isDisposed = true;
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
@ -56,7 +63,7 @@ class _DeleteUserDialogState extends State<DeleteUserDialog> {
|
||||
Expanded(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop(true);
|
||||
Navigator.of(context).pop(false); // Return false if canceled
|
||||
},
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
@ -76,7 +83,26 @@ class _DeleteUserDialogState extends State<DeleteUserDialog> {
|
||||
)),
|
||||
Expanded(
|
||||
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(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: const BoxDecoration(
|
||||
@ -91,13 +117,22 @@ class _DeleteUserDialogState extends State<DeleteUserDialog> {
|
||||
),
|
||||
),
|
||||
),
|
||||
child: const Center(
|
||||
child: Text(
|
||||
'Delete',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
),
|
||||
))),
|
||||
child: Center(
|
||||
child: isLoading
|
||||
? const SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: CircularProgressIndicator(
|
||||
color: ColorsManager.red,
|
||||
strokeWidth: 2.0,
|
||||
),
|
||||
)
|
||||
: const Text(
|
||||
'Delete',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.red,
|
||||
),
|
||||
))),
|
||||
)),
|
||||
],
|
||||
)
|
||||
|
||||
@ -128,7 +128,7 @@ class _PermissionManagementState extends State<PermissionManagement> {
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
option.title,
|
||||
' ${option.title.isNotEmpty ? option.title[0].toUpperCase() : ''}${option.title.substring(1)}',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
@ -184,7 +184,7 @@ class _PermissionManagementState extends State<PermissionManagement> {
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
subOption.title,
|
||||
' ${subOption.title.isNotEmpty ? subOption.title[0].toUpperCase() : ''}${subOption.title.substring(1)}',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w700,
|
||||
fontSize: 12,
|
||||
@ -246,7 +246,7 @@ class _PermissionManagementState extends State<PermissionManagement> {
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
child.title,
|
||||
' ${child.title.isNotEmpty ? child.title[0].toUpperCase() : ''}${child.title.substring(1)}',
|
||||
style: context.textTheme.bodyMedium?.copyWith(
|
||||
fontWeight: FontWeight.w400,
|
||||
fontSize: 12,
|
||||
|
||||
@ -5,141 +5,156 @@ import 'package:syncrow_web/utils/style.dart';
|
||||
|
||||
Future<void> showPopUpFilterMenu({
|
||||
required BuildContext context,
|
||||
Function()? onSortAtoZ,
|
||||
Function()? onSortZtoA,
|
||||
required Function(String value) onSortAtoZ,
|
||||
required Function(String value) onSortZtoA,
|
||||
Function()? cancelButton,
|
||||
required Map<String, bool> checkboxStates,
|
||||
required RelativeRect position,
|
||||
Function()? onOkPressed,
|
||||
List<String>? list,
|
||||
String? isSelected,
|
||||
}) async {
|
||||
|
||||
|
||||
await showMenu(
|
||||
context: context,
|
||||
position:position,
|
||||
|
||||
|
||||
position: position,
|
||||
color: ColorsManager.whiteColors,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.all(Radius.circular(10)),
|
||||
),
|
||||
items: <PopupMenuEntry>[
|
||||
PopupMenuItem(
|
||||
onTap: onSortAtoZ,
|
||||
child: ListTile(
|
||||
leading: Image.asset(
|
||||
Assets.AtoZIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: const Text(
|
||||
"Sort A to Z",
|
||||
style: TextStyle(color: Colors.blueGrey),
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
onTap: onSortZtoA,
|
||||
child: ListTile(
|
||||
leading: Image.asset(
|
||||
Assets.ZtoAIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: const Text(
|
||||
"Sort Z to A",
|
||||
style: TextStyle(color: Colors.blueGrey),
|
||||
),
|
||||
),
|
||||
),
|
||||
const PopupMenuDivider(),
|
||||
const PopupMenuItem(
|
||||
child: Text(
|
||||
"Filter by Status",
|
||||
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(
|
||||
child: Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
boxShadow: [],
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(10),
|
||||
bottomRight: Radius.circular(10))),
|
||||
padding: const EdgeInsets.all(10),
|
||||
height: 200,
|
||||
width: 400,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
color: Colors.white,
|
||||
child: ListView.builder(
|
||||
itemCount: list?.length ?? 0,
|
||||
itemBuilder: (context, index) {
|
||||
final item = list![index];
|
||||
return CheckboxListTile(
|
||||
dense: true,
|
||||
title: Text(item),
|
||||
value: checkboxStates[item],
|
||||
onChanged: (bool? newValue) {
|
||||
checkboxStates[item] = newValue ?? false;
|
||||
(context as Element).markNeedsBuild();
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
PopupMenuItem(
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop(); // Close the menu
|
||||
},
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: onOkPressed,
|
||||
child: const Text(
|
||||
"OK",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.spaceColor,
|
||||
enabled: false,
|
||||
child: StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SizedBox(
|
||||
child: ListTile(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (isSelected == 'Asc') {
|
||||
isSelected = null;
|
||||
onSortAtoZ.call('');
|
||||
} else {
|
||||
onSortAtoZ.call('Asc');
|
||||
isSelected = 'Asc';
|
||||
}
|
||||
});
|
||||
},
|
||||
leading: Image.asset(
|
||||
Assets.AtoZIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: Text(
|
||||
"Sort A to Z",
|
||||
style: TextStyle(
|
||||
color: isSelected == "Asc"
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.grayColor),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
ListTile(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
if (isSelected == 'Desc') {
|
||||
isSelected = null;
|
||||
onSortZtoA.call('');
|
||||
} else {
|
||||
onSortZtoA.call('Desc');
|
||||
isSelected = 'Desc';
|
||||
}
|
||||
});
|
||||
},
|
||||
leading: Image.asset(
|
||||
Assets.ZtoAIcon,
|
||||
width: 25,
|
||||
),
|
||||
title: Text(
|
||||
"Sort Z to A",
|
||||
style: TextStyle(
|
||||
color: isSelected == "Desc"
|
||||
? ColorsManager.blackColor
|
||||
: ColorsManager.grayColor),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
const Text(
|
||||
"Filter by Status",
|
||||
style: TextStyle(fontWeight: FontWeight.bold),
|
||||
),
|
||||
Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
boxShadow: [],
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(10),
|
||||
topRight: Radius.circular(10),
|
||||
bottomLeft: Radius.circular(10),
|
||||
bottomRight: Radius.circular(10))),
|
||||
padding: const EdgeInsets.all(10),
|
||||
height: 200,
|
||||
width: 400,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
color: Colors.white,
|
||||
child: ListView.builder(
|
||||
itemCount: list?.length ?? 0,
|
||||
itemBuilder: (context, index) {
|
||||
final item = list![index];
|
||||
return Row(
|
||||
children: [
|
||||
Checkbox(
|
||||
value: checkboxStates[item],
|
||||
onChanged: (bool? newValue) {
|
||||
checkboxStates[item] = newValue ?? false;
|
||||
(context as Element).markNeedsBuild();
|
||||
},
|
||||
),
|
||||
Text(
|
||||
item,
|
||||
style: TextStyle(color: ColorsManager.grayColor),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const Divider(),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
Navigator.of(context).pop(); // Close the menu
|
||||
},
|
||||
child: const Text("Cancel"),
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: onOkPressed,
|
||||
child: const Text(
|
||||
"OK",
|
||||
style: TextStyle(
|
||||
color: ColorsManager.spaceColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@ -52,14 +52,16 @@ class _RoleDropdownState extends State<RoleDropdown> {
|
||||
SizedBox(
|
||||
child: DropdownButtonFormField<String>(
|
||||
dropdownColor: ColorsManager.whiteColors,
|
||||
alignment: Alignment.center,
|
||||
// alignment: Alignment.,
|
||||
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),
|
||||
child: Text(
|
||||
' ${role.type.isNotEmpty ? role.type[0].toUpperCase() : ''}${role.type.substring(1)}',
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
onChanged: (value) {
|
||||
|
||||
@ -93,7 +93,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
try {
|
||||
emit(UsersLoadingState());
|
||||
bool res = await UserPermissionApi().changeUserStatusById(
|
||||
event.userId, event.newStatus == "disabled" ? true : false);
|
||||
event.userId, event.newStatus == "disabled" ? false : true);
|
||||
if (res == true) {
|
||||
add(const GetUsers());
|
||||
// users = users.map((user) {
|
||||
@ -133,7 +133,10 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
} else {
|
||||
emit(UsersLoadingState());
|
||||
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));
|
||||
}
|
||||
}
|
||||
@ -164,6 +167,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
emit(UsersLoadedState(users: users));
|
||||
} else {
|
||||
emit(UsersLoadingState());
|
||||
currentSortOrder = "NewestToOldest";
|
||||
users.sort((a, b) {
|
||||
final dateA = _parseDateTime(a.createdDate);
|
||||
final dateB = _parseDateTime(b.createdDate);
|
||||
@ -188,6 +192,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
final dateB = _parseDateTime(b.createdDate);
|
||||
return dateA.compareTo(dateB);
|
||||
});
|
||||
currentSortOrder = "OldestToNewest";
|
||||
emit(UsersLoadedState(users: users));
|
||||
}
|
||||
}
|
||||
@ -210,7 +215,7 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
final query = event.query.toLowerCase();
|
||||
final filteredUsers = initialUsers.where((user) {
|
||||
final fullName = "${user.firstName} ${user.lastName}".toLowerCase();
|
||||
final email = user.email.toLowerCase() ;
|
||||
final email = user.email.toLowerCase();
|
||||
return fullName.contains(query) || email.contains(query);
|
||||
}).toList();
|
||||
emit(UsersLoadedState(users: filteredUsers));
|
||||
@ -256,49 +261,96 @@ class UserTableBloc extends Bloc<UserTableEvent, UserTableState> {
|
||||
|
||||
void _filterUsersByRole(
|
||||
FilterUsersByRoleEvent event, Emitter<UserTableState> emit) {
|
||||
selectedRoles = event.selectedRoles.toSet();
|
||||
selectedRoles = event.selectedRoles!.toSet();
|
||||
|
||||
final filteredUsers = initialUsers.where((user) {
|
||||
if (selectedRoles.isEmpty) return true;
|
||||
return selectedRoles.contains(user.roleType);
|
||||
}).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));
|
||||
}
|
||||
|
||||
void _filterUsersByJobTitle(
|
||||
FilterUsersByJobEvent event, Emitter<UserTableState> emit) {
|
||||
selectedJobTitles = event.selectedJob.toSet();
|
||||
|
||||
selectedJobTitles = event.selectedJob!.toSet();
|
||||
emit(UsersLoadingState());
|
||||
final filteredUsers = initialUsers.where((user) {
|
||||
if (selectedJobTitles.isEmpty) return true;
|
||||
return selectedJobTitles.contains(user.jobTitle);
|
||||
}).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));
|
||||
}
|
||||
|
||||
void _filterUsersByCreated(
|
||||
FilterUsersByCreatedEvent event, Emitter<UserTableState> emit) {
|
||||
selectedCreatedBy = event.selectedCreatedBy.toSet();
|
||||
selectedCreatedBy = event.selectedCreatedBy!.toSet();
|
||||
|
||||
final filteredUsers = initialUsers.where((user) {
|
||||
if (selectedCreatedBy.isEmpty) return true;
|
||||
return selectedCreatedBy.contains(user.invitedBy);
|
||||
}).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));
|
||||
}
|
||||
|
||||
void _filterUserStatus(
|
||||
FilterUsersByDeActevateEvent event, Emitter<UserTableState> emit) {
|
||||
selectedStatuses = event.selectedActivate.toSet();
|
||||
selectedStatuses = event.selectedActivate!.toSet();
|
||||
|
||||
final filteredUsers = initialUsers.where((user) {
|
||||
if (selectedStatuses.isEmpty) return true;
|
||||
return selectedStatuses.contains(user.status);
|
||||
}).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));
|
||||
}
|
||||
|
||||
|
||||
@ -89,35 +89,36 @@ class DeleteUserEvent extends UserTableEvent {
|
||||
}
|
||||
|
||||
class FilterUsersByRoleEvent extends UserTableEvent {
|
||||
final List<String> selectedRoles;
|
||||
final List<String>? selectedRoles;
|
||||
final String? sortOrder;
|
||||
|
||||
FilterUsersByRoleEvent(this.selectedRoles);
|
||||
@override
|
||||
List<Object?> get props => [selectedRoles];
|
||||
const FilterUsersByRoleEvent({this.selectedRoles, this.sortOrder});
|
||||
List<Object?> get props => [selectedRoles, sortOrder];
|
||||
}
|
||||
|
||||
class FilterUsersByJobEvent extends UserTableEvent {
|
||||
final List<String> selectedJob;
|
||||
final List<String>? selectedJob;
|
||||
final String? sortOrder;
|
||||
|
||||
FilterUsersByJobEvent(this.selectedJob);
|
||||
@override
|
||||
List<Object?> get props => [selectedJob];
|
||||
const FilterUsersByJobEvent({this.selectedJob, this.sortOrder});
|
||||
List<Object?> get props => [selectedJob, sortOrder];
|
||||
}
|
||||
|
||||
class FilterUsersByCreatedEvent extends UserTableEvent {
|
||||
final List<String> selectedCreatedBy;
|
||||
final List<String>? selectedCreatedBy;
|
||||
|
||||
FilterUsersByCreatedEvent(this.selectedCreatedBy);
|
||||
@override
|
||||
List<Object?> get props => [selectedCreatedBy];
|
||||
final String? sortOrder;
|
||||
|
||||
const FilterUsersByCreatedEvent({this.selectedCreatedBy, this.sortOrder});
|
||||
List<Object?> get props => [selectedCreatedBy, sortOrder];
|
||||
}
|
||||
|
||||
class FilterUsersByDeActevateEvent extends UserTableEvent {
|
||||
final List<String> selectedActivate;
|
||||
final List<String>? selectedActivate;
|
||||
final String? sortOrder;
|
||||
|
||||
FilterUsersByDeActevateEvent(this.selectedActivate);
|
||||
@override
|
||||
List<Object?> get props => [selectedActivate];
|
||||
const FilterUsersByDeActevateEvent({this.selectedActivate, this.sortOrder});
|
||||
List<Object?> get props => [selectedActivate, sortOrder];
|
||||
}
|
||||
|
||||
class FilterOptionsEvent extends UserTableEvent {
|
||||
|
||||
@ -19,19 +19,13 @@ class DynamicTableScreen extends StatefulWidget {
|
||||
class _DynamicTableScreenState extends State<DynamicTableScreen>
|
||||
with WidgetsBindingObserver {
|
||||
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
|
||||
void 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);
|
||||
}
|
||||
|
||||
@ -44,7 +38,6 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
|
||||
@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) {
|
||||
@ -53,7 +46,7 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
|
||||
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
|
||||
0.1; // 25% of screen width for the tenth column
|
||||
}
|
||||
return newScreenWidth *
|
||||
0.09; // Default to 10% of screen width for other columns
|
||||
@ -64,293 +57,204 @@ class _DynamicTableScreenState extends State<DynamicTableScreen>
|
||||
@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)) {
|
||||
if (columnWidths.every((width) => width == screenWidth * 7)) {
|
||||
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.1;
|
||||
}
|
||||
return screenWidth * 0.11;
|
||||
return screenWidth * 0.09;
|
||||
});
|
||||
setState(() {});
|
||||
}
|
||||
return Container(
|
||||
child: SingleChildScrollView(
|
||||
clipBehavior: Clip.none,
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(20))),
|
||||
child: FittedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
// Header Row with Resizable Columns
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.circleRolesBackground,
|
||||
borderRadius: const 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,
|
||||
),
|
||||
return SingleChildScrollView(
|
||||
clipBehavior: Clip.none,
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: Container(
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(20))),
|
||||
child: FittedBox(
|
||||
child: Column(
|
||||
children: [
|
||||
Container(
|
||||
width: totalWidth,
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.circleRolesBackground,
|
||||
borderRadius: const 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 != 8 &&
|
||||
index != 5)
|
||||
FittedBox(
|
||||
child: IconButton(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.filterTableIcon,
|
||||
fit: BoxFit.none,
|
||||
),
|
||||
onPressed: () {
|
||||
if (widget.onFilter != null) {
|
||||
widget.onFilter!(index);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (index != 1 &&
|
||||
index != 9 &&
|
||||
index != 8 &&
|
||||
index != 5)
|
||||
FittedBox(
|
||||
child: IconButton(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.filterTableIcon,
|
||||
fit: BoxFit.none,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
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
|
||||
widget.rows.isEmpty
|
||||
? Container(
|
||||
child: SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 2,
|
||||
child: Container(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
SvgPicture.asset(Assets.emptyTable),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
onPressed: () {
|
||||
if (widget.onFilter != null) {
|
||||
widget.onFilter!(index);
|
||||
}
|
||||
},
|
||||
),
|
||||
const Text(
|
||||
'No Users',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700),
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: Center(
|
||||
child: Container(
|
||||
// height: MediaQuery.of(context).size.height * 0.59,
|
||||
width: MediaQuery.of(context).size.width,
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(15),
|
||||
bottomRight: Radius.circular(15))),
|
||||
child: ListView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemCount: widget.rows.length,
|
||||
itemBuilder: (context, rowIndex) {
|
||||
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;
|
||||
}
|
||||
GestureDetector(
|
||||
onHorizontalDragUpdate: (details) {
|
||||
setState(() {
|
||||
columnWidths[index] =
|
||||
(columnWidths[index] + details.delta.dx)
|
||||
.clamp(150.0, 300.0);
|
||||
totalWidth = columnWidths.reduce((a, b) => a + b);
|
||||
});
|
||||
},
|
||||
child: MouseRegion(
|
||||
cursor: SystemMouseCursors.resizeColumn,
|
||||
child: Container(
|
||||
color: Colors.green,
|
||||
child: Container(
|
||||
color: ColorsManager.boxDivider,
|
||||
width: 1,
|
||||
height: 50,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
widget.rows.isEmpty
|
||||
? SizedBox(
|
||||
height: MediaQuery.of(context).size.height / 2,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
SvgPicture.asset(Assets.emptyTable),
|
||||
const SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
const Text(
|
||||
'No Users',
|
||||
style: TextStyle(
|
||||
color: ColorsManager.lightGrayColor,
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w700),
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Center(
|
||||
child: Container(
|
||||
width: totalWidth,
|
||||
decoration: containerDecoration.copyWith(
|
||||
color: ColorsManager.whiteColors,
|
||||
borderRadius: const BorderRadius.only(
|
||||
bottomLeft: Radius.circular(15),
|
||||
bottomRight: Radius.circular(15))),
|
||||
child: ListView.builder(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
shrinkWrap: true,
|
||||
itemCount: widget.rows.length,
|
||||
itemBuilder: (context, rowIndex) {
|
||||
if (columnWidths.every((width) => width == 120.0)) {
|
||||
columnWidths = List<double>.generate(
|
||||
widget.titles.length, (index) {
|
||||
if (index == 1) {
|
||||
return screenWidth * 0.11;
|
||||
});
|
||||
setState(() {});
|
||||
}
|
||||
final row = widget.rows[rowIndex];
|
||||
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) {
|
||||
} else if (index == 9) {
|
||||
return screenWidth * 0.2;
|
||||
}
|
||||
return screenWidth * 0.11;
|
||||
});
|
||||
setState(() {});
|
||||
}
|
||||
final row = widget.rows[rowIndex];
|
||||
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: const Divider(
|
||||
color: ColorsManager.boxDivider,
|
||||
thickness: 1,
|
||||
height: 1,
|
||||
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,
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 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(),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
@ -107,7 +107,6 @@ class UsersPage extends StatelessWidget {
|
||||
builder: (context, state) {
|
||||
final screenSize = MediaQuery.of(context).size;
|
||||
final _blocRole = BlocProvider.of<UserTableBloc>(context);
|
||||
|
||||
if (state is UsersLoadingState) {
|
||||
_blocRole.add(ChangePage(_blocRole.currentPage));
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
@ -189,8 +188,6 @@ class UsersPage extends StatelessWidget {
|
||||
const SizedBox(height: 25),
|
||||
DynamicTableScreen(
|
||||
onFilter: (columnIndex) {
|
||||
_blocRole.add(FilterClearEvent());
|
||||
|
||||
if (columnIndex == 0) {
|
||||
showNameMenu(
|
||||
context: context,
|
||||
@ -210,11 +207,12 @@ class UsersPage extends StatelessWidget {
|
||||
if (columnIndex == 2) {
|
||||
final Map<String, bool> checkboxStates = {
|
||||
for (var item in _blocRole.jobTitle)
|
||||
item: false, // Initialize with false
|
||||
item: _blocRole.selectedJobTitles.contains(item),
|
||||
};
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
.findRenderObject() as RenderBox;
|
||||
|
||||
showPopUpFilterMenu(
|
||||
position: RelativeRect.fromLTRB(
|
||||
overlay.size.width / 4,
|
||||
@ -225,26 +223,28 @@ class UsersPage extends StatelessWidget {
|
||||
list: _blocRole.jobTitle,
|
||||
context: context,
|
||||
checkboxStates: checkboxStates,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
onOkPressed: () {
|
||||
_blocRole.add(FilterClearEvent());
|
||||
final selectedItems = checkboxStates.entries
|
||||
.where((entry) => entry.value)
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
Navigator.of(context).pop();
|
||||
_blocRole.add(FilterUsersByJobEvent(selectedItems));
|
||||
_blocRole.add(FilterUsersByJobEvent(
|
||||
selectedJob: selectedItems,
|
||||
sortOrder: _blocRole.currentSortOrder,
|
||||
));
|
||||
},
|
||||
onSortAtoZ: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameAsc());
|
||||
onSortAtoZ: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
},
|
||||
onSortZtoA: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameDesc());
|
||||
onSortZtoA: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (columnIndex == 3) {
|
||||
final Map<String, bool> checkboxStates = {
|
||||
for (var item in _blocRole.roleTypes)
|
||||
@ -263,32 +263,31 @@ class UsersPage extends StatelessWidget {
|
||||
list: _blocRole.roleTypes,
|
||||
context: context,
|
||||
checkboxStates: checkboxStates,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
onOkPressed: () {
|
||||
_blocRole.add(FilterClearEvent());
|
||||
final selectedItems = checkboxStates.entries
|
||||
.where((entry) => entry.value)
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
Navigator.of(context).pop();
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(FilterUsersByRoleEvent(selectedItems));
|
||||
context.read<UserTableBloc>().add(
|
||||
FilterUsersByRoleEvent(
|
||||
selectedRoles: selectedItems,
|
||||
sortOrder: _blocRole.currentSortOrder));
|
||||
},
|
||||
onSortAtoZ: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameAsc());
|
||||
onSortAtoZ: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
},
|
||||
onSortZtoA: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameDesc());
|
||||
onSortZtoA: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
},
|
||||
);
|
||||
}
|
||||
if (columnIndex == 4) {
|
||||
showDateFilterMenu(
|
||||
context: context,
|
||||
isSelected: _blocRole.currentSortOrderDate,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
aToZTap: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
@ -319,32 +318,30 @@ class UsersPage extends StatelessWidget {
|
||||
list: _blocRole.createdBy,
|
||||
context: context,
|
||||
checkboxStates: checkboxStates,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
onOkPressed: () {
|
||||
_blocRole.add(FilterClearEvent());
|
||||
final selectedItems = checkboxStates.entries
|
||||
.where((entry) => entry.value)
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
Navigator.of(context).pop();
|
||||
_blocRole
|
||||
.add(FilterUsersByCreatedEvent(selectedItems));
|
||||
_blocRole.add(FilterUsersByCreatedEvent(
|
||||
selectedCreatedBy: selectedItems,
|
||||
sortOrder: _blocRole.currentSortOrder));
|
||||
},
|
||||
onSortAtoZ: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameAsc());
|
||||
onSortAtoZ: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
},
|
||||
onSortZtoA: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameDesc());
|
||||
onSortZtoA: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (columnIndex == 7) {
|
||||
final Map<String, bool> checkboxStates = {
|
||||
for (var item in _blocRole.status)
|
||||
item: _blocRole.selectedCreatedBy.contains(item),
|
||||
item: _blocRole.selectedStatuses.contains(item),
|
||||
};
|
||||
final RenderBox overlay = Overlay.of(context)
|
||||
.context
|
||||
@ -359,24 +356,24 @@ class UsersPage extends StatelessWidget {
|
||||
list: _blocRole.status,
|
||||
context: context,
|
||||
checkboxStates: checkboxStates,
|
||||
isSelected: _blocRole.currentSortOrder,
|
||||
onOkPressed: () {
|
||||
_blocRole.add(FilterClearEvent());
|
||||
|
||||
final selectedItems = checkboxStates.entries
|
||||
.where((entry) => entry.value)
|
||||
.map((entry) => entry.key)
|
||||
.toList();
|
||||
Navigator.of(context).pop();
|
||||
_blocRole
|
||||
.add(FilterUsersByCreatedEvent(selectedItems));
|
||||
_blocRole.add(FilterUsersByDeActevateEvent(
|
||||
selectedActivate: selectedItems,
|
||||
sortOrder: _blocRole.currentSortOrder));
|
||||
},
|
||||
onSortAtoZ: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameAsc());
|
||||
onSortAtoZ: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
},
|
||||
onSortZtoA: () {
|
||||
context
|
||||
.read<UserTableBloc>()
|
||||
.add(const SortUsersByNameDesc());
|
||||
onSortZtoA: (v) {
|
||||
_blocRole.currentSortOrder = v;
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -412,8 +409,8 @@ class UsersPage extends StatelessWidget {
|
||||
rows: state.users.map((user) {
|
||||
return [
|
||||
Text('${user.firstName} ${user.lastName}'),
|
||||
Text(user.email ),
|
||||
Text(user.jobTitle ?? ''),
|
||||
Text(user.email),
|
||||
Text(user.jobTitle ?? '-'),
|
||||
Text(user.roleType ?? ''),
|
||||
Text(user.createdDate ?? ''),
|
||||
Text(user.createdTime ?? ''),
|
||||
@ -476,11 +473,17 @@ class UsersPage extends StatelessWidget {
|
||||
barrierDismissible: false,
|
||||
builder: (BuildContext context) {
|
||||
return DeleteUserDialog(
|
||||
onTapDelete: () {
|
||||
onTapDelete: () async {
|
||||
try {
|
||||
_blocRole.add(DeleteUserEvent(
|
||||
user.uuid, context));
|
||||
},
|
||||
);
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 2));
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
).then((v) {
|
||||
if (v != null) {
|
||||
@ -504,6 +507,7 @@ class UsersPage extends StatelessWidget {
|
||||
SizedBox(
|
||||
width: 500,
|
||||
child: NumberPagination(
|
||||
visiblePagesCount: 4,
|
||||
buttonRadius: 10,
|
||||
selectedButtonColor: ColorsManager.secondaryColor,
|
||||
buttonUnSelectedBorderColor:
|
||||
|
||||
@ -12,4 +12,33 @@ class HomeApi {
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
Future fetchTerms() async {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.terms,
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json['data'];
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
Future fetchPolicy() async {
|
||||
final response = await HTTPService().get(
|
||||
path: ApiEndpoints.policy,
|
||||
showServerMessage: true,
|
||||
expectedResponseModel: (json) {
|
||||
return json['data'];
|
||||
});
|
||||
return response;
|
||||
}
|
||||
|
||||
Future confirmUserAgreements(uuid) async {
|
||||
final response = await HTTPService().patch(
|
||||
path: ApiEndpoints.userAgreements.replaceAll('{userUuid}', uuid!),
|
||||
expectedResponseModel: (json) {
|
||||
return json['data'];
|
||||
});
|
||||
return response;
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,8 +71,8 @@ class UserPermissionApi {
|
||||
"firstName": firstName,
|
||||
"lastName": lastName,
|
||||
"email": email,
|
||||
"jobTitle": jobTitle != '' ? jobTitle : " ",
|
||||
"phoneNumber": phoneNumber != '' ? phoneNumber : " ",
|
||||
"jobTitle": jobTitle != '' ? jobTitle : null,
|
||||
"phoneNumber": phoneNumber != '' ? phoneNumber : null,
|
||||
"roleUuid": roleUuid,
|
||||
"projectUuid": "0e62577c-06fa-41b9-8a92-99a21fbaf51c",
|
||||
"spaceUuids": spaceUuids,
|
||||
@ -119,13 +119,8 @@ class UserPermissionApi {
|
||||
);
|
||||
return response ?? 'Unknown error occurred';
|
||||
} on DioException catch (e) {
|
||||
if (e.response != null) {
|
||||
final errorMessage = e.response?.data['error'];
|
||||
return errorMessage is String
|
||||
? errorMessage
|
||||
: 'Error occurred while checking email';
|
||||
}
|
||||
return 'Error occurred while checking email';
|
||||
final errorMessage = e.response?.data['error'];
|
||||
return errorMessage;
|
||||
} catch (e) {
|
||||
return e.toString();
|
||||
}
|
||||
|
||||
@ -108,6 +108,7 @@ abstract class ApiEndpoints {
|
||||
static const String deleteUser = '/invite-user/{inviteUserUuid}';
|
||||
static const String changeUserStatus =
|
||||
'/invite-user/{invitedUserUuid}/disable';
|
||||
|
||||
// static const String updateAutomation = '/automation/{automationId}';
|
||||
static const String terms = '/terms';
|
||||
static const String policy = '/policy';
|
||||
static const String userAgreements = '/user/agreements/web/{userUuid}';
|
||||
}
|
||||
|
||||
@ -7,9 +7,13 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
|
||||
#include <url_launcher_linux/url_launcher_plugin.h>
|
||||
|
||||
void fl_register_plugins(FlPluginRegistry* registry) {
|
||||
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
|
||||
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
|
||||
g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar =
|
||||
fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin");
|
||||
url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar);
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
flutter_secure_storage_linux
|
||||
url_launcher_linux
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
@ -8,9 +8,11 @@ import Foundation
|
||||
import flutter_secure_storage_macos
|
||||
import path_provider_foundation
|
||||
import shared_preferences_foundation
|
||||
import url_launcher_macos
|
||||
|
||||
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
|
||||
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
|
||||
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
|
||||
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
|
||||
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
|
||||
}
|
||||
|
||||
@ -54,6 +54,8 @@ dependencies:
|
||||
time_picker_spinner: ^1.0.0
|
||||
intl_phone_field: ^3.2.0
|
||||
number_pagination: ^1.1.6
|
||||
url_launcher: ^6.2.5
|
||||
flutter_html: ^3.0.0-beta.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
@ -7,8 +7,11 @@
|
||||
#include "generated_plugin_registrant.h"
|
||||
|
||||
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
|
||||
#include <url_launcher_windows/url_launcher_windows.h>
|
||||
|
||||
void RegisterPlugins(flutter::PluginRegistry* registry) {
|
||||
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
|
||||
UrlLauncherWindowsRegisterWithRegistrar(
|
||||
registry->GetRegistrarForPlugin("UrlLauncherWindows"));
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
|
||||
list(APPEND FLUTTER_PLUGIN_LIST
|
||||
flutter_secure_storage_windows
|
||||
url_launcher_windows
|
||||
)
|
||||
|
||||
list(APPEND FLUTTER_FFI_PLUGIN_LIST
|
||||
|
||||
Reference in New Issue
Block a user