Pagination, ListView
This commit is contained in:
parent
1999e63c0f
commit
94d2a730fb
@ -13,6 +13,9 @@ import '../../routes/custom_appBar.dart';
|
||||
import '../../routes/custom_drawer.dart';
|
||||
import '../../services/apiService.dart';
|
||||
import '../../utils/auth_utils.dart';
|
||||
import '../../utils/pagination.dart';
|
||||
import '../../widgets/custom_popup.dart';
|
||||
import '../../widgets/popup_listPlan_action.dart';
|
||||
|
||||
class ListAllPlans extends StatefulWidget {
|
||||
const ListAllPlans({super.key});
|
||||
@ -25,7 +28,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
int currentPage = 0;
|
||||
int itemsPerPage = 8;
|
||||
int itemsPerPage = 10;
|
||||
|
||||
String? userId;
|
||||
String? orgId;
|
||||
@ -158,12 +161,14 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
Future<List<Plan>> fetchPlans() async {
|
||||
late String apiUrldata;
|
||||
|
||||
if (roleUser == "Org Admin") {
|
||||
apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
|
||||
} else {
|
||||
apiUrldata =
|
||||
'$apiUrl/api/plans/findTravelAgentPlanList?org_id=$orgId&user_id=$userId';
|
||||
}
|
||||
apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
|
||||
|
||||
// if (roleUser == "Org Admin") {
|
||||
// apiUrldata = '$apiUrl/api/plans?org_id=$orgId';
|
||||
// } else {
|
||||
// apiUrldata =
|
||||
// '$apiUrl/api/plans/findTravelAgentPlanList?org_id=$orgId&user_id=$userId';
|
||||
// }
|
||||
|
||||
if (token == null) {
|
||||
throw Exception('Token not found. Please log in.');
|
||||
@ -238,10 +243,12 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
// backgroundColor: Color(0xFFFCFCFC),
|
||||
|
||||
// appBar: isDesktop ? null : const CustomAppBar(title: 'Home'),
|
||||
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
@ -251,7 +258,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(8),
|
||||
: EdgeInsets.all(0),
|
||||
child: Row(
|
||||
children: [
|
||||
// if (isDesktop) CustomDrawer(isDesktop: true),
|
||||
@ -266,13 +273,14 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
Widget buildGroupListLayout(bool isDesktop) {
|
||||
return Container(
|
||||
// decoration: BoxDecoration(
|
||||
// // color: Colors.amber,
|
||||
// // color: bodyColor,
|
||||
// color: Color(0xFFE1F5FE),
|
||||
// border: Border.all(
|
||||
// // color: Color(0xFFF7F7FB),
|
||||
// color: Colors.white,
|
||||
// width: 3.5)),
|
||||
// color: Colors.amber,
|
||||
// // color: bodyColor,
|
||||
// // color: Color(0xFFE1F5FE),
|
||||
// // border: Border.all(
|
||||
// // // color: Color(0xFFF7F7FB),
|
||||
// // color: Colors.white,
|
||||
// // width: 3.5)
|
||||
// ),
|
||||
child: buildTableLayout(isDesktop),
|
||||
);
|
||||
}
|
||||
@ -288,10 +296,8 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: isDesktop
|
||||
? EdgeInsets.all(10.0)
|
||||
: EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||
// padding: const EdgeInsets.all(10),
|
||||
margin: isDesktop ? EdgeInsets.all(10.0) : null,
|
||||
padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20),
|
||||
height: isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
@ -325,7 +331,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text('All Trip List',
|
||||
const Text('All Trips',
|
||||
style: TextStyle(
|
||||
fontFamily: "Inter",
|
||||
fontSize: 16,
|
||||
@ -334,43 +340,46 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
],
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
width: 1,
|
||||
),
|
||||
Spacer(),
|
||||
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
size: 18,
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
size: 18,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
),
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide:
|
||||
BorderSide(color: Colors.grey.shade300, width: 1),
|
||||
),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// SizedBox(width: 16),
|
||||
|
||||
@ -396,69 +405,110 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
// ),
|
||||
// ),
|
||||
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Color(0xFF114D8B),
|
||||
foregroundColor: Colors.white,
|
||||
disabledBackgroundColor: Color(0xFF114D8B),
|
||||
disabledForegroundColor: Colors.white,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
),
|
||||
padding:
|
||||
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
),
|
||||
onPressed: () {
|
||||
if (TripPlanAction == "Plan Creation Not Allowed") {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(
|
||||
"Action Not Allowed",
|
||||
style: TextStyle(
|
||||
fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
content: Text(
|
||||
"Plan Creation Not Allowed For This User."),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context),
|
||||
child: Text(
|
||||
"OK",
|
||||
style: TextStyle(color: layoutColor),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
} else {
|
||||
context.go('/createPlan', extra: {
|
||||
'orgId': orgId,
|
||||
});
|
||||
if (!isDesktop) Navigator.pop(context);
|
||||
}
|
||||
},
|
||||
child: Row(
|
||||
mainAxisSize:
|
||||
MainAxisSize.min, // Ensures content fits nicely
|
||||
children: [
|
||||
Text(
|
||||
"Add New Plan",
|
||||
style: TextStyle(fontSize: 13),
|
||||
),
|
||||
SizedBox(width: 8), // spacing between icon and text
|
||||
Icon(
|
||||
Icons.add_circle_outline_rounded,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// ElevatedButton(
|
||||
// style: ElevatedButton.styleFrom(
|
||||
// backgroundColor: Color(0xFF114D8B),
|
||||
// foregroundColor: Colors.white,
|
||||
// disabledBackgroundColor: Color(0xFF114D8B),
|
||||
// disabledForegroundColor: Colors.white,
|
||||
// shape: RoundedRectangleBorder(
|
||||
// borderRadius: BorderRadius.circular(8),
|
||||
// side: BorderSide(color: Color(0xFF114D8B), width: 2),
|
||||
// ),
|
||||
// padding:
|
||||
// EdgeInsets.symmetric(horizontal: 20, vertical: 12),
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// if (TripPlanAction == "Plan Creation Not Allowed") {
|
||||
// showDialog(
|
||||
// context: context,
|
||||
// builder: (context) => AlertDialog(
|
||||
// title: Text(
|
||||
// "Action Not Allowed",
|
||||
// style: TextStyle(
|
||||
// fontSize: 18, fontWeight: FontWeight.bold),
|
||||
// ),
|
||||
// content: Text(
|
||||
// "Plan Creation Not Allowed For This User."),
|
||||
// actions: [
|
||||
// TextButton(
|
||||
// onPressed: () => Navigator.pop(context),
|
||||
// child: Text(
|
||||
// "OK",
|
||||
// style: TextStyle(color: layoutColor),
|
||||
// ),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
// } else {
|
||||
// context.go('/createPlan', extra: {
|
||||
// 'orgId': orgId,
|
||||
// });
|
||||
// if (!isDesktop) Navigator.pop(context);
|
||||
// }
|
||||
// },
|
||||
// child: Row(
|
||||
// mainAxisSize:
|
||||
// MainAxisSize.min, // Ensures content fits nicely
|
||||
// children: [
|
||||
// Text(
|
||||
// "Add New Plan",
|
||||
// style: TextStyle(fontSize: 13),
|
||||
// ),
|
||||
// SizedBox(width: 8), // spacing between icon and text
|
||||
// Icon(
|
||||
// Icons.add_circle_outline_rounded,
|
||||
// size: 15,
|
||||
// color: Colors.white,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
|
||||
if (!isDesktop)
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.85,
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
size: 18,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
FutureBuilder<List<Plan>>(
|
||||
future: futurePlans,
|
||||
builder: (context, snapshot) {
|
||||
@ -475,25 +525,27 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
children: const [
|
||||
Icon(Icons.error_outline,
|
||||
color: Colors.redAccent, size: 60),
|
||||
SizedBox(height: 16),
|
||||
SizedBox(height: 1),
|
||||
Text("Oops!",
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.redAccent)),
|
||||
SizedBox(height: 8),
|
||||
Text("No Plans Available For This User",
|
||||
SizedBox(height: 15),
|
||||
Text("No Trips",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey)),
|
||||
SizedBox(height: 20),
|
||||
Text("Please Create Plan",
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black54)),
|
||||
SizedBox(height: 10),
|
||||
Text("Please Create Trip",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16, color: Colors.grey)),
|
||||
SizedBox(height: 20),
|
||||
fontFamily: "Inter",
|
||||
fontSize: 12,
|
||||
color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -535,15 +587,15 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Employee Code',
|
||||
label: Text('Trip Name',
|
||||
style: TextStyle(
|
||||
// color: Color(0xFF9E9DBD),
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Trip Name',
|
||||
label: Text('Employee Code',
|
||||
style: TextStyle(
|
||||
// color: Color(0xFF9E9DBD),
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
@ -585,11 +637,6 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(plan.employeeCode ?? "no data",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(plan.tripTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
@ -597,6 +644,11 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
DataCell(Text(plan.employeeCode ?? "no data",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(
|
||||
plan.userName.isNotEmpty
|
||||
? plan.userName
|
||||
@ -624,16 +676,6 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: getStatusColor(plan.statusValue),
|
||||
// color: plan.statusValue ==
|
||||
// "Partially Approved"
|
||||
// ? Colors.yellow.shade100
|
||||
// : plan.statusValue == "Approved"
|
||||
// ? Colors.green.shade100
|
||||
// : plan.statusValue == "Completed"
|
||||
// ? Colors.green.shade500
|
||||
// : plan.statusValue == "Rejected"
|
||||
// ? Colors.red.shade100
|
||||
// : Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
@ -642,14 +684,6 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
style: TextStyle(
|
||||
color:
|
||||
getStatusTextColor(plan.statusValue),
|
||||
// color: (plan.statusValue ==
|
||||
// "Partially Approved" ||
|
||||
// plan.statusValue == "Approved" ||
|
||||
// plan.statusValue == "Rejected")
|
||||
// ? Colors.black
|
||||
// : plan.statusValue == "Completed"
|
||||
// ? Colors.white
|
||||
// : Colors.grey,
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w400,
|
||||
@ -657,45 +691,77 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(Row(children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.remove_red_eye,
|
||||
color: Color(0xFF475569),
|
||||
size: 18,
|
||||
DataCell(
|
||||
PopupMenuButton<int>(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.zero,
|
||||
offset: Offset(0, 30),
|
||||
icon: Icon(
|
||||
Icons.more_vert,
|
||||
color: Color(0xFF475569),
|
||||
size: 14,
|
||||
),
|
||||
itemBuilder: (context) => [
|
||||
CustomPopupMenuEntry(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 8),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.remove_red_eye,
|
||||
color: Color(0xFF475569),
|
||||
size: 18),
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context); // Close popup manually
|
||||
ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: true);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: false);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
deletePlan(plan.planId);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.download,
|
||||
color: Color(0xFF114D8B),
|
||||
size: 18),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
apiService.getPdfDownload(
|
||||
plan.planId);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: () => ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: true)),
|
||||
GestureDetector(
|
||||
onTap: () => ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: false),
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
],
|
||||
),
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => deletePlan(plan.planId),
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.download,
|
||||
color: Color(0xFF475569),
|
||||
size: 18,
|
||||
),
|
||||
onPressed: () {
|
||||
apiService.getPdfDownload(plan.planId);
|
||||
}),
|
||||
])),
|
||||
),
|
||||
]);
|
||||
}).toList(),
|
||||
),
|
||||
@ -703,66 +769,148 @@ class _ListAllPlansState extends State<ListAllPlans> {
|
||||
},
|
||||
);
|
||||
|
||||
Widget buildMobileCardView(List<Plan> paginatedPlans) {
|
||||
return ListView.builder(
|
||||
itemCount: paginatedPlans.length,
|
||||
itemBuilder: (context, index) {
|
||||
final plan = paginatedPlans[index];
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin:
|
||||
EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 3,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Status and Employee Code
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: getStatusColor(plan.statusValue),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
plan.statusValue,
|
||||
style: TextStyle(
|
||||
color: getStatusTextColor(
|
||||
plan.statusValue),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
PlanPopupMenu(
|
||||
plan: plan,
|
||||
deletePlan: deletePlan,
|
||||
apiService: apiService,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
// Name
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
plan.employeeCode ?? 'No Data',
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontFamily: "Inter"),
|
||||
),
|
||||
Text(
|
||||
plan.userName.isNotEmpty
|
||||
? plan.userName
|
||||
: plan.travellerName,
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontFamily: "Inter"),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
// Trip Id and Trip Name
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text('${plan.tripTitle}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.bold)),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 2),
|
||||
// Type and Created On
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text('${plan.tripType}',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
Expanded(
|
||||
child:
|
||||
Text('${_formatDate(plan.createdOn)}',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Actions
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
isDesktop
|
||||
? table
|
||||
: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SingleChildScrollView(
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
? SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: table,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
// Previous button with arrow icon
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.arrow_back_ios_new,
|
||||
size: 10,
|
||||
),
|
||||
onPressed: currentPage > 0
|
||||
? () {
|
||||
setState(() {
|
||||
currentPage--;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
|
||||
// Page number text
|
||||
Text(
|
||||
'Page ${currentPage + 1}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
|
||||
// Next button with arrow icon
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 10,
|
||||
),
|
||||
onPressed: (currentPage + 1) * itemsPerPage <
|
||||
plans.length
|
||||
? () {
|
||||
setState(() {
|
||||
currentPage++;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
],
|
||||
child: table, // <-- your existing table
|
||||
)
|
||||
: buildMobileCardView(paginatedPlans),
|
||||
),
|
||||
PaginationControls(
|
||||
currentPage: currentPage,
|
||||
itemsPerPage: itemsPerPage,
|
||||
totalItems: plans.length,
|
||||
activeColor: layoutColor, // your theme color
|
||||
onPageChanged: (page) {
|
||||
setState(() {
|
||||
currentPage = page;
|
||||
});
|
||||
},
|
||||
onItemsPerPageChanged: (items) {
|
||||
setState(() {
|
||||
itemsPerPage = items;
|
||||
currentPage = 0;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
933
lib/Screens/allTrips/travel_agent_list.dart
Normal file
933
lib/Screens/allTrips/travel_agent_list.dart
Normal file
@ -0,0 +1,933 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:core';
|
||||
import 'package:frontend/data/models/plan.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:frontend/config/apiUrl.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:responsive_builder/responsive_builder.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import '../../routes/custom_appBar.dart';
|
||||
import '../../routes/custom_drawer.dart';
|
||||
import '../../services/apiService.dart';
|
||||
import '../../utils/auth_utils.dart';
|
||||
import '../../utils/pagination.dart';
|
||||
import '../../widgets/custom_popup.dart';
|
||||
import '../../widgets/popup_listPlan_action.dart';
|
||||
|
||||
class TravelAgentListPlans extends StatefulWidget {
|
||||
const TravelAgentListPlans({super.key});
|
||||
|
||||
@override
|
||||
_TravelAgentListPlansState createState() => _TravelAgentListPlansState();
|
||||
}
|
||||
|
||||
class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
int currentPage = 0;
|
||||
int itemsPerPage = 10;
|
||||
|
||||
String? userId;
|
||||
String? orgId;
|
||||
String? roleUser;
|
||||
String? token;
|
||||
String? TripPlanAction;
|
||||
|
||||
Color? layoutColor;
|
||||
Color? bodyColor;
|
||||
late Future<List<Plan>> futurePlans;
|
||||
List<Plan> allPlans = [];
|
||||
List<Plan> filteredPlans = [];
|
||||
TextEditingController searchController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
getToken();
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
initializeData();
|
||||
loadInitialData();
|
||||
|
||||
// futurePlans.then((plans) {
|
||||
// setState(() {
|
||||
// allPlans = plans;
|
||||
// filteredPlans = plans;
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
||||
// futurePlans = fetchPlans();
|
||||
}
|
||||
|
||||
void filterPlans(String query) {
|
||||
print("allPlans before filtering: $allPlans");
|
||||
final lowerQuery = query.toLowerCase();
|
||||
setState(() {
|
||||
filteredPlans = allPlans.where((plan) {
|
||||
return (plan.planId?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.employeeCode?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.tripTitle?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.userName?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.travellerName?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.tripType?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.createdOn?.toLowerCase().contains(lowerQuery) ?? false) ||
|
||||
(plan.statusValue?.toLowerCase().contains(lowerQuery) ?? false);
|
||||
}).toList();
|
||||
});
|
||||
print("filteredPlans: $filteredPlans");
|
||||
}
|
||||
|
||||
void loadInitialData() async {
|
||||
String? layoutString = await getLayoutColor();
|
||||
String? bodyStringColor = await getBodyColor();
|
||||
|
||||
setState(() {
|
||||
layoutColor = layoutString != null
|
||||
? Color(int.parse(layoutString))
|
||||
: Colors.redAccent;
|
||||
|
||||
bodyColor = bodyStringColor != null
|
||||
? Color(int.parse(bodyStringColor))
|
||||
: Colors.white;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> initializeData() async {
|
||||
token = await getToken();
|
||||
userId = await getUserId();
|
||||
orgId = await getOrgId();
|
||||
roleUser = await getRoleUser();
|
||||
TripPlanAction = await getTripPlanAction();
|
||||
|
||||
if (token == null || userId == null) {
|
||||
print("Token or USerId missing");
|
||||
return;
|
||||
} else {
|
||||
setState(() {
|
||||
futurePlans = fetchPlans();
|
||||
});
|
||||
|
||||
// Wait for futurePlans to be fetched and update allPlans
|
||||
futurePlans.then((plans) {
|
||||
setState(() {
|
||||
allPlans = plans; // Set allPlans after the fetch is complete
|
||||
filteredPlans =
|
||||
allPlans; // You can update filteredPlans too if needed
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<String?> getUserId() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final String? userDataString = prefs.getString('user_data');
|
||||
|
||||
if (userDataString != null) {
|
||||
try {
|
||||
final Map<String, dynamic> userData = jsonDecode(userDataString);
|
||||
return userData["user_id"]?.toString();
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String?> getOrgId() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
final String? userDataString = prefs.getString('user_data');
|
||||
|
||||
if (userDataString != null) {
|
||||
try {
|
||||
final Map<String, dynamic> userData = jsonDecode(userDataString);
|
||||
return userData["org_id"]?.toString();
|
||||
} catch (e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<String?> getToken() async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString('auth_token');
|
||||
}
|
||||
|
||||
// Fetch API Data
|
||||
Future<List<Plan>> fetchPlans() async {
|
||||
late String apiUrldata;
|
||||
|
||||
apiUrldata =
|
||||
'$apiUrl/api/plans/findTravelAgentPlanList?org_id=$orgId&user_id=$userId';
|
||||
|
||||
if (token == null) {
|
||||
throw Exception('Token not found. Please log in.');
|
||||
}
|
||||
|
||||
final response = await http.get(
|
||||
Uri.parse(apiUrldata),
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token', // Add token here
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
List<dynamic> plansJson = data['data'];
|
||||
return plansJson.map((json) => Plan.fromJson(json)).toList();
|
||||
} else {
|
||||
throw Exception('Failed to load plans');
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> postPlanData(planData, planId) async {
|
||||
final String apiUrldata = '$apiUrl/api/plans/createOrEditPlan';
|
||||
|
||||
final token = await getToken(); // Fetch token
|
||||
|
||||
if (token == null) {
|
||||
throw Exception('Token not found. Please log in.');
|
||||
}
|
||||
|
||||
planData['is_active'] = "0";
|
||||
|
||||
print("POSTPlanTesting------- $planData"); // Add plan_id for update
|
||||
|
||||
try {
|
||||
final response = await http.post(
|
||||
Uri.parse(apiUrldata),
|
||||
headers: {
|
||||
'Authorization': 'Bearer $token',
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: jsonEncode(planData), // Convert map to JSON
|
||||
);
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
print("Plan Deleted successfully!");
|
||||
print("Response: ${response.body}");
|
||||
initializeData();
|
||||
} else {
|
||||
print("Failed to submit plan. Status: ${response.statusCode}");
|
||||
print("Error: ${response.body}");
|
||||
}
|
||||
} catch (e) {
|
||||
print(" Error submitting plan: $e");
|
||||
}
|
||||
}
|
||||
|
||||
void deletePlan(String planId) async {
|
||||
try {
|
||||
Map<String, dynamic> planData = await ApiService.getViewPlan(planId);
|
||||
print("ViewAAA - $planData");
|
||||
|
||||
postPlanData(planData, planId);
|
||||
} catch (e) {
|
||||
print("Error fetching plan: $e");
|
||||
}
|
||||
}
|
||||
|
||||
Widget build(BuildContext context) {
|
||||
return ResponsiveBuilder(builder: (context, sizingInfo) {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
// appBar: isDesktop ? null : const CustomAppBar(title: 'Home'),
|
||||
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
? EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width *
|
||||
0.1, // 30% of screen width as horizontal padding
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(0),
|
||||
child: Row(
|
||||
children: [
|
||||
// if (isDesktop) CustomDrawer(isDesktop: true),
|
||||
Expanded(child: buildGroupListLayout(isDesktop))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget buildGroupListLayout(bool isDesktop) {
|
||||
return Container(
|
||||
// decoration: BoxDecoration(
|
||||
// // color: Colors.amber,
|
||||
// // color: bodyColor,
|
||||
// color: Color(0xFFE1F5FE),
|
||||
// border: Border.all(
|
||||
// // color: Color(0xFFF7F7FB),
|
||||
// color: Colors.white,
|
||||
// width: 3.5)),
|
||||
child: buildTableLayout(isDesktop),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildTableLayout(isDesktop) {
|
||||
String _formatDate(String rawDate) {
|
||||
try {
|
||||
final dateTime = DateTime.parse(rawDate);
|
||||
return DateFormat('dd MMM yy hh:m a').format(dateTime);
|
||||
} catch (e) {
|
||||
return rawDate; // fallback if parsing fails
|
||||
}
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: isDesktop ? EdgeInsets.all(10.0) : null,
|
||||
padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20),
|
||||
height: isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
decoration: BoxDecoration(
|
||||
border: isDesktop
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: Colors.white,
|
||||
// color: Color(0xFFF7F7FB),
|
||||
)
|
||||
: null,
|
||||
color: Colors.white,
|
||||
// color: Color(0xFFF7F7FB),
|
||||
|
||||
// color: Colors.amber,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(1.0),
|
||||
child: Container(
|
||||
// padding: const EdgeInsets.all(10.0),
|
||||
color: Colors.white,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Divider(
|
||||
// thickness: 0.2, // how "thick" the line is
|
||||
// color: Colors.grey, // optional
|
||||
// ),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text('My Trips',
|
||||
style: TextStyle(
|
||||
fontFamily: "Inter",
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Color(0xFF212121))),
|
||||
],
|
||||
),
|
||||
|
||||
Spacer(),
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
size: 18,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// SizedBox(width: 16),
|
||||
|
||||
Spacer(),
|
||||
// ElevatedButton(
|
||||
// style: ElevatedButton.styleFrom(
|
||||
// foregroundColor: Colors.white,
|
||||
// backgroundColor: Colors.blueAccent,
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// context.go('/createPlan', extra: {
|
||||
// 'orgId': orgId,
|
||||
// });
|
||||
// if (!isDesktop) Navigator.pop(context);
|
||||
// },
|
||||
// child: Row(
|
||||
// children: [
|
||||
// Icon(Icons.add_circle, color: Colors.white),
|
||||
// SizedBox(width: 5),
|
||||
// Text('NewPlan'),
|
||||
//
|
||||
// ],
|
||||
// ),
|
||||
// ),
|
||||
],
|
||||
),
|
||||
if (!isDesktop) const SizedBox(height: 10),
|
||||
if (!isDesktop)
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.85,
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
size: 18,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
FutureBuilder<List<Plan>>(
|
||||
future: futurePlans,
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return const Center(child: CircularProgressIndicator());
|
||||
} else if (snapshot.hasError ||
|
||||
!snapshot.hasData ||
|
||||
snapshot.data!.isEmpty) {
|
||||
return Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: const [
|
||||
SizedBox(height: 20),
|
||||
Icon(Icons.error_outline,
|
||||
color: Colors.redAccent, size: 60),
|
||||
SizedBox(height: 1),
|
||||
Text("Oops!",
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.redAccent)),
|
||||
SizedBox(height: 20),
|
||||
Text("No Approvals",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black54)),
|
||||
SizedBox(height: 10),
|
||||
// Text("Please Create Trip",
|
||||
// textAlign: TextAlign.center,
|
||||
// style: TextStyle(
|
||||
// fontFamily: "Inter",
|
||||
// fontSize: 12,
|
||||
// color: Colors.grey)),
|
||||
// SizedBox(height: 20),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// List<Plan> plans = snapshot.data!;
|
||||
|
||||
List<Plan> plans =
|
||||
filteredPlans.isNotEmpty ? filteredPlans : allPlans;
|
||||
plans.sort((a, b) =>
|
||||
int.parse(b.planId).compareTo(int.parse(a.planId)));
|
||||
|
||||
List<Plan> paginatedPlans = plans
|
||||
.skip(currentPage * itemsPerPage)
|
||||
.take(itemsPerPage)
|
||||
.toList();
|
||||
|
||||
Widget table = LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
double minWidth = isDesktop ? constraints.maxWidth : 1300;
|
||||
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(minWidth: minWidth),
|
||||
child: DataTable(
|
||||
dividerThickness: 0.5,
|
||||
columnSpacing: isDesktop ? 24.0 : 16.0,
|
||||
border: TableBorder(
|
||||
horizontalInside: BorderSide(
|
||||
width: 0.5, color: Colors.grey.shade200),
|
||||
),
|
||||
columns: const [
|
||||
DataColumn(
|
||||
label: Text('Trip Id',
|
||||
style: TextStyle(
|
||||
// color: Colors.grey,
|
||||
// color: Color(0xFF9E9DBD),
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Trip Name',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Employee Code',
|
||||
style: TextStyle(
|
||||
// color: Color(0xFF9E9DBD),
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Traveller',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Trip Type',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Created On',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Status',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Actions',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
],
|
||||
rows: paginatedPlans.map((plan) {
|
||||
return DataRow(cells: [
|
||||
DataCell(Text(plan.planId,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
|
||||
DataCell(Text(plan.tripTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
|
||||
DataCell(Text(plan.employeeCode ?? "no data",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(
|
||||
plan.userName.isNotEmpty
|
||||
? plan.userName
|
||||
: plan.travellerName,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(plan.tripType,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(_formatDate(plan.createdOn),
|
||||
// plan.createdOn,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(
|
||||
Container(
|
||||
width: double
|
||||
.infinity, // Set your desired fixed size (equal width and height)
|
||||
height: 25,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: getStatusColor(plan.statusValue),
|
||||
// color: plan.statusValue ==
|
||||
// "Partially Approved"
|
||||
// ? Colors.yellow.shade100
|
||||
// : plan.statusValue == "Approved"
|
||||
// ? Colors.green.shade100
|
||||
// : plan.statusValue == "Completed"
|
||||
// ? Colors.green.shade500
|
||||
// : plan.statusValue == "Rejected"
|
||||
// ? Colors.red.shade100
|
||||
// : Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
),
|
||||
child: Text(
|
||||
plan.statusValue,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color:
|
||||
getStatusTextColor(plan.statusValue),
|
||||
// color: (plan.statusValue ==
|
||||
// "Partially Approved" ||
|
||||
// plan.statusValue == "Approved" ||
|
||||
// plan.statusValue == "Rejected")
|
||||
// ? Colors.black
|
||||
// : plan.statusValue == "Completed"
|
||||
// ? Colors.white
|
||||
// : Colors.grey,
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
DataCell(
|
||||
PopupMenuButton<int>(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.zero,
|
||||
offset: Offset(0, 30),
|
||||
icon: Icon(Icons.more_vert,
|
||||
color: Color(0xFF475569)),
|
||||
itemBuilder: (context) => [
|
||||
CustomPopupMenuEntry(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 8),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.remove_red_eye,
|
||||
color: Color(0xFF475569),
|
||||
size: 14),
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context); // Close popup manually
|
||||
ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: true);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: false);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
deletePlan(plan.planId);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.download,
|
||||
color: Color(0xFF114D8B),
|
||||
size: 18),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
apiService.getPdfDownload(
|
||||
plan.planId);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// DataCell(Row(children: [
|
||||
// IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.remove_red_eye,
|
||||
// color: Color(0xFF475569),
|
||||
// size: 18,
|
||||
// ),
|
||||
// onPressed: () => ApiService.viewPlan(
|
||||
// context, plan.planId,
|
||||
// isViewMode: true)),
|
||||
// GestureDetector(
|
||||
// onTap: () => ApiService.viewPlan(
|
||||
// context, plan.planId,
|
||||
// isViewMode: false),
|
||||
// child: Image.asset(
|
||||
// 'assets/images/IconsImg/edit.png',
|
||||
// width: 20,
|
||||
// height: 15),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: 5,
|
||||
// ),
|
||||
// GestureDetector(
|
||||
// onTap: () => deletePlan(plan.planId),
|
||||
// child: Image.asset(
|
||||
// 'assets/images/IconsImg/delete.png',
|
||||
// width: 20,
|
||||
// height: 15),
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.download,
|
||||
// color: Color(0xFF475569),
|
||||
// size: 18,
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// apiService.getPdfDownload(plan.planId);
|
||||
// }),
|
||||
// ])),
|
||||
]);
|
||||
}).toList(),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
Widget buildMobileCardView(List<Plan> paginatedPlans) {
|
||||
return ListView.builder(
|
||||
itemCount: paginatedPlans.length,
|
||||
itemBuilder: (context, index) {
|
||||
final plan = paginatedPlans[index];
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin:
|
||||
EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 3,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Status and Employee Code
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: getStatusColor(plan.statusValue),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
plan.statusValue,
|
||||
style: TextStyle(
|
||||
color: getStatusTextColor(
|
||||
plan.statusValue),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
PlanPopupMenu(
|
||||
plan: plan,
|
||||
deletePlan: deletePlan,
|
||||
apiService: apiService,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
// Name
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
plan.employeeCode ?? 'No Data',
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontFamily: "Inter"),
|
||||
),
|
||||
Text(
|
||||
plan.userName.isNotEmpty
|
||||
? plan.userName
|
||||
: plan.travellerName,
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontFamily: "Inter"),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
// Trip Id and Trip Name
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text('${plan.tripTitle}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.bold)),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 2),
|
||||
// Type and Created On
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text('${plan.tripType}',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
Expanded(
|
||||
child:
|
||||
Text('${_formatDate(plan.createdOn)}',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Actions
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
? SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: table, // <-- your existing table
|
||||
)
|
||||
: buildMobileCardView(paginatedPlans),
|
||||
),
|
||||
PaginationControls(
|
||||
currentPage: currentPage,
|
||||
itemsPerPage: itemsPerPage,
|
||||
totalItems: plans.length,
|
||||
activeColor: layoutColor, // your theme color
|
||||
onPageChanged: (page) {
|
||||
setState(() {
|
||||
currentPage = page;
|
||||
});
|
||||
},
|
||||
onItemsPerPageChanged: (items) {
|
||||
setState(() {
|
||||
itemsPerPage = items;
|
||||
currentPage = 0;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Helper functions for colors
|
||||
Color getStatusColor(String status) {
|
||||
if (status == "Partially Approved") return Colors.yellow.shade100;
|
||||
if (status == "Approved") return Colors.green.shade100;
|
||||
if (status == "Completed") return Colors.green.shade500;
|
||||
if (status == "Rejected") return Colors.red.shade100;
|
||||
return Colors.grey.shade100;
|
||||
}
|
||||
|
||||
Color getStatusTextColor(String status) {
|
||||
if (status == "Partially Approved" ||
|
||||
status == "Approved" ||
|
||||
status == "Rejected") {
|
||||
return Colors.black;
|
||||
} else if (status == "Completed") {
|
||||
return Colors.white;
|
||||
}
|
||||
return Colors.grey;
|
||||
}
|
||||
}
|
||||
@ -13,6 +13,9 @@ import '../../routes/custom_appBar.dart';
|
||||
import '../../routes/custom_drawer.dart';
|
||||
import '../../services/apiService.dart';
|
||||
import '../../utils/auth_utils.dart';
|
||||
import '../../utils/pagination.dart';
|
||||
import '../../widgets/custom_popup.dart';
|
||||
import '../../widgets/popup_listPlan_action.dart';
|
||||
|
||||
class ApprovalList extends StatefulWidget {
|
||||
const ApprovalList({super.key});
|
||||
@ -32,7 +35,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
Color? bodyColor;
|
||||
|
||||
int currentPage = 0;
|
||||
int itemsPerPage = 8;
|
||||
int itemsPerPage = 10;
|
||||
List<Plan> allPlans = [];
|
||||
List<Plan> filteredPlans = [];
|
||||
TextEditingController searchController = TextEditingController();
|
||||
@ -296,10 +299,10 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
// appBar: isDesktop ? null : const CustomAppBar(title: 'Home'),
|
||||
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
@ -309,7 +312,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(8),
|
||||
: EdgeInsets.all(0),
|
||||
child: Row(
|
||||
children: [
|
||||
// if (isDesktop) CustomDrawer(isDesktop: true),
|
||||
@ -346,18 +349,28 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: isDesktop
|
||||
? EdgeInsets.all(10.0)
|
||||
: EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||
// padding: const EdgeInsets.all(10),
|
||||
margin: isDesktop ? EdgeInsets.all(10.0) : null,
|
||||
padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20),
|
||||
height: isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
decoration: BoxDecoration(
|
||||
border: isDesktop
|
||||
? Border.all(
|
||||
width: 2,
|
||||
color: Colors.white,
|
||||
// color: Color(0xFFF7F7FB),
|
||||
)
|
||||
: null,
|
||||
color: Colors.white,
|
||||
// color: Color(0xFFF7F7FB),
|
||||
|
||||
// color: Colors.amber,
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(1.0),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(1.0),
|
||||
// padding: const EdgeInsets.all(10.0),
|
||||
color: Colors.white,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
@ -370,7 +383,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text('List For Approval',
|
||||
const Text('My Approvals',
|
||||
style: TextStyle(
|
||||
fontFamily: "Inter",
|
||||
fontSize: 16,
|
||||
@ -439,7 +452,7 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search for a plan",
|
||||
hintText: "Search...",
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
prefixIcon: Icon(
|
||||
@ -488,25 +501,20 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
children: const [
|
||||
Icon(Icons.error_outline,
|
||||
color: Colors.redAccent, size: 60),
|
||||
SizedBox(height: 16),
|
||||
SizedBox(height: 1),
|
||||
Text("Oops!",
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.redAccent)),
|
||||
SizedBox(height: 8),
|
||||
Text("No Plans Available For This User",
|
||||
SizedBox(height: 15),
|
||||
Text("No Approvals",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey)),
|
||||
SizedBox(height: 20),
|
||||
Text("Please Create Plan",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16, color: Colors.grey)),
|
||||
SizedBox(height: 20),
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black54)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -637,30 +645,16 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
height: 25,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: plan.statusValue ==
|
||||
"Partially Approved"
|
||||
? Colors.yellow.shade100
|
||||
: plan.statusValue == "Approved"
|
||||
? Colors.green.shade100
|
||||
: plan.statusValue == "Completed"
|
||||
? Colors.green.shade500
|
||||
: plan.statusValue == "Rejected"
|
||||
? Colors.red.shade100
|
||||
: Colors.grey.shade100,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
color: getStatusColor(plan.statusValue),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
|
||||
child: Text(
|
||||
plan.statusValue,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: (plan.statusValue ==
|
||||
"Partially Approved" ||
|
||||
plan.statusValue == "Approved" ||
|
||||
plan.statusValue == "Rejected")
|
||||
? Colors.black
|
||||
: plan.statusValue == "Completed"
|
||||
? Colors.white
|
||||
: Colors.grey,
|
||||
color:
|
||||
getStatusTextColor(plan.statusValue),
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w400,
|
||||
@ -668,55 +662,127 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(Row(children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.remove_red_eye,
|
||||
color: Color(0xFF475569),
|
||||
size: 18,
|
||||
|
||||
DataCell(
|
||||
PopupMenuButton<int>(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.zero,
|
||||
offset: Offset(0, 30),
|
||||
icon: Icon(
|
||||
Icons.more_vert,
|
||||
color: Color(0xFF475569),
|
||||
size: 14,
|
||||
),
|
||||
itemBuilder: (context) => [
|
||||
CustomPopupMenuEntry(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 8),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.remove_red_eye,
|
||||
color: Color(0xFF475569),
|
||||
size: 18),
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context); // Close popup manually
|
||||
ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: true);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: false);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
deletePlan(plan.planId);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.download,
|
||||
color: Color(0xFF114D8B),
|
||||
size: 18),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
apiService.getPdfDownload(
|
||||
plan.planId);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: () => viewPlanforApprover(
|
||||
plan.planId,
|
||||
isViewMode: true,
|
||||
isApprover: true)),
|
||||
|
||||
GestureDetector(
|
||||
onTap: () => ApiService.viewPlanForApprover(
|
||||
context, plan.planId,
|
||||
isViewMode: false, isApprover: true),
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
],
|
||||
),
|
||||
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.edit,
|
||||
// color: Colors.green),
|
||||
// onPressed: () => viewPlanforApprover(plan.planId,
|
||||
// isViewMode: false) ),
|
||||
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => deletePlan(plan.planId),
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
),
|
||||
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.download,
|
||||
color: Color(0xFF475569),
|
||||
size: 18,
|
||||
),
|
||||
onPressed: () {
|
||||
apiService.getPdfDownload(plan.planId);
|
||||
}),
|
||||
])),
|
||||
),
|
||||
// DataCell(Row(children: [
|
||||
// IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.remove_red_eye,
|
||||
// color: Color(0xFF475569),
|
||||
// size: 18,
|
||||
// ),
|
||||
// onPressed: () => viewPlanforApprover(
|
||||
// plan.planId,
|
||||
// isViewMode: true,
|
||||
// isApprover: true)),
|
||||
//
|
||||
// GestureDetector(
|
||||
// onTap: () => ApiService.viewPlanForApprover(
|
||||
// context, plan.planId,
|
||||
// isViewMode: false, isApprover: true),
|
||||
// child: Image.asset(
|
||||
// 'assets/images/IconsImg/edit.png',
|
||||
// width: 20,
|
||||
// height: 15),
|
||||
// ),
|
||||
//
|
||||
// // IconButton(
|
||||
// // icon: const Icon(Icons.edit,
|
||||
// // color: Colors.green),
|
||||
// // onPressed: () => viewPlanforApprover(plan.planId,
|
||||
// // isViewMode: false) ),
|
||||
//
|
||||
// SizedBox(
|
||||
// width: 5,
|
||||
// ),
|
||||
// GestureDetector(
|
||||
// onTap: () => deletePlan(plan.planId),
|
||||
// child: Image.asset(
|
||||
// 'assets/images/IconsImg/delete.png',
|
||||
// width: 20,
|
||||
// height: 15),
|
||||
// ),
|
||||
//
|
||||
// IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.download,
|
||||
// color: Color(0xFF475569),
|
||||
// size: 18,
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// apiService.getPdfDownload(plan.planId);
|
||||
// }),
|
||||
// ])),
|
||||
]);
|
||||
}).toList(),
|
||||
),
|
||||
@ -724,66 +790,154 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
},
|
||||
);
|
||||
|
||||
Widget buildMobileCardView(List<Plan> paginatedPlans) {
|
||||
return ListView.builder(
|
||||
itemCount: paginatedPlans.length,
|
||||
itemBuilder: (context, index) {
|
||||
final plan = paginatedPlans[index];
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin:
|
||||
EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 3,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Status and Employee Code
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: getStatusColor(plan.statusValue),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
plan.statusValue,
|
||||
style: TextStyle(
|
||||
color: getStatusTextColor(
|
||||
plan.statusValue),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
PlanPopupMenu(
|
||||
plan: plan,
|
||||
deletePlan: deletePlan,
|
||||
apiService: apiService,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
// Name
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
plan.employeeCode ?? 'No Data',
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontFamily: "Inter"),
|
||||
),
|
||||
Text(
|
||||
plan.userName.isNotEmpty
|
||||
? plan.userName
|
||||
: plan.travellerName,
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontFamily: "Inter"),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
// Trip Id and Trip Name
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text('${plan.tripTitle}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.bold)),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 2),
|
||||
// Type and Created On
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text('${plan.tripType}',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
Expanded(
|
||||
child:
|
||||
Text('${_formatDate(plan.createdOn)}',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Actions
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
isDesktop
|
||||
? table
|
||||
: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SingleChildScrollView(
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
? SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: table,
|
||||
child: table, // <-- your existing table
|
||||
)
|
||||
: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: table,
|
||||
),
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
// Previous button with arrow icon
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.arrow_back_ios_new,
|
||||
size: 10,
|
||||
),
|
||||
onPressed: currentPage > 0
|
||||
? () {
|
||||
setState(() {
|
||||
currentPage--;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
|
||||
// Page number text
|
||||
Text(
|
||||
'Page ${currentPage + 1}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
|
||||
// Next button with arrow icon
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 10,
|
||||
),
|
||||
onPressed: (currentPage + 1) * itemsPerPage <
|
||||
plans.length
|
||||
? () {
|
||||
setState(() {
|
||||
currentPage++;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
],
|
||||
),
|
||||
PaginationControls(
|
||||
currentPage: currentPage,
|
||||
itemsPerPage: itemsPerPage,
|
||||
totalItems: plans.length,
|
||||
activeColor: layoutColor, // your theme color
|
||||
onPageChanged: (page) {
|
||||
setState(() {
|
||||
currentPage = page;
|
||||
});
|
||||
},
|
||||
onItemsPerPageChanged: (items) {
|
||||
setState(() {
|
||||
itemsPerPage = items;
|
||||
currentPage = 0;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
@ -797,3 +951,23 @@ class _ApprovalListState extends State<ApprovalList> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Helper functions for colors
|
||||
Color getStatusColor(String status) {
|
||||
if (status == "Partially Approved") return Colors.yellow.shade100;
|
||||
if (status == "Approved") return Colors.green.shade100;
|
||||
if (status == "Completed") return Colors.green.shade500;
|
||||
if (status == "Rejected") return Colors.red.shade100;
|
||||
return Colors.grey.shade100;
|
||||
}
|
||||
|
||||
Color getStatusTextColor(String status) {
|
||||
if (status == "Partially Approved" ||
|
||||
status == "Approved" ||
|
||||
status == "Rejected") {
|
||||
return Colors.black;
|
||||
} else if (status == "Completed") {
|
||||
return Colors.white;
|
||||
}
|
||||
return Colors.grey;
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
final TextEditingController _newPasswordController = TextEditingController();
|
||||
final TextEditingController _confirmPasswordController =
|
||||
TextEditingController();
|
||||
String? userRole;
|
||||
bool _obscureText = true;
|
||||
bool _isForgotPassword = false;
|
||||
bool _showOtpResetFields = false;
|
||||
@ -61,6 +62,12 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
final pref = await SharedPreferences.getInstance();
|
||||
await pref.setString('auth_token', token);
|
||||
await pref.setString('user_data', jsonEncode(userData));
|
||||
|
||||
userRole = userData['role'];
|
||||
|
||||
print("userData - $userData");
|
||||
print("userData11 - ${userData['role']}");
|
||||
print("userData12 - $userRole");
|
||||
}
|
||||
} catch (e) {
|
||||
print('Error decoding token: $e');
|
||||
@ -99,7 +106,14 @@ class _LoginWidgetState extends State<LoginWidget> {
|
||||
backgroundColor: Colors.green, // Set background to green
|
||||
),
|
||||
);
|
||||
context.go('/listPlan'); // Navigate to home
|
||||
|
||||
if (userRole == "Travel Agent") {
|
||||
context.go('/listTravelAgentPlan');
|
||||
} else if (userRole == "Org Admin" || userRole == "Travel Admin") {
|
||||
context.go('/listAllPlan');
|
||||
} else {
|
||||
context.go('/listPlan');
|
||||
}
|
||||
} else {
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
|
||||
@ -13,7 +13,7 @@ class HomePage extends StatelessWidget {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
appBar: isDesktop ? null : const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||
body: Row(
|
||||
children: [
|
||||
|
||||
@ -324,7 +324,7 @@ class _groupState extends State<Group> {
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
|
||||
@ -132,7 +132,7 @@ class _GroupListState extends State<GroupList> {
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
|
||||
@ -331,7 +331,7 @@ class _OrgSetUpState extends State<OrgSetUp> {
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
|
||||
@ -61,7 +61,7 @@ class _OrganizationListState extends State<OrganizationList> {
|
||||
backgroundColor: Colors.white,
|
||||
// appBar: isDesktop ? null : const CustomAppBar(title: 'Home'),
|
||||
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Row(
|
||||
children: [
|
||||
|
||||
@ -65,8 +65,10 @@ class _CreatePlansState extends State<CreatePlan> {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: const CustomAppBar(),
|
||||
// backgroundColor: Colors.white,
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
// backgroundColor: Color(0xFFFCFCFC),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
@ -109,16 +111,18 @@ class _CreatePlansState extends State<CreatePlan> {
|
||||
// print("RECived palndata - ${planData}");
|
||||
|
||||
return Container(
|
||||
// margin: const EdgeInsets.only(left: 10.0, right: 15.0, top: 10.0, bottom: 10.0),
|
||||
// decoration: BoxDecoration(
|
||||
// // color: Colors.amber,
|
||||
// // color: bodyColor,
|
||||
// color: Color(0xFFE1F5FE),
|
||||
// border: Border.all(
|
||||
// color: Colors.white,
|
||||
// // color: Color(0xFFF7F7FB),
|
||||
//
|
||||
// width: 3.5)),
|
||||
margin: const EdgeInsets.only(top: 10.0, bottom: 10.0),
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(
|
||||
// color: Colors.amber,
|
||||
// color: bodyColor,
|
||||
color: Colors.white,
|
||||
// border: Border.all(
|
||||
// color: Colors.white,
|
||||
// // color: Color(0xFFF7F7FB),
|
||||
//
|
||||
// width: 3.5)
|
||||
),
|
||||
child: Column(
|
||||
children: [
|
||||
// Container(
|
||||
|
||||
@ -13,6 +13,9 @@ import '../../routes/custom_appBar.dart';
|
||||
import '../../routes/custom_drawer.dart';
|
||||
import '../../services/apiService.dart';
|
||||
import '../../utils/auth_utils.dart';
|
||||
import '../../utils/pagination.dart';
|
||||
import '../../widgets/custom_popup.dart';
|
||||
import '../../widgets/popup_listPlan_action.dart';
|
||||
|
||||
class ListPlans extends StatefulWidget {
|
||||
const ListPlans({super.key});
|
||||
@ -25,7 +28,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
final ApiService apiService = ApiService();
|
||||
|
||||
int currentPage = 0;
|
||||
int itemsPerPage = 8;
|
||||
int itemsPerPage = 10;
|
||||
|
||||
String? userId;
|
||||
String? orgId;
|
||||
@ -272,10 +275,10 @@ class _ListPlansState extends State<ListPlans> {
|
||||
bool isDesktop = sizingInfo.deviceScreenType == DeviceScreenType.desktop;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
backgroundColor: Color(0xFFf5f5f5),
|
||||
// appBar: isDesktop ? null : const CustomAppBar(title: 'Home'),
|
||||
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
@ -285,7 +288,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
vertical: MediaQuery.of(context).size.height *
|
||||
0, // 5% of screen height as vertical padding
|
||||
)
|
||||
: EdgeInsets.all(8),
|
||||
: EdgeInsets.all(0),
|
||||
child: Row(
|
||||
children: [
|
||||
// if (isDesktop) CustomDrawer(isDesktop: true),
|
||||
@ -322,10 +325,8 @@ class _ListPlansState extends State<ListPlans> {
|
||||
}
|
||||
|
||||
return Container(
|
||||
margin: isDesktop
|
||||
? EdgeInsets.all(10.0)
|
||||
: EdgeInsets.only(left: 20.0, bottom: 20.0, top: 10.0, right: 20.0),
|
||||
// padding: const EdgeInsets.all(10),
|
||||
margin: isDesktop ? EdgeInsets.all(10.0) : null,
|
||||
padding: const EdgeInsets.only(top: 15, bottom: 15, left: 20, right: 20),
|
||||
height: isDesktop
|
||||
? MediaQuery.of(context).size.height * 0.98
|
||||
: MediaQuery.of(context).size.height,
|
||||
@ -359,7 +360,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const Text('Trip List',
|
||||
const Text('My Trip Request',
|
||||
style: TextStyle(
|
||||
fontFamily: "Inter",
|
||||
fontSize: 16,
|
||||
@ -369,46 +370,45 @@ class _ListPlansState extends State<ListPlans> {
|
||||
),
|
||||
|
||||
Spacer(),
|
||||
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
size: 18,
|
||||
if (isDesktop)
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
size: 18,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
),
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide:
|
||||
BorderSide(color: Colors.grey.shade300, width: 1),
|
||||
),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
// SizedBox(width: 16),
|
||||
|
||||
Spacer(),
|
||||
if (isDesktop) Spacer(),
|
||||
// ElevatedButton(
|
||||
// style: ElevatedButton.styleFrom(
|
||||
// foregroundColor: Colors.white,
|
||||
@ -478,7 +478,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
MainAxisSize.min, // Ensures content fits nicely
|
||||
children: [
|
||||
Text(
|
||||
"Add New Plan",
|
||||
"Add New Trip",
|
||||
style: TextStyle(fontSize: 13),
|
||||
),
|
||||
SizedBox(width: 8), // spacing between icon and text
|
||||
@ -492,7 +492,50 @@ class _ListPlansState extends State<ListPlans> {
|
||||
),
|
||||
],
|
||||
),
|
||||
if (!isDesktop) const SizedBox(height: 10),
|
||||
if (!isDesktop)
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.85,
|
||||
height: 40,
|
||||
child: TextField(
|
||||
controller: searchController,
|
||||
onChanged: filterPlans,
|
||||
decoration: InputDecoration(
|
||||
hintText: "Search...",
|
||||
hintStyle:
|
||||
TextStyle(fontSize: 12, color: Color(0xFF9E9DBD)),
|
||||
prefixIcon: Icon(
|
||||
Icons.search,
|
||||
color: Color(0xFF9E9DBD),
|
||||
size: 18,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
enabledBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade200, width: 0.5),
|
||||
),
|
||||
focusedBorder: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
borderSide: BorderSide(
|
||||
color: Colors.grey.shade300, width: 1),
|
||||
),
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
const SizedBox(height: 10),
|
||||
|
||||
FutureBuilder<List<Plan>>(
|
||||
future: futurePlans,
|
||||
builder: (context, snapshot) {
|
||||
@ -509,25 +552,27 @@ class _ListPlansState extends State<ListPlans> {
|
||||
children: const [
|
||||
Icon(Icons.error_outline,
|
||||
color: Colors.redAccent, size: 60),
|
||||
SizedBox(height: 16),
|
||||
SizedBox(height: 1),
|
||||
Text("Oops!",
|
||||
style: TextStyle(
|
||||
fontSize: 22,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.redAccent)),
|
||||
SizedBox(height: 8),
|
||||
Text("No Plans Available For This User",
|
||||
SizedBox(height: 15),
|
||||
Text("No Trips",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.grey)),
|
||||
SizedBox(height: 20),
|
||||
Text("Please Create Plan",
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Colors.black54)),
|
||||
SizedBox(height: 10),
|
||||
Text("Please Create Trip",
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16, color: Colors.grey)),
|
||||
SizedBox(height: 20),
|
||||
fontFamily: "Inter",
|
||||
fontSize: 12,
|
||||
color: Colors.grey)),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -569,15 +614,15 @@ class _ListPlansState extends State<ListPlans> {
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Employee Code',
|
||||
label: Text('Trip Name',
|
||||
style: TextStyle(
|
||||
// color: Color(0xFF9E9DBD),
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
DataColumn(
|
||||
label: Text('Trip Name',
|
||||
label: Text('Employee Code',
|
||||
style: TextStyle(
|
||||
// color: Color(0xFF9E9DBD),
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.w600))),
|
||||
@ -619,11 +664,7 @@ class _ListPlansState extends State<ListPlans> {
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(plan.employeeCode ?? "no data",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
|
||||
DataCell(Text(plan.tripTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
@ -631,6 +672,12 @@ class _ListPlansState extends State<ListPlans> {
|
||||
),
|
||||
softWrap: true,
|
||||
overflow: TextOverflow.ellipsis)),
|
||||
|
||||
DataCell(Text(plan.employeeCode ?? "no data",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
))),
|
||||
DataCell(Text(
|
||||
plan.userName.isNotEmpty
|
||||
? plan.userName
|
||||
@ -691,53 +738,122 @@ class _ListPlansState extends State<ListPlans> {
|
||||
),
|
||||
),
|
||||
),
|
||||
DataCell(Row(children: [
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.remove_red_eye,
|
||||
color: Color(0xFF475569),
|
||||
size: 18,
|
||||
DataCell(
|
||||
PopupMenuButton<int>(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.zero,
|
||||
offset: Offset(0, 30),
|
||||
icon: Icon(Icons.more_vert,
|
||||
size: 14, color: Color(0xFF475569)),
|
||||
itemBuilder: (context) => [
|
||||
CustomPopupMenuEntry(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 8),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.center,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.remove_red_eye,
|
||||
color: Color(0xFF475569),
|
||||
size: 18),
|
||||
onPressed: () {
|
||||
Navigator.pop(
|
||||
context); // Close popup manually
|
||||
ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: true);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: false);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
deletePlan(plan.planId);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.download,
|
||||
color: Color(0xFF114D8B),
|
||||
size: 18),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
apiService.getPdfDownload(
|
||||
plan.planId);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: () => ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: true)),
|
||||
|
||||
GestureDetector(
|
||||
onTap: () => ApiService.viewPlan(
|
||||
context, plan.planId,
|
||||
isViewMode: false),
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/edit.png',
|
||||
width: 15,
|
||||
height: 15),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// IconButton(
|
||||
// icon: const Icon(Icons.edit,
|
||||
// color: Colors.green),
|
||||
// onPressed: () => viewPlan(plan.planId,
|
||||
// isViewMode: false) ),
|
||||
|
||||
SizedBox(
|
||||
width: 5,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () => deletePlan(plan.planId),
|
||||
child: Image.asset(
|
||||
'assets/images/IconsImg/delete.png',
|
||||
width: 20,
|
||||
height: 15),
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.download,
|
||||
color: Color(0xFF475569),
|
||||
size: 18,
|
||||
),
|
||||
onPressed: () {
|
||||
apiService.getPdfDownload(plan.planId);
|
||||
}),
|
||||
])),
|
||||
// DataCell(Row(children: [
|
||||
// IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.remove_red_eye,
|
||||
// color: Color(0xFF475569),
|
||||
// size: 18,
|
||||
// ),
|
||||
// onPressed: () => ApiService.viewPlan(
|
||||
// context, plan.planId,
|
||||
// isViewMode: true)),
|
||||
//
|
||||
// GestureDetector(
|
||||
// onTap: () => ApiService.viewPlan(
|
||||
// context, plan.planId,
|
||||
// isViewMode: false),
|
||||
// child: Image.asset(
|
||||
// 'assets/images/IconsImg/edit.png',
|
||||
// width: 15,
|
||||
// height: 15),
|
||||
// ),
|
||||
//
|
||||
// // IconButton(
|
||||
// // icon: const Icon(Icons.edit,
|
||||
// // color: Colors.green),
|
||||
// // onPressed: () => viewPlan(plan.planId,
|
||||
// // isViewMode: false) ),
|
||||
//
|
||||
// SizedBox(
|
||||
// width: 5,
|
||||
// ),
|
||||
// GestureDetector(
|
||||
// onTap: () => deletePlan(plan.planId),
|
||||
// child: Image.asset(
|
||||
// 'assets/images/IconsImg/delete.png',
|
||||
// width: 20,
|
||||
// height: 15),
|
||||
// ),
|
||||
// IconButton(
|
||||
// icon: const Icon(
|
||||
// Icons.download,
|
||||
// color: Color(0xFF475569),
|
||||
// size: 18,
|
||||
// ),
|
||||
// onPressed: () {
|
||||
// apiService.getPdfDownload(plan.planId);
|
||||
// }),
|
||||
// ])),
|
||||
]);
|
||||
}).toList(),
|
||||
),
|
||||
@ -745,66 +861,148 @@ class _ListPlansState extends State<ListPlans> {
|
||||
},
|
||||
);
|
||||
|
||||
Widget buildMobileCardView(List<Plan> paginatedPlans) {
|
||||
return ListView.builder(
|
||||
itemCount: paginatedPlans.length,
|
||||
itemBuilder: (context, index) {
|
||||
final plan = paginatedPlans[index];
|
||||
return Card(
|
||||
color: Colors.white,
|
||||
margin:
|
||||
EdgeInsets.symmetric(horizontal: 12, vertical: 6),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
elevation: 3,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12.0),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
// Status and Employee Code
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: getStatusColor(plan.statusValue),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
plan.statusValue,
|
||||
style: TextStyle(
|
||||
color: getStatusTextColor(
|
||||
plan.statusValue),
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
),
|
||||
),
|
||||
PlanPopupMenu(
|
||||
plan: plan,
|
||||
deletePlan: deletePlan,
|
||||
apiService: apiService,
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 8),
|
||||
// Name
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
plan.employeeCode ?? 'No Data',
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontFamily: "Inter"),
|
||||
),
|
||||
Text(
|
||||
plan.userName.isNotEmpty
|
||||
? plan.userName
|
||||
: plan.travellerName,
|
||||
style: TextStyle(
|
||||
fontSize: 12, fontFamily: "Inter"),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
// Trip Id and Trip Name
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text('${plan.tripTitle}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontFamily: "Inter",
|
||||
fontWeight: FontWeight.bold)),
|
||||
),
|
||||
],
|
||||
),
|
||||
SizedBox(height: 2),
|
||||
// Type and Created On
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text('${plan.tripType}',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
Expanded(
|
||||
child:
|
||||
Text('${_formatDate(plan.createdOn)}',
|
||||
style: TextStyle(
|
||||
fontSize: 10,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// Actions
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return Expanded(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
// mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
isDesktop
|
||||
? table
|
||||
: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
child: SingleChildScrollView(
|
||||
Expanded(
|
||||
child: isDesktop
|
||||
? SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: table,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
// Previous button with arrow icon
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.arrow_back_ios_new,
|
||||
size: 10,
|
||||
),
|
||||
onPressed: currentPage > 0
|
||||
? () {
|
||||
setState(() {
|
||||
currentPage--;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
|
||||
// Page number text
|
||||
Text(
|
||||
'Page ${currentPage + 1}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
SizedBox(width: 2),
|
||||
|
||||
// Next button with arrow icon
|
||||
IconButton(
|
||||
icon: Icon(
|
||||
Icons.arrow_forward_ios,
|
||||
size: 10,
|
||||
),
|
||||
onPressed: (currentPage + 1) * itemsPerPage <
|
||||
plans.length
|
||||
? () {
|
||||
setState(() {
|
||||
currentPage++;
|
||||
});
|
||||
}
|
||||
: null,
|
||||
),
|
||||
],
|
||||
child: table, // <-- your existing table
|
||||
)
|
||||
: buildMobileCardView(paginatedPlans),
|
||||
),
|
||||
PaginationControls(
|
||||
currentPage: currentPage,
|
||||
itemsPerPage: itemsPerPage,
|
||||
totalItems: plans.length,
|
||||
activeColor: layoutColor, // your theme color
|
||||
onPageChanged: (page) {
|
||||
setState(() {
|
||||
currentPage = page;
|
||||
});
|
||||
},
|
||||
onItemsPerPageChanged: (items) {
|
||||
setState(() {
|
||||
itemsPerPage = items;
|
||||
currentPage = 0;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@ -384,7 +384,7 @@ class _PolicyState extends State<Policy> {
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white,
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
|
||||
@ -148,7 +148,7 @@ class _PolicyListState extends State<PolicyList> {
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Colors.white54,
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
|
||||
@ -666,7 +666,7 @@ class _CreateUserFormState extends State<CreateUserForm> {
|
||||
backgroundColor: Colors.white,
|
||||
// appBar: isDesktop ? null : const CustomAppBar(title: 'Create User '),
|
||||
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
|
||||
@ -306,7 +306,7 @@ class _UserListScreenState extends State<UserListScreen> {
|
||||
backgroundColor: Colors.white,
|
||||
// appBar: isDesktop ? null : const CustomAppBar(title: 'User Management'),
|
||||
// drawer: isDesktop ? null : CustomDrawer(isDesktop: false),
|
||||
appBar: const CustomAppBar(),
|
||||
appBar: CustomAppBar(isDesktop: isDesktop),
|
||||
drawer: CustomDrawer(isDesktop: false),
|
||||
body: Padding(
|
||||
padding: isDesktop
|
||||
|
||||
@ -5,6 +5,7 @@ import 'package:shared_preferences/shared_preferences.dart'; // don't forget
|
||||
import '../services/apiService.dart';
|
||||
|
||||
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
final bool isDesktop;
|
||||
final String? logoUrl;
|
||||
final String? username;
|
||||
final List<Widget>? actions;
|
||||
@ -16,6 +17,7 @@ class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
|
||||
this.username,
|
||||
this.actions,
|
||||
this.showBackButton = false,
|
||||
required this.isDesktop,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -140,161 +142,231 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
||||
return AppBar(
|
||||
backgroundColor: Colors.white,
|
||||
surfaceTintColor: Colors.white,
|
||||
|
||||
// elevation: 3,
|
||||
automaticallyImplyLeading: false,
|
||||
// leading: showBackButton
|
||||
// ? IconButton(
|
||||
// icon: const Icon(Icons.arrow_back, color: Colors.black87),
|
||||
// onPressed: () => Navigator.pop(context),
|
||||
// )
|
||||
// : null,
|
||||
automaticallyImplyLeading: !widget.isDesktop,
|
||||
titleSpacing: 0,
|
||||
title: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width * 0.05),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
||||
|
||||
child: selectedOrg?['logo'] != null
|
||||
? ClipRect(
|
||||
child: Image.network(
|
||||
selectedOrg!['logo'],
|
||||
width: 100,
|
||||
height: 80,
|
||||
// fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return const CircleAvatar(
|
||||
title: !widget.isDesktop
|
||||
? Text('')
|
||||
: Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: MediaQuery.of(context).size.width * 0.05),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
// padding: const EdgeInsets.symmetric(horizontal: 40, vertical: 10),
|
||||
|
||||
child: selectedOrg?['logo'] != null
|
||||
? ClipRect(
|
||||
child: Image.network(
|
||||
selectedOrg!['logo'],
|
||||
width: 100,
|
||||
height: 80,
|
||||
// fit: BoxFit.contain,
|
||||
errorBuilder: (context, error, stackTrace) {
|
||||
return const CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundColor: Colors.redAccent,
|
||||
child: Icon(Icons.error, size: 10),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: const CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundColor: Colors.redAccent,
|
||||
child: Icon(Icons.error, size: 10),
|
||||
);
|
||||
},
|
||||
),
|
||||
)
|
||||
: const CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundColor: Colors.white,
|
||||
child: Icon(
|
||||
Icons.add_a_photo,
|
||||
size: 10,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.25,
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (userData?["role"] == "Org Admin" ||
|
||||
userData?["role"] == "Travel Admin")
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding =
|
||||
// EdgeInsets.symmetric(horizontal: 12, vertical: 78);
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF114D8B); // Change color on hover
|
||||
});
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding = EdgeInsets.symmetric(
|
||||
// horizontal: 8, vertical: 4); // Normal padding
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF475569); // Revert color when hover ends
|
||||
});
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.go('/listAllPlan');
|
||||
},
|
||||
child: Text(
|
||||
"All Trips",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
// color: Color(0xFF475569),
|
||||
color: _myTravelRequestColor,
|
||||
fontFamily: "Inter",
|
||||
backgroundColor: Colors.white,
|
||||
child: Icon(
|
||||
Icons.add_a_photo,
|
||||
size: 10,
|
||||
color: Colors.grey,
|
||||
),
|
||||
),
|
||||
)),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding =
|
||||
// EdgeInsets.symmetric(horizontal: 12, vertical: 78);
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF114D8B); // Change color on hover
|
||||
});
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding = EdgeInsets.symmetric(
|
||||
// horizontal: 8, vertical: 4); // Normal padding
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF475569); // Revert color when hover ends
|
||||
});
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.go('/listPlan');
|
||||
},
|
||||
child: Text(
|
||||
"My Travel Request",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
// color: Color(0xFF475569),
|
||||
color: _myTravelRequestColor,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
)),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
_myApprovalsColor =
|
||||
Color(0xFF114D8B); // Change color on hover
|
||||
});
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
_myApprovalsColor =
|
||||
Color(0xFF475569); // Revert color when hover ends
|
||||
});
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.go('/ApprovalList');
|
||||
},
|
||||
child: Text(
|
||||
"My Approvals",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: _myApprovalsColor,
|
||||
// color: Color(0xFF475569),
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width * 0.2,
|
||||
),
|
||||
Container(
|
||||
width: MediaQuery.of(context).size.width * 0.35,
|
||||
// color: Colors.blueGrey,
|
||||
child: Row(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (userData?["role"] == "Org Admin" ||
|
||||
userData?["role"] == "Travel Admin")
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding =
|
||||
// EdgeInsets.symmetric(horizontal: 12, vertical: 78);
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF114D8B); // Change color on hover
|
||||
});
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding = EdgeInsets.symmetric(
|
||||
// horizontal: 8, vertical: 4); // Normal padding
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF475569); // Revert color when hover ends
|
||||
});
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.go('/listAllPlan');
|
||||
},
|
||||
child: Text(
|
||||
"All Trips",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
// color: Color(0xFF475569),
|
||||
color: _myTravelRequestColor,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
)),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
if (userDetails["role"] == "Travel Agent")
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding =
|
||||
// EdgeInsets.symmetric(horizontal: 12, vertical: 78);
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF114D8B); // Change color on hover
|
||||
});
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding = EdgeInsets.symmetric(
|
||||
// horizontal: 8, vertical: 4); // Normal padding
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF475569); // Revert color when hover ends
|
||||
});
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.go('/listTravelAgentPlan');
|
||||
},
|
||||
child: Text(
|
||||
"My Trips",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
// color: Color(0xFF475569),
|
||||
color: _myTravelRequestColor,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
)),
|
||||
),
|
||||
if (userDetails["role"] != "Travel Agent")
|
||||
const SizedBox(width: 20),
|
||||
if (userDetails["role"] != "Travel Agent")
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding =
|
||||
// EdgeInsets.symmetric(horizontal: 12, vertical: 78);
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF114D8B); // Change color on hover
|
||||
});
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
// _myTravelRequestPadding = EdgeInsets.symmetric(
|
||||
// horizontal: 8, vertical: 4); // Normal padding
|
||||
// _myTravelRequestColor =
|
||||
// Color(0xFF475569); // Revert color when hover ends
|
||||
});
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.go('/listPlan');
|
||||
},
|
||||
child: Text(
|
||||
"My Trip Request",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
// color: Color(0xFF475569),
|
||||
color: _myTravelRequestColor,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
)),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
if (userData?["role"] != "Travel Agent")
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
_myApprovalsColor =
|
||||
Color(0xFF114D8B); // Change color on hover
|
||||
});
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
_myApprovalsColor = Color(
|
||||
0xFF475569); // Revert color when hover ends
|
||||
});
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.go('/ApprovalList');
|
||||
},
|
||||
child: Text(
|
||||
"My Approvals",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: _myApprovalsColor,
|
||||
// color: Color(0xFF475569),
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
)),
|
||||
),
|
||||
if (userData?["role"] == "Travel Agent")
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
onEnter: (_) {
|
||||
setState(() {
|
||||
_myApprovalsColor =
|
||||
Color(0xFF114D8B); // Change color on hover
|
||||
});
|
||||
},
|
||||
onExit: (_) {
|
||||
setState(() {
|
||||
_myApprovalsColor = Color(
|
||||
0xFF475569); // Revert color when hover ends
|
||||
});
|
||||
},
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.go('/listTravelAgentPlan');
|
||||
},
|
||||
child: Text(
|
||||
"My Approvals",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: _myApprovalsColor,
|
||||
// color: Color(0xFF475569),
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
)),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Spacer(),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
@ -306,8 +378,6 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
||||
builder: (context) => PopupMenuButton<String>(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.zero,
|
||||
// icon: const Icon(Icons.arrow_drop_down,
|
||||
// size: 20, color: Colors.black87),
|
||||
offset: const Offset(0, 50), // 👈 shift it 50 pixels down
|
||||
onSelected: (String value) {
|
||||
switch (value) {
|
||||
@ -341,14 +411,23 @@ class _CustomAppBarState extends State<CustomAppBar> {
|
||||
// menuItems.map(buildMenuItem).toList(),
|
||||
|
||||
itemBuilder: (BuildContext context) {
|
||||
final isUser = userData?["role"] == "User";
|
||||
final filteredItems = isUser
|
||||
? menuItems
|
||||
.where((item) =>
|
||||
item['value'] == '/CreateUserDetails' ||
|
||||
item['value'] == '/logout')
|
||||
.toList()
|
||||
: menuItems;
|
||||
// final isUser = userData?["role"] == "User";
|
||||
final role = userData?["role"];
|
||||
List<Map<String, dynamic>> filteredItems;
|
||||
|
||||
if (role == "User") {
|
||||
filteredItems = menuItems
|
||||
.where((item) =>
|
||||
item['value'] == '/CreateUserDetails' ||
|
||||
item['value'] == '/logout')
|
||||
.toList();
|
||||
} else if (role == "Travel Agent") {
|
||||
filteredItems = menuItems
|
||||
.where((item) => item['value'] == '/logout')
|
||||
.toList();
|
||||
} else {
|
||||
filteredItems = menuItems;
|
||||
}
|
||||
|
||||
// Create a new list starting with role display and divider
|
||||
return [
|
||||
|
||||
@ -165,167 +165,28 @@ class _CustomDrawerState extends State<CustomDrawer> {
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"Welcome,",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w500,
|
||||
fontFamily: "Archivo",
|
||||
color: Colors.black,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
MouseRegion(
|
||||
cursor: SystemMouseCursors.click,
|
||||
child: Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
print("ONTAP Custom");
|
||||
print("ONTAP Custom- $userDetails ");
|
||||
context.go(
|
||||
"/CreateUserDetails",
|
||||
extra: {
|
||||
"selectedUser": userDetails,
|
||||
"isEditProfile": true,
|
||||
"isViewMode": true
|
||||
},
|
||||
);
|
||||
},
|
||||
child: Text(
|
||||
userData?["name"] ?? "N/A",
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: "Archivo",
|
||||
// color: Color(0xFF12B24B),
|
||||
color: layoutColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
// GestureDetector(
|
||||
// onTap: () {
|
||||
// print("ONTAP Custom");
|
||||
// print("ONTAP Custom- $userDetails ");
|
||||
// context.go(
|
||||
// "/CreateUserDetails",
|
||||
// extra: {
|
||||
// "selectedUser": userDetails,
|
||||
// "isEditProfile": true,
|
||||
// "isViewMode": true
|
||||
// },
|
||||
// );
|
||||
// },
|
||||
// child: SizedBox(
|
||||
// height: 80,
|
||||
// child: Container(
|
||||
// color: Color(0xFFF3F3FA),
|
||||
// padding: EdgeInsets.all(16),
|
||||
// // width: double.infinity,
|
||||
// child: Row(
|
||||
// // mainAxisAlignment: MainAxisAlignment.center,
|
||||
// children: [
|
||||
// Column(
|
||||
// crossAxisAlignment: CrossAxisAlignment.start,
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// children: [
|
||||
// Column(
|
||||
// children: [
|
||||
// Text(
|
||||
// "Welcome",
|
||||
// style: TextStyle(
|
||||
// color: Colors.black,
|
||||
// fontSize: 13,
|
||||
// fontWeight: FontWeight.w400,
|
||||
// fontFamily: "Archivo"),
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// Column(
|
||||
// children: [
|
||||
// Text(
|
||||
// userData?["name"] ?? "N/A",
|
||||
// style: TextStyle(
|
||||
// color: Color(0xFF12B24B),
|
||||
// fontSize: 13,
|
||||
// fontWeight: FontWeight.w600,
|
||||
// fontFamily: "Archivo"),
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
// ],
|
||||
// ),
|
||||
// ],
|
||||
// )),
|
||||
// ),
|
||||
// ),
|
||||
SizedBox(
|
||||
height: 15,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// _buildDrawerItem(context, Icons.home_outlined, 'Home', '/home'),
|
||||
_buildDrawerItem(context, Icons.request_page_outlined,
|
||||
'My Travel Request', '/listPlan'),
|
||||
_buildDrawerItem(context, Icons.assessment_outlined, 'My Approvals',
|
||||
'/ApprovalList'),
|
||||
if (userData?["role"] != "User")
|
||||
_buildDrawerItem(context, Icons.account_circle_outlined,
|
||||
'User List', '/listUser'),
|
||||
// _buildExpandableItem(
|
||||
// context,
|
||||
// Icons.assessment_outlined,
|
||||
// 'Plans',
|
||||
// [
|
||||
// _buildSubDrawerItem(
|
||||
// context, 'My Travel Request', '/listPlan'),
|
||||
// _buildSubDrawerItem(context, 'My Approvals', '/ApprovalList')
|
||||
// ],
|
||||
// '/listPlan'),
|
||||
//
|
||||
// _buildExpandableItem(
|
||||
// context,
|
||||
// Icons.account_circle_outlined,
|
||||
// 'User ',
|
||||
// [
|
||||
// _buildSubDrawerItem(context, 'User List', '/listUser'),
|
||||
// // _buildSubDrawerItem(context,'PlanB','/PlanB')
|
||||
// ],
|
||||
// '/listUser'),
|
||||
if (userData?["role"] != "User")
|
||||
_buildExpandableItem(
|
||||
context,
|
||||
Icons.settings_outlined,
|
||||
'Settings ',
|
||||
[
|
||||
_buildSubDrawerItem(
|
||||
context, 'Organization', '/OrganizationSetup'),
|
||||
_buildSubDrawerItem(context, 'Group', '/group'),
|
||||
_buildSubDrawerItem(context, 'Policy', '/PolicyList'),
|
||||
// _buildSubDrawerItem(context,'PlanB','/PlanB')
|
||||
],
|
||||
'/OrganizationSetup',
|
||||
),
|
||||
_buildDrawerItem(context, Icons.login_outlined, 'Logout', '/'),
|
||||
if (widget.isDesktop) Spacer(),
|
||||
|
||||
if (userData?["role"] == "Org Admin" ||
|
||||
userData?["role"] == "Travel Admin")
|
||||
_buildDrawerItem(context, Icons.request_page_outlined,
|
||||
'All Trips', '/listAllPlan'),
|
||||
|
||||
if (userDetails["role"] != "Travel Agent")
|
||||
_buildDrawerItem(context, Icons.request_page_outlined,
|
||||
'My Approvals1', '/listTravelAgentPlan'),
|
||||
|
||||
if (userDetails["role"] != "Travel Agent")
|
||||
_buildDrawerItem(context, Icons.request_page_outlined,
|
||||
'My Trip Request', '/listPlan'),
|
||||
|
||||
if (userDetails["role"] != "Travel Agent")
|
||||
_buildDrawerItem(context, Icons.assessment_outlined,
|
||||
'My Approvals', '/ApprovalList'),
|
||||
|
||||
Container(
|
||||
margin: const EdgeInsets.all(20),
|
||||
child: Row(
|
||||
|
||||
@ -15,6 +15,7 @@ import 'package:frontend/Screens/userManagement/user_List.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
|
||||
import '../Screens/allTrips/list_all_plans.dart';
|
||||
import '../Screens/allTrips/travel_agent_list.dart';
|
||||
import '../Screens/approvals/approval_list.dart';
|
||||
import '../Screens/group/group.dart';
|
||||
import '../Screens/group/groupList.dart';
|
||||
@ -33,6 +34,10 @@ final GoRouter router = GoRouter(
|
||||
path: '/listAllPlan',
|
||||
builder: (context, state) => ListAllPlans(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/listTravelAgentPlan',
|
||||
builder: (context, state) => TravelAgentListPlans(),
|
||||
),
|
||||
GoRoute(
|
||||
path: '/listPlan',
|
||||
builder: (context, state) => ListPlans(),
|
||||
|
||||
103
lib/utils/pagination.dart
Normal file
103
lib/utils/pagination.dart
Normal file
@ -0,0 +1,103 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class PaginationControls extends StatelessWidget {
|
||||
final int currentPage;
|
||||
final int itemsPerPage;
|
||||
final int totalItems;
|
||||
final Function(int) onPageChanged;
|
||||
final Function(int) onItemsPerPageChanged;
|
||||
final Color? activeColor;
|
||||
|
||||
const PaginationControls({
|
||||
Key? key,
|
||||
required this.currentPage,
|
||||
required this.itemsPerPage,
|
||||
required this.totalItems,
|
||||
required this.onPageChanged,
|
||||
required this.onItemsPerPageChanged,
|
||||
this.activeColor = Colors.blue, // fallback if no color given
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
int totalPages = (totalItems / itemsPerPage).ceil();
|
||||
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
'Items per page:',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
color: Colors.black87,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
DropdownButton<int>(
|
||||
value: itemsPerPage,
|
||||
items: [10, 20, 50, 100]
|
||||
.map((value) => DropdownMenuItem<int>(
|
||||
value: value,
|
||||
child: Text('$value',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
)),
|
||||
))
|
||||
.toList(),
|
||||
onChanged: (value) {
|
||||
if (value != null) {
|
||||
onItemsPerPageChanged(value);
|
||||
}
|
||||
},
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.black,
|
||||
fontFamily: "Inter",
|
||||
),
|
||||
underline: SizedBox(),
|
||||
iconSize: 16,
|
||||
),
|
||||
SizedBox(width: 16),
|
||||
IconButton(
|
||||
icon: Icon(Icons.arrow_back_ios_new, size: 10),
|
||||
onPressed:
|
||||
currentPage > 0 ? () => onPageChanged(currentPage - 1) : null,
|
||||
),
|
||||
Row(
|
||||
children: List.generate(
|
||||
totalPages,
|
||||
(index) => Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4),
|
||||
child: ElevatedButton(
|
||||
onPressed: () => onPageChanged(index),
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor:
|
||||
currentPage == index ? activeColor : Colors.grey[300]!,
|
||||
minimumSize: Size(30, 30),
|
||||
padding: EdgeInsets.zero,
|
||||
),
|
||||
child: Text(
|
||||
'${index + 1}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontFamily: "Inter",
|
||||
color: currentPage == index ? Colors.white : Colors.black,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.arrow_forward_ios, size: 10),
|
||||
onPressed: (currentPage + 1) * itemsPerPage < totalItems
|
||||
? () => onPageChanged(currentPage + 1)
|
||||
: null,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
26
lib/widgets/custom_popup.dart
Normal file
26
lib/widgets/custom_popup.dart
Normal file
@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CustomPopupMenuEntry extends PopupMenuEntry<int> {
|
||||
final Widget child;
|
||||
|
||||
CustomPopupMenuEntry({required this.child});
|
||||
|
||||
@override
|
||||
double get height => 0; // 0 because height depends on child
|
||||
|
||||
@override
|
||||
bool represents(int? value) => false;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _CustomPopupMenuEntryState();
|
||||
}
|
||||
|
||||
class _CustomPopupMenuEntryState extends State<CustomPopupMenuEntry> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IntrinsicHeight(
|
||||
// <-- wrap with IntrinsicHeight
|
||||
child: widget.child,
|
||||
);
|
||||
}
|
||||
}
|
||||
81
lib/widgets/popup_listPlan_action.dart
Normal file
81
lib/widgets/popup_listPlan_action.dart
Normal file
@ -0,0 +1,81 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../data/models/plan.dart';
|
||||
import '../services/apiService.dart';
|
||||
import 'custom_popup.dart';
|
||||
|
||||
class PlanPopupMenu extends StatelessWidget {
|
||||
final Plan plan;
|
||||
final Function(String planId) deletePlan;
|
||||
final ApiService apiService;
|
||||
|
||||
const PlanPopupMenu({
|
||||
Key? key,
|
||||
required this.plan,
|
||||
required this.deletePlan,
|
||||
required this.apiService,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Align(
|
||||
alignment: Alignment.centerRight,
|
||||
child: PopupMenuButton<int>(
|
||||
color: Colors.white,
|
||||
padding: EdgeInsets.zero,
|
||||
offset: Offset(0, 30),
|
||||
icon: Icon(
|
||||
Icons.more_vert,
|
||||
color: Color(0xFF475569),
|
||||
size: 20,
|
||||
),
|
||||
itemBuilder: (context) => [
|
||||
CustomPopupMenuEntry(
|
||||
child: Container(
|
||||
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
IconButton(
|
||||
icon: Icon(Icons.remove_red_eye, size: 18),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
ApiService.viewPlan(context, plan.planId,
|
||||
isViewMode: true);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset('assets/images/IconsImg/edit.png',
|
||||
width: 20, height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
ApiService.viewPlan(context, plan.planId,
|
||||
isViewMode: false);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Image.asset('assets/images/IconsImg/delete.png',
|
||||
width: 20, height: 15),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
deletePlan(plan.planId);
|
||||
},
|
||||
),
|
||||
IconButton(
|
||||
icon: Icon(Icons.download,
|
||||
color: Color(0xFF114D8B), size: 18),
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
apiService.getPdfDownload(plan.planId);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user