plan header ui-changes

This commit is contained in:
venbaittech 2025-05-07 10:36:05 +05:30
parent 94d2a730fb
commit 2b8172d5f4
16 changed files with 1791 additions and 863 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

View File

@ -289,7 +289,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
String _formatDate(String rawDate) {
try {
final dateTime = DateTime.parse(rawDate);
return DateFormat('dd MMM yy hh:m a').format(dateTime);
return DateFormat('dd, MMM yyyy hh:m a').format(dateTime);
} catch (e) {
return rawDate; // fallback if parsing fails
}
@ -309,7 +309,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
// color: Color(0xFFF7F7FB),
)
: null,
color: Colors.white,
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
// color: Color(0xFFF7F7FB),
// color: Colors.amber,
@ -318,7 +318,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
padding: const EdgeInsets.all(1.0),
child: Container(
// padding: const EdgeInsets.all(10.0),
color: Colors.white,
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@ -331,12 +331,12 @@ class _ListAllPlansState extends State<ListAllPlans> {
children: [
Row(
children: [
const Text('All Trips',
Text('All Trips',
style: TextStyle(
fontFamily: "Inter",
fontSize: 16,
fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600,
color: Color(0xFF212121))),
color: const Color(0xFF212121))),
],
),
@ -474,7 +474,7 @@ class _ListAllPlansState extends State<ListAllPlans> {
children: [
Container(
width: MediaQuery.of(context).size.width * 0.85,
height: 40,
height: 35,
child: TextField(
controller: searchController,
onChanged: filterPlans,
@ -781,99 +781,142 @@ class _ListAllPlansState extends State<ListAllPlans> {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 3,
elevation: 3, // Control the strength of the shadow
// shadowColor: Colors.black54, // Softer shadow
// clipBehavior: Clip.antiAlias,
child: Padding(
padding: const EdgeInsets.all(12.0),
// padding: EdgeInsets.symmetric(vertical: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.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,
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
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: 10,
fontWeight: FontWeight.w600,
),
),
),
),
],
),
PlanPopupMenu(
plan: plan,
deletePlan: deletePlan,
apiService: apiService,
Column(
children: [
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),
SizedBox(height: 2),
// Trip Id and Trip Name
Row(
children: [
Expanded(
child: Text('${plan.tripTitle}',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripTitle}',
style: TextStyle(
fontSize: 12,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
],
),
],
),
SizedBox(height: 2),
// Type and Created On
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text('${plan.tripType}',
style: TextStyle(
fontSize: 10,
color: Colors.black87,
fontFamily: "Inter",
)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripType}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
),
Expanded(
child:
Text('${_formatDate(plan.createdOn)}',
style: TextStyle(
fontSize: 10,
color: Colors.black87,
fontFamily: "Inter",
)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text('${_formatDate(plan.createdOn)}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
),
],
),
SizedBox(height: 3),
// Name
Row(
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
plan.userName.isNotEmpty
? '${plan.userName}'
: '${plan.travellerName}',
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
),
],
),
Spacer(),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
plan.employeeCode ?? 'No Data',
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
),
],
),
],
),
// Actions
],
),

View File

@ -280,7 +280,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
String _formatDate(String rawDate) {
try {
final dateTime = DateTime.parse(rawDate);
return DateFormat('dd MMM yy hh:m a').format(dateTime);
return DateFormat('dd,MMM yyyy hh:m a').format(dateTime);
} catch (e) {
return rawDate; // fallback if parsing fails
}
@ -300,7 +300,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
// color: Color(0xFFF7F7FB),
)
: null,
color: Colors.white,
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
// color: Color(0xFFF7F7FB),
// color: Colors.amber,
@ -309,7 +309,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
padding: const EdgeInsets.all(1.0),
child: Container(
// padding: const EdgeInsets.all(10.0),
color: Colors.white,
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@ -322,10 +322,10 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
children: [
Row(
children: [
const Text('My Trips',
Text('My Trips',
style: TextStyle(
fontFamily: "Inter",
fontSize: 16,
fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600,
color: Color(0xFF212121))),
],
@ -400,7 +400,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
children: [
Container(
width: MediaQuery.of(context).size.width * 0.85,
height: 40,
height: 35,
child: TextField(
controller: searchController,
onChanged: filterPlans,
@ -607,16 +607,6 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
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(
@ -625,14 +615,6 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
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,
@ -791,7 +773,7 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
style: TextStyle(
color: getStatusTextColor(
plan.statusValue),
fontSize: 12,
fontSize: 10,
fontWeight: FontWeight.w600,
),
),
@ -803,63 +785,92 @@ class _TravelAgentListPlansState extends State<TravelAgentListPlans> {
),
],
),
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),
SizedBox(height: 2),
// Trip Id and Trip Name
Row(
children: [
Expanded(
child: Text('${plan.tripTitle}',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripTitle}',
style: TextStyle(
fontSize: 12,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
],
),
],
),
SizedBox(height: 2),
// Type and Created On
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text('${plan.tripType}',
style: TextStyle(
fontSize: 10,
color: Colors.black87,
fontFamily: "Inter",
)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripType}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
),
Expanded(
child:
Text('${_formatDate(plan.createdOn)}',
style: TextStyle(
fontSize: 10,
color: Colors.black87,
fontFamily: "Inter",
)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text('${_formatDate(plan.createdOn)}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
),
],
),
SizedBox(height: 3),
// Name
Row(
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
plan.userName.isNotEmpty
? '${plan.userName}'
: '${plan.travellerName}',
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
),
],
),
Spacer(),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
plan.employeeCode ?? 'No Data',
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
),
],
),
],
),
// Actions
// Actions
],

View File

@ -1,7 +1,190 @@
import 'package:flutter/material.dart';
Future<dynamic> showApprovalDialog(
BuildContext context, Color layoutColor) async {
String selectedAction = ""; // "", "accept", "reject"
String remarks = "";
return showDialog<String>(
context: context,
barrierDismissible: false, // force user to tap cancel
builder: (context) {
return StatefulBuilder(
builder: (context, setState) {
return AlertDialog(
backgroundColor: Colors.white,
contentPadding: const EdgeInsets.all(24),
content: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"To Approve or Reject Trip",
style: TextStyle(
fontFamily: "Inter", fontWeight: FontWeight.w500),
),
IconButton(
icon: const Icon(
Icons.close,
size: 15,
),
onPressed: () {
Navigator.pop(context, null); // Close the dialog
},
),
],
),
// Accept and Reject Buttons
const SizedBox(height: 10),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: selectedAction == "accept"
? layoutColor
: Colors.grey.shade200,
foregroundColor: selectedAction == "accept"
? Colors.white
: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(vertical: 10),
),
onPressed: () {
setState(() {
selectedAction = "accept";
});
},
child: const Text("Accept"),
),
),
const SizedBox(width: 20),
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: selectedAction == "reject"
? Colors.redAccent
: Colors.grey.shade200,
foregroundColor: selectedAction == "reject"
? Colors.white
: Colors.black,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
padding: EdgeInsets.symmetric(vertical: 10),
),
onPressed: () {
setState(() {
selectedAction = "reject";
});
},
child: const Text(
"Reject",
style: TextStyle(fontFamily: "Inter"),
),
),
),
],
),
const SizedBox(height: 20),
// Dynamic Content Based on Selection
if (selectedAction == "accept") ...[
const Text(
"Do you want to approve?",
style: TextStyle(fontFamily: "Inter", fontSize: 14),
),
] else if (selectedAction == "reject") ...[
const Text(
"Please enter reason for rejection:",
style: TextStyle(fontFamily: "Inter", fontSize: 14),
),
const SizedBox(height: 10),
TextField(
style: TextStyle(fontFamily: "Inter", fontSize: 14),
maxLines: 3,
onChanged: (value) => remarks = value,
decoration: InputDecoration(
hintText: "Remarks...",
hintStyle: const TextStyle(
fontSize: 10, // 👈 Set your desired font size here
color: Colors.grey,
fontFamily:
"Inter", // optional if you want consistent font
),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(
color: Colors.blueGrey, width: 0.5),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide:
BorderSide(color: Colors.blueGrey, width: 0.5),
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide(color: layoutColor, width: 1),
),
),
),
]
],
),
actionsAlignment: MainAxisAlignment.center,
actions: [
// Cancel Button
if (selectedAction.isNotEmpty)
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.white,
foregroundColor: layoutColor,
side: BorderSide(color: layoutColor, width: 1.5),
),
onPressed: () {
Navigator.pop(context, null); // No result
},
child: const Text(
"Cancel",
style: TextStyle(fontFamily: "Inter", fontSize: 12),
),
),
if (selectedAction.isNotEmpty)
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: layoutColor,
foregroundColor: Colors.white,
),
onPressed: () {
if (selectedAction == "accept") {
Navigator.pop(context, "approved"); // Return approval
} else if (selectedAction == "reject" &&
remarks.trim().isNotEmpty) {
Navigator.pop(context, remarks.trim()); // Return remarks
}
},
child: const Text(
"OK",
style: TextStyle(fontFamily: "Inter", fontSize: 12),
),
),
],
);
},
);
},
);
}
/// Show confirm dialog for approval
Future<bool?> showApproveDialog(BuildContext context, Color layoutColor) {
Future<bool?> showApproveDialog1(BuildContext context, Color layoutColor) {
return showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
@ -47,7 +230,7 @@ Future<bool?> showApproveDialog(BuildContext context, Color layoutColor) {
}
/// Show confirm dialog for rejection with remarks input
Future<String?> showRejectDialog(
Future<String?> showRejectDialog1(
BuildContext context, Color layoutColor) async {
String remarks = "";
@ -75,10 +258,9 @@ Future<String?> showRejectDialog(
decoration: const InputDecoration(
hintText: "Remarks...",
hintStyle: TextStyle(
fontSize: 12, // 👈 Set your desired font size here
fontSize: 10, // 👈 Set your desired font size here
color: Colors.grey,
fontFamily:
"Archivo", // optional if you want consistent font
fontFamily: "Inter", // optional if you want consistent font
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueGrey, width: 0.5),

View File

@ -342,7 +342,7 @@ class _ApprovalListState extends State<ApprovalList> {
String _formatDate(String rawDate) {
try {
final dateTime = DateTime.parse(rawDate);
return DateFormat('dd MMM yy hh:m a').format(dateTime);
return DateFormat('dd, MMM yyyy hh:m a').format(dateTime);
} catch (e) {
return rawDate; // fallback if parsing fails
}
@ -362,7 +362,7 @@ class _ApprovalListState extends State<ApprovalList> {
// color: Color(0xFFF7F7FB),
)
: null,
color: Colors.white,
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
// color: Color(0xFFF7F7FB),
// color: Colors.amber,
@ -371,7 +371,7 @@ class _ApprovalListState extends State<ApprovalList> {
padding: const EdgeInsets.all(1.0),
child: Container(
// padding: const EdgeInsets.all(10.0),
color: Colors.white,
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@ -383,10 +383,10 @@ class _ApprovalListState extends State<ApprovalList> {
children: [
Row(
children: [
const Text('My Approvals',
Text('My Approvals',
style: TextStyle(
fontFamily: "Inter",
fontSize: 16,
fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600,
)),
],
@ -447,7 +447,7 @@ class _ApprovalListState extends State<ApprovalList> {
children: [
Container(
width: MediaQuery.of(context).size.width * 0.8,
height: 40,
height: 35,
child: TextField(
controller: searchController,
onChanged: filterPlans,
@ -554,15 +554,15 @@ class _ApprovalListState extends State<ApprovalList> {
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))),
@ -605,6 +605,14 @@ class _ApprovalListState extends State<ApprovalList> {
fontSize: 13,
fontFamily: "Archivo",
))),
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,
@ -623,13 +631,7 @@ class _ApprovalListState extends State<ApprovalList> {
fontSize: 13,
fontFamily: "Inter",
))),
DataCell(Text(plan.tripTitle,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
DataCell(Text(
// plan.createdOn,
@ -684,17 +686,17 @@ class _ApprovalListState extends State<ApprovalList> {
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);
},
),
icon: Icon(Icons.remove_red_eye,
color: Color(0xFF475569),
size: 18),
onPressed: () {
Navigator.pop(
context); // Close popup manually
viewPlanforApprover(
plan.planId,
isViewMode: true,
isApprover: true);
}),
IconButton(
icon: Image.asset(
'assets/images/IconsImg/edit.png',
@ -702,9 +704,10 @@ class _ApprovalListState extends State<ApprovalList> {
height: 15),
onPressed: () {
Navigator.pop(context);
ApiService.viewPlan(
ApiService.viewPlanForApprover(
context, plan.planId,
isViewMode: false);
isViewMode: false,
isApprover: true);
},
),
IconButton(
@ -825,76 +828,173 @@ class _ApprovalListState extends State<ApprovalList> {
style: TextStyle(
color: getStatusTextColor(
plan.statusValue),
fontSize: 12,
fontSize: 10,
fontWeight: FontWeight.w600,
),
),
),
PlanPopupMenu(
plan: plan,
deletePlan: deletePlan,
apiService: apiService,
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
viewPlanforApprover(
plan.planId,
isViewMode: true,
isApprover: true);
}),
IconButton(
icon: Image.asset(
'assets/images/IconsImg/edit.png',
width: 20,
height: 15),
onPressed: () {
Navigator.pop(context);
ApiService
.viewPlanForApprover(
context,
plan.planId,
isViewMode: false,
isApprover: true);
},
),
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);
},
),
],
),
),
),
],
),
],
),
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),
SizedBox(height: 2),
// Trip Id and Trip Name
Row(
children: [
Expanded(
child: Text('${plan.tripTitle}',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripTitle}',
style: TextStyle(
fontSize: 12,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
],
),
],
),
SizedBox(height: 2),
// Type and Created On
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text('${plan.tripType}',
style: TextStyle(
fontSize: 10,
color: Colors.black87,
fontFamily: "Inter",
)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripType}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
),
Expanded(
child:
Text('${_formatDate(plan.createdOn)}',
style: TextStyle(
fontSize: 10,
color: Colors.black87,
fontFamily: "Inter",
)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text('${_formatDate(plan.createdOn)}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
),
],
),
SizedBox(height: 3),
// Name
Row(
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
plan.userName.isNotEmpty
? '${plan.userName}'
: '${plan.travellerName}',
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
),
],
),
Spacer(),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
plan.employeeCode ?? 'No Data',
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
),
],
),
],
),
// Actions
// Actions
],
),
@ -914,13 +1014,7 @@ class _ApprovalListState extends State<ApprovalList> {
scrollDirection: Axis.vertical,
child: table, // <-- your existing table
)
: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: table,
),
),
: buildMobileCardView(paginatedPlans),
),
PaginationControls(
currentPage: currentPage,

View File

@ -0,0 +1,128 @@
import 'package:flutter/material.dart';
import 'package:super_tooltip/super_tooltip.dart';
class ApprovalTooltip extends StatefulWidget {
final List<Map<String, dynamic>> planStatusList;
final bool hasApprovals;
final String statusText;
final bool isApproverApproved;
final bool isApproverRejected;
final Color Function(String) getStatusColor;
const ApprovalTooltip({
super.key,
required this.planStatusList,
required this.hasApprovals,
required this.statusText,
required this.isApproverApproved,
required this.isApproverRejected,
required this.getStatusColor,
});
@override
State<ApprovalTooltip> createState() => _ApprovalTooltipState();
}
class _ApprovalTooltipState extends State<ApprovalTooltip> {
late SuperTooltip tooltip;
@override
void initState() {
super.initState();
tooltip = SuperTooltip(
popupDirection: TooltipDirection.down,
content: _buildTooltipContent(),
borderColor: Colors.grey.shade300,
backgroundColor: Colors.white,
shadowColor: Colors.black38,
barrierColor: Colors.transparent,
);
}
Widget _buildTooltipContent() {
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (!widget.hasApprovals)
Center(
child: Text(
"--- No Approvals ---",
style: const TextStyle(
fontFamily: "Archivo",
fontSize: 11,
fontWeight: FontWeight.w500,
color: Colors.black87,
),
),
),
for (int i = 0; i < widget.planStatusList.length; i++) ...[
if (widget.planStatusList[i].entries.any((entry) =>
entry.key.contains('status') &&
entry.value != null &&
entry.value.toString().isNotEmpty)) ...[
_buildApprovalItem(
"Approver ${i + 1}",
widget.planStatusList[i].entries
.firstWhere(
(entry) => entry.key.contains('status'),
orElse: () => MapEntry('', ''),
)
.value
.toString(),
),
const SizedBox(height: 6),
],
],
],
);
}
Widget _buildApprovalItem(String title, String value) {
return Row(
children: [
Text(
title,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 8),
Text(
value,
style: const TextStyle(
fontSize: 12,
),
),
],
);
}
@override
Widget build(BuildContext context) {
return MouseRegion(
child: Container(
decoration: BoxDecoration(
border: Border.all(color: widget.getStatusColor(widget.statusText)),
borderRadius: BorderRadius.circular(8),
),
padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 6),
child: Text(
widget.statusText,
style: TextStyle(
fontFamily: "Roboto",
fontWeight: FontWeight.w400,
fontSize: 12,
color: widget.getStatusColor(
widget.isApproverApproved
? "Approved"
: widget.isApproverRejected
? "Rejected"
: (widget.statusText),
),
),
),
),
);
}
}

View File

@ -675,24 +675,36 @@ class _LoginWidgetState extends State<LoginWidget> {
const SizedBox(height: 20),
if (!_isForgotPassword && !_showOtpResetFields)
Container(
width: 45, // Adjust size
height: 45,
decoration: BoxDecoration(
// Background color
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(15)),
border: Border.all(
color: Color(0xFF9E9DBD), width: 1), // Grey outline
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Image.asset(
'assets/images/login/microsoft.png',
width: 30, // Optional: control size
height: 30,
fit: BoxFit.contain,
),
const SizedBox(width: 10),
Container(
width: 30, // Adjust size
height: 30,
decoration: BoxDecoration(
// Background color
shape: BoxShape.rectangle,
borderRadius: BorderRadius.all(Radius.circular(15)),
border: Border.all(
color: Color(0xFF9E9DBD), width: 1), // Grey outline
),
child: Center(
child: Image.asset(
'assets/images/login/VectorG.png',
width: 20, // Optional: control size
height: 10,
fit: BoxFit.contain,
)),
child: Center(
child: Image.asset(
'assets/images/login/VectorG.png',
width: 20, // Optional: control size
height: 20,
fit: BoxFit.contain,
)),
),
],
),
],
),

View File

@ -14,12 +14,14 @@ class UserSelectionDialog extends StatefulWidget {
final String title;
final Color layoutColorForUser;
final void Function(String, String, bool) onSubmit;
final void Function() onClose;
UserSelectionDialog({
Key? key,
required this.title,
required this.layoutColorForUser,
required this.onSubmit,
required this.onClose,
}) : super(key: key);
@override
@ -427,7 +429,10 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
),
onPressed: () => Navigator.pop(context),
onPressed: () {
widget.onClose();
Navigator.pop(context);
},
child: Text(
"Cancel",
),

File diff suppressed because it is too large Load Diff

View File

@ -318,7 +318,7 @@ class _ListPlansState extends State<ListPlans> {
String _formatDate(String rawDate) {
try {
final dateTime = DateTime.parse(rawDate);
return DateFormat('dd MMM yy hh:m a').format(dateTime);
return DateFormat('dd, MMM yyyy hh:m a').format(dateTime);
} catch (e) {
return rawDate; // fallback if parsing fails
}
@ -338,7 +338,7 @@ class _ListPlansState extends State<ListPlans> {
// color: Color(0xFFF7F7FB),
)
: null,
color: Colors.white,
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
// color: Color(0xFFF7F7FB),
// color: Colors.amber,
@ -347,7 +347,7 @@ class _ListPlansState extends State<ListPlans> {
padding: const EdgeInsets.all(1.0),
child: Container(
// padding: const EdgeInsets.all(10.0),
color: Colors.white,
color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
@ -360,10 +360,10 @@ class _ListPlansState extends State<ListPlans> {
children: [
Row(
children: [
const Text('My Trip Request',
Text('My Trips',
style: TextStyle(
fontFamily: "Inter",
fontSize: 16,
fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600,
color: Color(0xFF212121))),
],
@ -440,8 +440,9 @@ class _ListPlansState extends State<ListPlans> {
borderRadius: BorderRadius.circular(8),
side: BorderSide(color: Color(0xFF114D8B), width: 2),
),
padding:
EdgeInsets.symmetric(horizontal: 20, vertical: 12),
padding: isDesktop
? EdgeInsets.symmetric(horizontal: 20, vertical: 12)
: EdgeInsets.symmetric(horizontal: 15, vertical: 10),
),
onPressed: () {
if (TripPlanAction == "Plan Creation Not Allowed") {
@ -479,7 +480,7 @@ class _ListPlansState extends State<ListPlans> {
children: [
Text(
"Add New Trip",
style: TextStyle(fontSize: 13),
style: TextStyle(fontSize: isDesktop ? 13 : 11),
),
SizedBox(width: 8), // spacing between icon and text
Icon(
@ -498,7 +499,7 @@ class _ListPlansState extends State<ListPlans> {
children: [
Container(
width: MediaQuery.of(context).size.width * 0.85,
height: 40,
height: 35,
child: TextField(
controller: searchController,
onChanged: filterPlans,
@ -896,7 +897,7 @@ class _ListPlansState extends State<ListPlans> {
style: TextStyle(
color: getStatusTextColor(
plan.statusValue),
fontSize: 12,
fontSize: 10,
fontWeight: FontWeight.w600,
),
),
@ -908,64 +909,92 @@ class _ListPlansState extends State<ListPlans> {
),
],
),
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),
SizedBox(height: 2),
// Trip Id and Trip Name
Row(
children: [
Expanded(
child: Text('${plan.tripTitle}',
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripTitle}',
style: TextStyle(
fontSize: 12,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
],
),
],
),
SizedBox(height: 2),
// Type and Created On
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [
Expanded(
child: Text('${plan.tripType}',
style: TextStyle(
fontSize: 10,
color: Colors.black87,
fontFamily: "Inter",
)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(' ${plan.tripType}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
),
Expanded(
child:
Text('${_formatDate(plan.createdOn)}',
style: TextStyle(
fontSize: 10,
color: Colors.black87,
fontFamily: "Inter",
)),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text('${_formatDate(plan.createdOn)}',
style: TextStyle(
fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
),
],
),
SizedBox(height: 3),
// Name
Row(
children: [
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
plan.userName.isNotEmpty
? '${plan.userName}'
: '${plan.travellerName}',
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
),
],
),
Spacer(),
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
plan.employeeCode ?? 'No Data',
style: TextStyle(
fontSize: 9,
fontFamily: "Inter",
color: Colors.black87),
),
],
),
],
),
// Actions
// Actions
],
),

View File

@ -4,6 +4,8 @@ import 'package:go_router/go_router.dart';
import 'package:shared_preferences/shared_preferences.dart'; // don't forget
import '../services/apiService.dart';
enum TabSelection { allTrips, myTrips, myApprovals }
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
final bool isDesktop;
final String? logoUrl;
@ -30,6 +32,8 @@ class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
class _CustomAppBarState extends State<CustomAppBar> {
final ApiService apiService = ApiService();
TabSelection selectedTab = TabSelection.allTrips;
String? token;
Map<String, dynamic>? userData;
Map<String, dynamic>? fetchedUserData;
@ -68,6 +72,17 @@ class _CustomAppBarState extends State<CustomAppBar> {
});
}
String getTabLabel(TabSelection tab) {
switch (tab) {
case TabSelection.allTrips:
return "All Trips";
case TabSelection.myTrips:
return "My Trips";
case TabSelection.myApprovals:
return "My Approvals";
}
}
Future<String?> getToken() async {
final prefs = await SharedPreferences.getInstance();
return prefs.getString("auth_token");
@ -144,6 +159,10 @@ class _CustomAppBarState extends State<CustomAppBar> {
surfaceTintColor: Colors.white,
// elevation: 3,
automaticallyImplyLeading: !widget.isDesktop,
iconTheme: IconThemeData(
color: layoutColor, // 👈 Set your desired icon color here
),
titleSpacing: 0,
title: !widget.isDesktop
@ -186,183 +205,221 @@ class _CustomAppBarState extends State<CustomAppBar> {
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 Trips",
// 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",
// ),
// )),
// ),
// ],
// ),
// ),
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",
),
)),
),
buildNavItem("All Trips", _myTravelRequestColor,
() => context.go('/listAllPlan'),
isSelected: selectedTab == "All Trips"),
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")
buildNavItem("My Trips", _myTravelRequestColor,
() => context.go('/listTravelAgentPlan'),
isSelected: selectedTab == "My Trips"),
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",
),
)),
),
buildNavItem("My Trips", _myTravelRequestColor,
() => context.go('/listPlan'),
isSelected: selectedTab == "My Trips"),
],
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",
),
)),
),
buildNavItem("My Approvals", _myApprovalsColor, () {
if (userData?["role"] == "Travel Agent") {
isSelected:
selectedTab == "My Approvals";
context.go('/listTravelAgentPlan');
} else {
isSelected:
selectedTab == "My Approvals";
context.go('/ApprovalList');
}
}),
],
),
),
Spacer(),
],
),
@ -499,7 +556,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
preferredSize: Size.fromHeight(1),
child: Container(
height: 1,
color: Colors.grey.shade200, // Set the color of the bottom border
// color: Colors.grey.shade200, // Set the color of the bottom border
color: layoutColor, // Set the color of the bottom border
),
),
);
@ -554,3 +612,35 @@ PopupMenuItem<String> buildMenuItem(Map<String, dynamic> item) {
),
);
}
Widget buildNavItem(String label, Color color, VoidCallback onTap,
{bool isSelected = false}) {
return MouseRegion(
cursor: SystemMouseCursors.click,
child: InkWell(
onTap: onTap,
child: Container(
padding: EdgeInsets.only(bottom: 2),
decoration: isSelected
? BoxDecoration(
border: Border(
bottom: BorderSide(
color: color, // underline color
width: 2, // underline thickness
),
),
)
: null, // no underline when not selected
child: Text(
label,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: color,
fontFamily: "Inter",
),
),
),
),
);
}

View File

@ -175,13 +175,13 @@ class _CustomDrawerState extends State<CustomDrawer> {
_buildDrawerItem(context, Icons.request_page_outlined,
'All Trips', '/listAllPlan'),
if (userDetails["role"] != "Travel Agent")
if (userDetails["role"] == "Travel Agent")
_buildDrawerItem(context, Icons.request_page_outlined,
'My Approvals1', '/listTravelAgentPlan'),
'My Approvals', '/listTravelAgentPlan'),
if (userDetails["role"] != "Travel Agent")
_buildDrawerItem(context, Icons.request_page_outlined,
'My Trip Request', '/listPlan'),
_buildDrawerItem(context, Icons.request_page_outlined, 'My Trips',
'/listPlan'),
if (userDetails["role"] != "Travel Agent")
_buildDrawerItem(context, Icons.assessment_outlined,

View File

@ -66,28 +66,41 @@ class PaginationControls extends StatelessWidget {
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,
),
),
),
SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Row(
children: List.generate(
totalPages,
(index) {
// Only show 2 pages: currentPage and currentPage+1
if (index == currentPage || index == currentPage + 1) {
return 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,
),
),
),
);
} else {
return SizedBox.shrink(); // Don't show other pages
}
},
),
),
),

View File

@ -28,14 +28,16 @@ class PlanPopupMenu extends StatelessWidget {
icon: Icon(
Icons.more_vert,
color: Color(0xFF475569),
size: 20,
size: 15,
),
itemBuilder: (context) => [
CustomPopupMenuEntry(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
padding: EdgeInsets.symmetric(horizontal: 2, vertical: 4),
// padding: EdgeInsets.symmetric(horizontal: 8, vertical: 8),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
IconButton(
icon: Icon(Icons.remove_red_eye, size: 18),

View File

@ -565,6 +565,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.1"
super_tooltip:
dependency: "direct main"
description:
name: super_tooltip
sha256: "55c0764554c961846d489503b76a1fc33ec2120bd7407266b77a34abbf3ed471"
url: "https://pub.dev"
source: hosted
version: "2.0.9"
term_glyph:
dependency: transitive
description:

View File

@ -47,6 +47,7 @@ dependencies:
image_picker: ^1.1.2
web: ^1.1.0
universal_html: ^2.2.4
super_tooltip: ^2.0.9
dev_dependencies:
@ -75,6 +76,7 @@ flutter:
- assets/images/login/travelSpend_Logo.png
- assets/images/login/TravelSpendsLogo1.png
- assets/images/login/VectorG.png
- assets/images/login/microsoft.png
- assets/images/IconsImg/delete.png
- assets/images/IconsImg/edit.png
- assets/images/IconsImg/planPdf_icon.png