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

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

View File

@ -1,7 +1,190 @@
import 'package:flutter/material.dart'; 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 /// Show confirm dialog for approval
Future<bool?> showApproveDialog(BuildContext context, Color layoutColor) { Future<bool?> showApproveDialog1(BuildContext context, Color layoutColor) {
return showDialog<bool>( return showDialog<bool>(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
@ -47,7 +230,7 @@ Future<bool?> showApproveDialog(BuildContext context, Color layoutColor) {
} }
/// Show confirm dialog for rejection with remarks input /// Show confirm dialog for rejection with remarks input
Future<String?> showRejectDialog( Future<String?> showRejectDialog1(
BuildContext context, Color layoutColor) async { BuildContext context, Color layoutColor) async {
String remarks = ""; String remarks = "";
@ -75,10 +258,9 @@ Future<String?> showRejectDialog(
decoration: const InputDecoration( decoration: const InputDecoration(
hintText: "Remarks...", hintText: "Remarks...",
hintStyle: TextStyle( hintStyle: TextStyle(
fontSize: 12, // 👈 Set your desired font size here fontSize: 10, // 👈 Set your desired font size here
color: Colors.grey, color: Colors.grey,
fontFamily: fontFamily: "Inter", // optional if you want consistent font
"Archivo", // optional if you want consistent font
), ),
border: OutlineInputBorder( border: OutlineInputBorder(
borderSide: BorderSide(color: Colors.blueGrey, width: 0.5), borderSide: BorderSide(color: Colors.blueGrey, width: 0.5),

View File

@ -342,7 +342,7 @@ class _ApprovalListState extends State<ApprovalList> {
String _formatDate(String rawDate) { String _formatDate(String rawDate) {
try { try {
final dateTime = DateTime.parse(rawDate); 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) { } catch (e) {
return rawDate; // fallback if parsing fails return rawDate; // fallback if parsing fails
} }
@ -362,7 +362,7 @@ class _ApprovalListState extends State<ApprovalList> {
// color: Color(0xFFF7F7FB), // color: Color(0xFFF7F7FB),
) )
: null, : null,
color: Colors.white, color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
// color: Color(0xFFF7F7FB), // color: Color(0xFFF7F7FB),
// color: Colors.amber, // color: Colors.amber,
@ -371,7 +371,7 @@ class _ApprovalListState extends State<ApprovalList> {
padding: const EdgeInsets.all(1.0), padding: const EdgeInsets.all(1.0),
child: Container( child: Container(
// padding: const EdgeInsets.all(10.0), // padding: const EdgeInsets.all(10.0),
color: Colors.white, color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
@ -383,10 +383,10 @@ class _ApprovalListState extends State<ApprovalList> {
children: [ children: [
Row( Row(
children: [ children: [
const Text('My Approvals', Text('My Approvals',
style: TextStyle( style: TextStyle(
fontFamily: "Inter", fontFamily: "Inter",
fontSize: 16, fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
)), )),
], ],
@ -447,7 +447,7 @@ class _ApprovalListState extends State<ApprovalList> {
children: [ children: [
Container( Container(
width: MediaQuery.of(context).size.width * 0.8, width: MediaQuery.of(context).size.width * 0.8,
height: 40, height: 35,
child: TextField( child: TextField(
controller: searchController, controller: searchController,
onChanged: filterPlans, onChanged: filterPlans,
@ -554,15 +554,15 @@ class _ApprovalListState extends State<ApprovalList> {
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.w600))), fontWeight: FontWeight.w600))),
DataColumn( DataColumn(
label: Text('Employee Code', label: Text('Trip Name',
style: TextStyle( style: TextStyle(
// color: Color(0xFF9E9DBD),
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.w600))), fontWeight: FontWeight.w600))),
DataColumn( DataColumn(
label: Text('Trip Name', label: Text('Employee Code',
style: TextStyle( style: TextStyle(
// color: Color(0xFF9E9DBD),
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
fontWeight: FontWeight.w600))), fontWeight: FontWeight.w600))),
@ -605,6 +605,14 @@ class _ApprovalListState extends State<ApprovalList> {
fontSize: 13, fontSize: 13,
fontFamily: "Archivo", fontFamily: "Archivo",
))), ))),
DataCell(Text(plan.tripTitle,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
DataCell(Text(plan.employeeCode ?? "no data", DataCell(Text(plan.employeeCode ?? "no data",
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
@ -623,13 +631,7 @@ class _ApprovalListState extends State<ApprovalList> {
fontSize: 13, fontSize: 13,
fontFamily: "Inter", fontFamily: "Inter",
))), ))),
DataCell(Text(plan.tripTitle,
style: TextStyle(
fontSize: 13,
fontFamily: "Inter",
),
softWrap: true,
overflow: TextOverflow.ellipsis)),
DataCell(Text( DataCell(Text(
// plan.createdOn, // plan.createdOn,
@ -684,17 +686,17 @@ class _ApprovalListState extends State<ApprovalList> {
MainAxisAlignment.center, MainAxisAlignment.center,
children: [ children: [
IconButton( IconButton(
icon: Icon(Icons.remove_red_eye, icon: Icon(Icons.remove_red_eye,
color: Color(0xFF475569), color: Color(0xFF475569),
size: 18), size: 18),
onPressed: () { onPressed: () {
Navigator.pop( Navigator.pop(
context); // Close popup manually context); // Close popup manually
ApiService.viewPlan( viewPlanforApprover(
context, plan.planId, plan.planId,
isViewMode: true); isViewMode: true,
}, isApprover: true);
), }),
IconButton( IconButton(
icon: Image.asset( icon: Image.asset(
'assets/images/IconsImg/edit.png', 'assets/images/IconsImg/edit.png',
@ -702,9 +704,10 @@ class _ApprovalListState extends State<ApprovalList> {
height: 15), height: 15),
onPressed: () { onPressed: () {
Navigator.pop(context); Navigator.pop(context);
ApiService.viewPlan( ApiService.viewPlanForApprover(
context, plan.planId, context, plan.planId,
isViewMode: false); isViewMode: false,
isApprover: true);
}, },
), ),
IconButton( IconButton(
@ -825,76 +828,173 @@ class _ApprovalListState extends State<ApprovalList> {
style: TextStyle( style: TextStyle(
color: getStatusTextColor( color: getStatusTextColor(
plan.statusValue), plan.statusValue),
fontSize: 12, fontSize: 10,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
), ),
PlanPopupMenu( PopupMenuButton<int>(
plan: plan, color: Colors.white,
deletePlan: deletePlan, padding: EdgeInsets.zero,
apiService: apiService, 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 SizedBox(height: 2),
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 // Trip Id and Trip Name
Row( Row(
children: [ children: [
Expanded( Column(
child: Text('${plan.tripTitle}', crossAxisAlignment:
style: TextStyle( CrossAxisAlignment.start,
fontSize: 13, children: [
fontFamily: "Inter", Text(' ${plan.tripTitle}',
fontWeight: FontWeight.bold)), style: TextStyle(
fontSize: 12,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
],
), ),
], ],
), ),
SizedBox(height: 2), SizedBox(height: 2),
// Type and Created On // Type and Created On
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Column(
child: Text('${plan.tripType}', crossAxisAlignment:
style: TextStyle( CrossAxisAlignment.start,
fontSize: 10, children: [
color: Colors.black87, Text(' ${plan.tripType}',
fontFamily: "Inter", style: TextStyle(
)), fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
), ),
Expanded( Column(
child: crossAxisAlignment:
Text('${_formatDate(plan.createdOn)}', CrossAxisAlignment.start,
style: TextStyle( children: [
fontSize: 10, Text('${_formatDate(plan.createdOn)}',
color: Colors.black87, style: TextStyle(
fontFamily: "Inter", 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 // Actions
], ],
), ),
@ -914,13 +1014,7 @@ class _ApprovalListState extends State<ApprovalList> {
scrollDirection: Axis.vertical, scrollDirection: Axis.vertical,
child: table, // <-- your existing table child: table, // <-- your existing table
) )
: SingleChildScrollView( : buildMobileCardView(paginatedPlans),
scrollDirection: Axis.horizontal,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: table,
),
),
), ),
PaginationControls( PaginationControls(
currentPage: currentPage, 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), const SizedBox(height: 20),
if (!_isForgotPassword && !_showOtpResetFields) if (!_isForgotPassword && !_showOtpResetFields)
Container( Row(
width: 45, // Adjust size mainAxisAlignment: MainAxisAlignment.center,
height: 45, children: [
decoration: BoxDecoration( Image.asset(
// Background color 'assets/images/login/microsoft.png',
shape: BoxShape.rectangle, width: 30, // Optional: control size
borderRadius: BorderRadius.all(Radius.circular(15)), height: 30,
border: Border.all( fit: BoxFit.contain,
color: Color(0xFF9E9DBD), width: 1), // Grey outline ),
), 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: Center(
child: Image.asset( child: Image.asset(
'assets/images/login/VectorG.png', 'assets/images/login/VectorG.png',
width: 20, // Optional: control size width: 20, // Optional: control size
height: 10, height: 20,
fit: BoxFit.contain, fit: BoxFit.contain,
)), )),
),
],
), ),
], ],
), ),

View File

@ -14,12 +14,14 @@ class UserSelectionDialog extends StatefulWidget {
final String title; final String title;
final Color layoutColorForUser; final Color layoutColorForUser;
final void Function(String, String, bool) onSubmit; final void Function(String, String, bool) onSubmit;
final void Function() onClose;
UserSelectionDialog({ UserSelectionDialog({
Key? key, Key? key,
required this.title, required this.title,
required this.layoutColorForUser, required this.layoutColorForUser,
required this.onSubmit, required this.onSubmit,
required this.onClose,
}) : super(key: key); }) : super(key: key);
@override @override
@ -427,7 +429,10 @@ class _UserSelectionDialogState extends State<UserSelectionDialog> {
), ),
padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12), padding: EdgeInsets.symmetric(horizontal: 20, vertical: 12),
), ),
onPressed: () => Navigator.pop(context), onPressed: () {
widget.onClose();
Navigator.pop(context);
},
child: Text( child: Text(
"Cancel", "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) { String _formatDate(String rawDate) {
try { try {
final dateTime = DateTime.parse(rawDate); 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) { } catch (e) {
return rawDate; // fallback if parsing fails return rawDate; // fallback if parsing fails
} }
@ -338,7 +338,7 @@ class _ListPlansState extends State<ListPlans> {
// color: Color(0xFFF7F7FB), // color: Color(0xFFF7F7FB),
) )
: null, : null,
color: Colors.white, color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
// color: Color(0xFFF7F7FB), // color: Color(0xFFF7F7FB),
// color: Colors.amber, // color: Colors.amber,
@ -347,7 +347,7 @@ class _ListPlansState extends State<ListPlans> {
padding: const EdgeInsets.all(1.0), padding: const EdgeInsets.all(1.0),
child: Container( child: Container(
// padding: const EdgeInsets.all(10.0), // padding: const EdgeInsets.all(10.0),
color: Colors.white, color: isDesktop ? Colors.white : Color(0xFFFCFCFC),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
@ -360,10 +360,10 @@ class _ListPlansState extends State<ListPlans> {
children: [ children: [
Row( Row(
children: [ children: [
const Text('My Trip Request', Text('My Trips',
style: TextStyle( style: TextStyle(
fontFamily: "Inter", fontFamily: "Inter",
fontSize: 16, fontSize: isDesktop ? 16 : 14,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Color(0xFF212121))), color: Color(0xFF212121))),
], ],
@ -440,8 +440,9 @@ class _ListPlansState extends State<ListPlans> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
side: BorderSide(color: Color(0xFF114D8B), width: 2), side: BorderSide(color: Color(0xFF114D8B), width: 2),
), ),
padding: padding: isDesktop
EdgeInsets.symmetric(horizontal: 20, vertical: 12), ? EdgeInsets.symmetric(horizontal: 20, vertical: 12)
: EdgeInsets.symmetric(horizontal: 15, vertical: 10),
), ),
onPressed: () { onPressed: () {
if (TripPlanAction == "Plan Creation Not Allowed") { if (TripPlanAction == "Plan Creation Not Allowed") {
@ -479,7 +480,7 @@ class _ListPlansState extends State<ListPlans> {
children: [ children: [
Text( Text(
"Add New Trip", "Add New Trip",
style: TextStyle(fontSize: 13), style: TextStyle(fontSize: isDesktop ? 13 : 11),
), ),
SizedBox(width: 8), // spacing between icon and text SizedBox(width: 8), // spacing between icon and text
Icon( Icon(
@ -498,7 +499,7 @@ class _ListPlansState extends State<ListPlans> {
children: [ children: [
Container( Container(
width: MediaQuery.of(context).size.width * 0.85, width: MediaQuery.of(context).size.width * 0.85,
height: 40, height: 35,
child: TextField( child: TextField(
controller: searchController, controller: searchController,
onChanged: filterPlans, onChanged: filterPlans,
@ -896,7 +897,7 @@ class _ListPlansState extends State<ListPlans> {
style: TextStyle( style: TextStyle(
color: getStatusTextColor( color: getStatusTextColor(
plan.statusValue), plan.statusValue),
fontSize: 12, fontSize: 10,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@ -908,64 +909,92 @@ class _ListPlansState extends State<ListPlans> {
), ),
], ],
), ),
SizedBox(height: 8),
// Name SizedBox(height: 2),
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 // Trip Id and Trip Name
Row( Row(
children: [ children: [
Expanded( Column(
child: Text('${plan.tripTitle}', crossAxisAlignment:
style: TextStyle( CrossAxisAlignment.start,
fontSize: 13, children: [
fontFamily: "Inter", Text(' ${plan.tripTitle}',
fontWeight: FontWeight.bold)), style: TextStyle(
fontSize: 12,
fontFamily: "Inter",
fontWeight: FontWeight.bold)),
],
), ),
], ],
), ),
SizedBox(height: 2), SizedBox(height: 2),
// Type and Created On // Type and Created On
Row( Row(
mainAxisSize: MainAxisSize.min, mainAxisAlignment:
MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Column(
child: Text('${plan.tripType}', crossAxisAlignment:
style: TextStyle( CrossAxisAlignment.start,
fontSize: 10, children: [
color: Colors.black87, Text(' ${plan.tripType}',
fontFamily: "Inter", style: TextStyle(
)), fontSize: 9,
color: Colors.black87,
fontFamily: "Inter",
)),
],
), ),
Expanded( Column(
child: crossAxisAlignment:
Text('${_formatDate(plan.createdOn)}', CrossAxisAlignment.start,
style: TextStyle( children: [
fontSize: 10, Text('${_formatDate(plan.createdOn)}',
color: Colors.black87, style: TextStyle(
fontFamily: "Inter", 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 // 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 'package:shared_preferences/shared_preferences.dart'; // don't forget
import '../services/apiService.dart'; import '../services/apiService.dart';
enum TabSelection { allTrips, myTrips, myApprovals }
class CustomAppBar extends StatefulWidget implements PreferredSizeWidget { class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
final bool isDesktop; final bool isDesktop;
final String? logoUrl; final String? logoUrl;
@ -30,6 +32,8 @@ class CustomAppBar extends StatefulWidget implements PreferredSizeWidget {
class _CustomAppBarState extends State<CustomAppBar> { class _CustomAppBarState extends State<CustomAppBar> {
final ApiService apiService = ApiService(); final ApiService apiService = ApiService();
TabSelection selectedTab = TabSelection.allTrips;
String? token; String? token;
Map<String, dynamic>? userData; Map<String, dynamic>? userData;
Map<String, dynamic>? fetchedUserData; 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 { Future<String?> getToken() async {
final prefs = await SharedPreferences.getInstance(); final prefs = await SharedPreferences.getInstance();
return prefs.getString("auth_token"); return prefs.getString("auth_token");
@ -144,6 +159,10 @@ class _CustomAppBarState extends State<CustomAppBar> {
surfaceTintColor: Colors.white, surfaceTintColor: Colors.white,
// elevation: 3, // elevation: 3,
automaticallyImplyLeading: !widget.isDesktop, automaticallyImplyLeading: !widget.isDesktop,
iconTheme: IconThemeData(
color: layoutColor, // 👈 Set your desired icon color here
),
titleSpacing: 0, titleSpacing: 0,
title: !widget.isDesktop title: !widget.isDesktop
@ -186,183 +205,221 @@ class _CustomAppBarState extends State<CustomAppBar> {
SizedBox( SizedBox(
width: MediaQuery.of(context).size.width * 0.2, 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( Container(
width: MediaQuery.of(context).size.width * 0.35, width: MediaQuery.of(context).size.width * 0.35,
// color: Colors.blueGrey,
child: Row( child: Row(
// crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
if (userData?["role"] == "Org Admin" || if (userData?["role"] == "Org Admin" ||
userData?["role"] == "Travel Admin") userData?["role"] == "Travel Admin")
MouseRegion( buildNavItem("All Trips", _myTravelRequestColor,
cursor: SystemMouseCursors.click, () => context.go('/listAllPlan'),
onEnter: (_) { isSelected: selectedTab == "All Trips"),
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), const SizedBox(width: 20),
if (userDetails["role"] == "Travel Agent") if (userDetails["role"] == "Travel Agent")
MouseRegion( buildNavItem("My Trips", _myTravelRequestColor,
cursor: SystemMouseCursors.click, () => context.go('/listTravelAgentPlan'),
onEnter: (_) { isSelected: selectedTab == "My Trips"),
setState(() { if (userDetails["role"] != "Travel Agent") ...[
// _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), const SizedBox(width: 20),
if (userDetails["role"] != "Travel Agent") buildNavItem("My Trips", _myTravelRequestColor,
MouseRegion( () => context.go('/listPlan'),
cursor: SystemMouseCursors.click, isSelected: selectedTab == "My Trips"),
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), const SizedBox(width: 20),
if (userData?["role"] != "Travel Agent") buildNavItem("My Approvals", _myApprovalsColor, () {
MouseRegion( if (userData?["role"] == "Travel Agent") {
cursor: SystemMouseCursors.click, isSelected:
onEnter: (_) { selectedTab == "My Approvals";
setState(() { context.go('/listTravelAgentPlan');
_myApprovalsColor = } else {
Color(0xFF114D8B); // Change color on hover isSelected:
}); selectedTab == "My Approvals";
}, context.go('/ApprovalList');
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(), Spacer(),
], ],
), ),
@ -499,7 +556,8 @@ class _CustomAppBarState extends State<CustomAppBar> {
preferredSize: Size.fromHeight(1), preferredSize: Size.fromHeight(1),
child: Container( child: Container(
height: 1, 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, _buildDrawerItem(context, Icons.request_page_outlined,
'All Trips', '/listAllPlan'), 'All Trips', '/listAllPlan'),
if (userDetails["role"] != "Travel Agent") if (userDetails["role"] == "Travel Agent")
_buildDrawerItem(context, Icons.request_page_outlined, _buildDrawerItem(context, Icons.request_page_outlined,
'My Approvals1', '/listTravelAgentPlan'), 'My Approvals', '/listTravelAgentPlan'),
if (userDetails["role"] != "Travel Agent") if (userDetails["role"] != "Travel Agent")
_buildDrawerItem(context, Icons.request_page_outlined, _buildDrawerItem(context, Icons.request_page_outlined, 'My Trips',
'My Trip Request', '/listPlan'), '/listPlan'),
if (userDetails["role"] != "Travel Agent") if (userDetails["role"] != "Travel Agent")
_buildDrawerItem(context, Icons.assessment_outlined, _buildDrawerItem(context, Icons.assessment_outlined,

View File

@ -66,28 +66,41 @@ class PaginationControls extends StatelessWidget {
onPressed: onPressed:
currentPage > 0 ? () => onPageChanged(currentPage - 1) : null, currentPage > 0 ? () => onPageChanged(currentPage - 1) : null,
), ),
Row( SingleChildScrollView(
children: List.generate( scrollDirection: Axis.horizontal,
totalPages, child: Row(
(index) => Padding( children: List.generate(
padding: const EdgeInsets.symmetric(horizontal: 4), totalPages,
child: ElevatedButton( (index) {
onPressed: () => onPageChanged(index), // Only show 2 pages: currentPage and currentPage+1
style: ElevatedButton.styleFrom( if (index == currentPage || index == currentPage + 1) {
backgroundColor: return Padding(
currentPage == index ? activeColor : Colors.grey[300]!, padding: const EdgeInsets.symmetric(horizontal: 4),
minimumSize: Size(30, 30), child: ElevatedButton(
padding: EdgeInsets.zero, onPressed: () => onPageChanged(index),
), style: ElevatedButton.styleFrom(
child: Text( backgroundColor: currentPage == index
'${index + 1}', ? activeColor
style: TextStyle( : Colors.grey[300]!,
fontSize: 12, minimumSize: Size(30, 30),
fontFamily: "Inter", padding: EdgeInsets.zero,
color: currentPage == index ? Colors.white : Colors.black, ),
), 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( icon: Icon(
Icons.more_vert, Icons.more_vert,
color: Color(0xFF475569), color: Color(0xFF475569),
size: 20, size: 15,
), ),
itemBuilder: (context) => [ itemBuilder: (context) => [
CustomPopupMenuEntry( CustomPopupMenuEntry(
child: Container( 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( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
IconButton( IconButton(
icon: Icon(Icons.remove_red_eye, size: 18), icon: Icon(Icons.remove_red_eye, size: 18),

View File

@ -565,6 +565,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.1" 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: term_glyph:
dependency: transitive dependency: transitive
description: description:

View File

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